Move Station Form to Composition API.
This commit is contained in:
parent
123d0f1f8b
commit
11adef3ba0
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<b-modal id="send_test_message" centered ref="modal" :title="langTitle">
|
||||
<b-modal id="send_test_message" centered ref="modal" :title="$gettext('Send Test Message')">
|
||||
<b-form @submit.prevent="doSendTest">
|
||||
<b-wrapped-form-group id="email_address" :field="v$.emailAddress" autofocus>
|
||||
<template #label>
|
||||
|
@ -18,55 +18,61 @@
|
|||
</b-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import useVuelidate from "@vuelidate/core";
|
||||
import {email, required} from '@vuelidate/validators';
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import {ref} from "vue";
|
||||
import {useNotify} from "~/vendor/bootstrapVue";
|
||||
import gettext from "~/vendor/gettext";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
|
||||
export default {
|
||||
name: 'AdminSettingsTestMessageModal',
|
||||
components: {BWrappedFormGroup},
|
||||
setup() {
|
||||
return {v$: useVuelidate()}
|
||||
},
|
||||
props: {
|
||||
testMessageUrl: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
emailAddress: null
|
||||
};
|
||||
},
|
||||
validations: {
|
||||
emailAddress: {required, email}
|
||||
},
|
||||
computed: {
|
||||
langTitle() {
|
||||
return this.$gettext('Send Test Message');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.emailAddress = null;
|
||||
this.v$.$reset();
|
||||
this.$refs.modal.hide();
|
||||
},
|
||||
async doSendTest() {
|
||||
this.v$.$touch();
|
||||
if (this.v$.$errors.length > 0) {
|
||||
return;
|
||||
}
|
||||
const props = defineProps({
|
||||
testMessageUrl: String
|
||||
});
|
||||
|
||||
this.$wrapWithLoading(
|
||||
this.axios.post(this.testMessageUrl, {
|
||||
'email': this.emailAddress
|
||||
})
|
||||
).then(() => {
|
||||
this.$notifySuccess(this.$gettext('Test message sent.'));
|
||||
}).finally(() => {
|
||||
this.close();
|
||||
});
|
||||
}
|
||||
}
|
||||
const blankForm = {
|
||||
emailAddress: null
|
||||
};
|
||||
|
||||
const form = ref({...blankForm});
|
||||
|
||||
const validations = {
|
||||
emailAddress: {required, email}
|
||||
};
|
||||
|
||||
const v$ = useVuelidate(validations, form);
|
||||
|
||||
const resetForm = () => {
|
||||
form.value = {...blankForm};
|
||||
};
|
||||
|
||||
const modal = ref(); // BModal
|
||||
|
||||
const close = () => {
|
||||
v$.value.reset();
|
||||
modal.value.hide();
|
||||
}
|
||||
|
||||
const {wrapWithLoading, notifySuccess} = useNotify();
|
||||
const {axios} = useAxios();
|
||||
const {$gettext} = gettext;
|
||||
|
||||
const doSendTest = () => {
|
||||
v$.value.$touch();
|
||||
|
||||
if (v$.value.$errors.length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
wrapWithLoading(
|
||||
axios.post(props.testMessageUrl, {
|
||||
'email': form.value.emailAddress
|
||||
})
|
||||
).then(() => {
|
||||
notifySuccess($gettext('Test message sent.'));
|
||||
}).finally(() => {
|
||||
close();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -1,95 +1,102 @@
|
|||
<template>
|
||||
<modal-form ref="modal" :loading="loading" :title="langTitle" :error="error" :disable-save-button="v$.form.$invalid"
|
||||
<modal-form ref="modal" :loading="loading" :title="$gettext('Clone Station')" :error="error"
|
||||
:disable-save-button="v$.$invalid"
|
||||
@submit="doSubmit" @hidden="clearContents">
|
||||
|
||||
<admin-stations-clone-modal-form :form="v$.form"></admin-stations-clone-modal-form>
|
||||
<admin-stations-clone-modal-form :form="v$"></admin-stations-clone-modal-form>
|
||||
|
||||
</modal-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import useVuelidate from "@vuelidate/core";
|
||||
import {required} from '@vuelidate/validators';
|
||||
import ModalForm from "~/components/Common/ModalForm";
|
||||
import AdminStationsCloneModalForm from "~/components/Admin/Stations/CloneModalForm";
|
||||
import {ref} from "vue";
|
||||
import gettext from "~/vendor/gettext";
|
||||
import {useNotify} from "~/vendor/bootstrapVue";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
|
||||
export default {
|
||||
name: 'AdminStationsCloneModal',
|
||||
components: {AdminStationsCloneModalForm, ModalForm},
|
||||
setup() {
|
||||
return {v$: useVuelidate()}
|
||||
},
|
||||
emits: ['relist'],
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
cloneUrl: null,
|
||||
error: null,
|
||||
form: {},
|
||||
}
|
||||
},
|
||||
validations() {
|
||||
return {
|
||||
form: {
|
||||
name: {required},
|
||||
description: {},
|
||||
clone: {}
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
langTitle() {
|
||||
return this.$gettext('Clone Station');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
resetForm() {
|
||||
this.form = {
|
||||
name: '',
|
||||
description: '',
|
||||
clone: [],
|
||||
};
|
||||
},
|
||||
create(stationName, cloneUrl) {
|
||||
this.resetForm();
|
||||
const emit = defineEmits(['relist']);
|
||||
|
||||
const newStationName = this.$gettext('%{station} - Copy');
|
||||
this.form.name = this.$gettextInterpolate(newStationName, {station: stationName});
|
||||
const loading = ref(true);
|
||||
const cloneUrl = ref(null);
|
||||
const error = ref(null);
|
||||
|
||||
this.loading = false;
|
||||
this.error = null;
|
||||
this.cloneUrl = cloneUrl;
|
||||
const blankForm = {
|
||||
name: '',
|
||||
description: '',
|
||||
clone: [],
|
||||
};
|
||||
|
||||
this.$refs.modal.show();
|
||||
},
|
||||
clearContents() {
|
||||
this.resetForm();
|
||||
this.cloneUrl = null;
|
||||
},
|
||||
close() {
|
||||
this.$refs.modal.hide();
|
||||
},
|
||||
doSubmit() {
|
||||
this.v$.$touch();
|
||||
if (this.v$.$errors.length > 0) {
|
||||
return;
|
||||
}
|
||||
const form = ref({...blankForm});
|
||||
|
||||
this.error = null;
|
||||
this.$wrapWithLoading(
|
||||
this.axios({
|
||||
method: 'POST',
|
||||
url: this.cloneUrl,
|
||||
data: this.form
|
||||
})
|
||||
).then(() => {
|
||||
this.$notifySuccess();
|
||||
this.$emit('relist');
|
||||
this.close();
|
||||
}).catch((error) => {
|
||||
this.error = error.response.data.message;
|
||||
});
|
||||
},
|
||||
const validations = {
|
||||
name: {required},
|
||||
description: {},
|
||||
clone: {}
|
||||
};
|
||||
|
||||
const v$ = useVuelidate(validations, form);
|
||||
|
||||
const resetForm = () => {
|
||||
form.value = {...blankForm};
|
||||
};
|
||||
|
||||
const modal = ref(); // BVModal
|
||||
const {$gettext} = gettext;
|
||||
|
||||
const create = (stationName, stationCloneUrl) => {
|
||||
resetForm();
|
||||
|
||||
form.value.name = $gettext(
|
||||
'%{station} - Copy',
|
||||
{station: stationName}
|
||||
);
|
||||
loading.value = false;
|
||||
error.value = null;
|
||||
cloneUrl.value = stationCloneUrl;
|
||||
|
||||
modal.value.show();
|
||||
};
|
||||
|
||||
const clearContents = () => {
|
||||
resetForm();
|
||||
cloneUrl.value = null;
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
modal.value.hide();
|
||||
};
|
||||
|
||||
const {wrapWithLoading, notifySuccess} = useNotify();
|
||||
const {axios} = useAxios();
|
||||
|
||||
const doSubmit = () => {
|
||||
v$.value.$touch();
|
||||
if (v$.value.$errors.length > 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
error.value = null;
|
||||
|
||||
wrapWithLoading(
|
||||
axios({
|
||||
method: 'POST',
|
||||
url: cloneUrl.value,
|
||||
data: form.value
|
||||
})
|
||||
).then(() => {
|
||||
notifySuccess();
|
||||
emit('relist');
|
||||
close();
|
||||
}).catch((error) => {
|
||||
error.value = error.response.data.message;
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
create
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -29,56 +29,55 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import {computed} from "vue";
|
||||
import gettext from "~/vendor/gettext";
|
||||
|
||||
export default {
|
||||
name: 'AdminStationsCloneModalForm',
|
||||
components: {BWrappedFormGroup},
|
||||
props: {
|
||||
form: Object
|
||||
},
|
||||
computed: {
|
||||
cloneOptions() {
|
||||
return [
|
||||
{
|
||||
text: this.$gettext('Share Media Storage Location'),
|
||||
value: 'media_storage'
|
||||
},
|
||||
{
|
||||
text: this.$gettext('Share Recordings Storage Location'),
|
||||
value: 'recordings_storage'
|
||||
},
|
||||
{
|
||||
text: this.$gettext('Share Podcasts Storage Location'),
|
||||
value: 'podcasts_storage'
|
||||
},
|
||||
{
|
||||
text: this.$gettext('Playlists'),
|
||||
value: 'playlists',
|
||||
},
|
||||
{
|
||||
text: this.$gettext('Mount Points'),
|
||||
value: 'mounts'
|
||||
},
|
||||
{
|
||||
text: this.$gettext('Remote Relays'),
|
||||
value: 'remotes'
|
||||
},
|
||||
{
|
||||
text: this.$gettext('Streamers/DJs'),
|
||||
value: 'streamers'
|
||||
},
|
||||
{
|
||||
text: this.$gettext('User Permissions'),
|
||||
value: 'permissions'
|
||||
},
|
||||
{
|
||||
text: this.$gettext('Web Hooks'),
|
||||
value: 'webhooks'
|
||||
}
|
||||
];
|
||||
const props = defineProps({
|
||||
form: Object
|
||||
});
|
||||
|
||||
const {$gettext} = gettext;
|
||||
|
||||
const cloneOptions = computed(() => {
|
||||
return [
|
||||
{
|
||||
text: $gettext('Share Media Storage Location'),
|
||||
value: 'media_storage'
|
||||
},
|
||||
{
|
||||
text: $gettext('Share Recordings Storage Location'),
|
||||
value: 'recordings_storage'
|
||||
},
|
||||
{
|
||||
text: $gettext('Share Podcasts Storage Location'),
|
||||
value: 'podcasts_storage'
|
||||
},
|
||||
{
|
||||
text: $gettext('Playlists'),
|
||||
value: 'playlists',
|
||||
},
|
||||
{
|
||||
text: $gettext('Mount Points'),
|
||||
value: 'mounts'
|
||||
},
|
||||
{
|
||||
text: $gettext('Remote Relays'),
|
||||
value: 'remotes'
|
||||
},
|
||||
{
|
||||
text: $gettext('Streamers/DJs'),
|
||||
value: 'streamers'
|
||||
},
|
||||
{
|
||||
text: $gettext('User Permissions'),
|
||||
value: 'permissions'
|
||||
},
|
||||
{
|
||||
text: $gettext('Web Hooks'),
|
||||
value: 'webhooks'
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -20,70 +20,86 @@
|
|||
</b-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ModalForm from "~/components/Common/ModalForm";
|
||||
<script setup>
|
||||
import AdminStationsForm, {StationFormProps} from "~/components/Admin/Stations/StationForm";
|
||||
import InvisibleSubmitButton from "~/components/Common/InvisibleSubmitButton";
|
||||
import {computed, ref} from "vue";
|
||||
import gettext from "~/vendor/gettext";
|
||||
|
||||
const props = defineProps({
|
||||
...StationFormProps.props,
|
||||
createUrl: String
|
||||
});
|
||||
|
||||
const emit = defineEmits(['relist']);
|
||||
|
||||
const editUrl = ref(null);
|
||||
const loading = ref(true);
|
||||
const disableSaveButton = ref(true);
|
||||
|
||||
const isEditMode = computed(() => {
|
||||
return editUrl.value !== null;
|
||||
});
|
||||
|
||||
const {$gettext} = gettext;
|
||||
|
||||
const langTitle = computed(() => {
|
||||
return isEditMode.value
|
||||
? $gettext('Edit Station')
|
||||
: $gettext('Add Station');
|
||||
});
|
||||
|
||||
const modal = ref(); // BVModal
|
||||
|
||||
const onValidUpdate = (newValue) => {
|
||||
disableSaveButton.value = !newValue;
|
||||
};
|
||||
|
||||
const onLoadingUpdate = (newValue) => {
|
||||
loading.value = newValue;
|
||||
};
|
||||
|
||||
const create = () => {
|
||||
editUrl.value = null;
|
||||
modal.value.show();
|
||||
};
|
||||
|
||||
const edit = (recordUrl) => {
|
||||
editUrl.value = recordUrl;
|
||||
modal.value.show();
|
||||
};
|
||||
|
||||
const form = ref(); // Template Ref
|
||||
|
||||
const resetForm = () => {
|
||||
form.value.reset();
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
modal.value.hide();
|
||||
};
|
||||
|
||||
const onSubmit = () => {
|
||||
emit('relist');
|
||||
close();
|
||||
};
|
||||
|
||||
const doSubmit = () => {
|
||||
form.value.submit();
|
||||
};
|
||||
|
||||
const clearContents = () => {
|
||||
editUrl.value = null;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
create,
|
||||
edit
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'AdminStationsEditModal',
|
||||
inheritAttrs: false,
|
||||
components: {InvisibleSubmitButton, AdminStationsForm, ModalForm},
|
||||
emits: ['relist'],
|
||||
props: {
|
||||
createUrl: String
|
||||
},
|
||||
mixins: [
|
||||
StationFormProps
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
editUrl: null,
|
||||
loading: true,
|
||||
disableSaveButton: true,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
langTitle() {
|
||||
return this.isEditMode
|
||||
? this.$gettext('Edit Station')
|
||||
: this.$gettext('Add Station');
|
||||
},
|
||||
isEditMode() {
|
||||
return this.editUrl !== null;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onValidUpdate(newValue) {
|
||||
this.disableSaveButton = !newValue;
|
||||
},
|
||||
onLoadingUpdate(newValue) {
|
||||
this.loading = newValue;
|
||||
},
|
||||
create() {
|
||||
this.editUrl = null;
|
||||
this.$refs.modal.show();
|
||||
},
|
||||
edit(recordUrl) {
|
||||
this.editUrl = recordUrl;
|
||||
this.$refs.modal.show();
|
||||
},
|
||||
resetForm() {
|
||||
this.$refs.form.reset();
|
||||
},
|
||||
onSubmit() {
|
||||
this.$emit('relist');
|
||||
this.close();
|
||||
},
|
||||
doSubmit() {
|
||||
this.$refs.form.submit();
|
||||
},
|
||||
close() {
|
||||
this.$refs.modal.hide();
|
||||
},
|
||||
clearContents() {
|
||||
this.editUrl = null;
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -66,66 +66,62 @@
|
|||
</b-form-group>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import objectToFormOptions from "~/functions/objectToFormOptions";
|
||||
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
|
||||
import BFormFieldset from "~/components/Form/BFormFieldset";
|
||||
import {onMounted, reactive, ref} from "vue";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
|
||||
export default {
|
||||
name: 'AdminStationsAdminForm',
|
||||
components: {BWrappedFormCheckbox, BWrappedFormGroup, BFormFieldset},
|
||||
props: {
|
||||
form: Object,
|
||||
isEditMode: Boolean,
|
||||
storageLocationApiUrl: String,
|
||||
showAdvanced: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
const props = defineProps({
|
||||
form: Object,
|
||||
isEditMode: Boolean,
|
||||
storageLocationApiUrl: String,
|
||||
showAdvanced: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
storageLocationsLoading: true,
|
||||
storageLocationOptions: {
|
||||
media_storage_location: [],
|
||||
recordings_storage_location: [],
|
||||
podcasts_storage_location: []
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadLocations();
|
||||
},
|
||||
methods: {
|
||||
loadLocations() {
|
||||
this.axios.get(this.storageLocationApiUrl).then((resp) => {
|
||||
this.storageLocationOptions.media_storage_location = objectToFormOptions(
|
||||
this.filterLocations(resp.data.media_storage_location)
|
||||
);
|
||||
this.storageLocationOptions.recordings_storage_location = objectToFormOptions(
|
||||
this.filterLocations(resp.data.recordings_storage_location)
|
||||
);
|
||||
this.storageLocationOptions.podcasts_storage_location = objectToFormOptions(
|
||||
this.filterLocations(resp.data.podcasts_storage_location)
|
||||
);
|
||||
}).finally(() => {
|
||||
this.storageLocationsLoading = false;
|
||||
});
|
||||
},
|
||||
filterLocations(group) {
|
||||
if (!this.isEditMode) {
|
||||
return group;
|
||||
}
|
||||
});
|
||||
|
||||
let newGroup = {};
|
||||
for (const oldKey in group) {
|
||||
if (oldKey !== "") {
|
||||
newGroup[oldKey] = group[oldKey];
|
||||
}
|
||||
}
|
||||
return newGroup;
|
||||
const storageLocationsLoading = ref(true);
|
||||
const storageLocationOptions = reactive({
|
||||
media_storage_location: [],
|
||||
recordings_storage_location: [],
|
||||
podcasts_storage_location: []
|
||||
});
|
||||
|
||||
const filterLocations = (group) => {
|
||||
if (!props.isEditMode) {
|
||||
return group;
|
||||
}
|
||||
|
||||
let newGroup = {};
|
||||
for (const oldKey in group) {
|
||||
if (oldKey !== "") {
|
||||
newGroup[oldKey] = group[oldKey];
|
||||
}
|
||||
}
|
||||
return newGroup;
|
||||
}
|
||||
|
||||
const {axios} = useAxios();
|
||||
|
||||
const loadLocations = () => {
|
||||
axios.get(props.storageLocationApiUrl).then((resp) => {
|
||||
storageLocationOptions.media_storage_location = objectToFormOptions(
|
||||
filterLocations(resp.data.media_storage_location)
|
||||
);
|
||||
storageLocationOptions.recordings_storage_location = objectToFormOptions(
|
||||
filterLocations(resp.data.recordings_storage_location)
|
||||
);
|
||||
storageLocationOptions.podcasts_storage_location = objectToFormOptions(
|
||||
filterLocations(resp.data.podcasts_storage_location)
|
||||
);
|
||||
}).finally(() => {
|
||||
storageLocationsLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(loadLocations);
|
||||
</script>
|
||||
|
|
|
@ -222,7 +222,7 @@
|
|||
</b-form-fieldset>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import BFormFieldset from "~/components/Form/BFormFieldset";
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import {
|
||||
|
@ -234,106 +234,111 @@ import {
|
|||
} from "~/components/Entity/RadioAdapters";
|
||||
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
|
||||
import BFormMarkup from "~/components/Form/BFormMarkup";
|
||||
import {computed} from "vue";
|
||||
import gettext from "~/vendor/gettext";
|
||||
|
||||
export default {
|
||||
name: 'AdminStationsBackendForm',
|
||||
components: {BFormMarkup, BWrappedFormCheckbox, BWrappedFormGroup, BFormFieldset},
|
||||
props: {
|
||||
form: Object,
|
||||
station: Object,
|
||||
isStereoToolInstalled: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showAdvanced: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
const props = defineProps({
|
||||
form: Object,
|
||||
station: Object,
|
||||
isStereoToolInstalled: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
computed: {
|
||||
backendTypeOptions() {
|
||||
return [
|
||||
{
|
||||
text: this.$gettext('Use Liquidsoap on this server.'),
|
||||
value: BACKEND_LIQUIDSOAP
|
||||
},
|
||||
{
|
||||
text: this.$gettext('Do not use an AutoDJ service.'),
|
||||
value: BACKEND_NONE
|
||||
}
|
||||
];
|
||||
},
|
||||
isBackendEnabled() {
|
||||
return this.form.backend_type.$model !== BACKEND_NONE;
|
||||
},
|
||||
isStereoToolEnabled() {
|
||||
return this.form.backend_config.audio_processing_method.$model === AUDIO_PROCESSING_STEREO_TOOL;
|
||||
},
|
||||
crossfadeOptions() {
|
||||
return [
|
||||
{
|
||||
text: this.$gettext('Smart Mode'),
|
||||
value: 'smart',
|
||||
},
|
||||
{
|
||||
text: this.$gettext('Normal Mode'),
|
||||
value: 'normal',
|
||||
},
|
||||
{
|
||||
text: this.$gettext('Disable Crossfading'),
|
||||
value: 'none',
|
||||
}
|
||||
];
|
||||
},
|
||||
audioProcessingOptions() {
|
||||
const audioProcessingOptions = [
|
||||
{
|
||||
text: this.$gettext('Liquidsoap'),
|
||||
value: AUDIO_PROCESSING_LIQUIDSOAP,
|
||||
},
|
||||
{
|
||||
text: this.$gettext('Disable Processing'),
|
||||
value: AUDIO_PROCESSING_NONE,
|
||||
}
|
||||
];
|
||||
showAdvanced: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
});
|
||||
|
||||
if (this.isStereoToolInstalled) {
|
||||
audioProcessingOptions.splice(1, 0,
|
||||
{
|
||||
text: this.$gettext('Stereo Tool'),
|
||||
value: AUDIO_PROCESSING_STEREO_TOOL,
|
||||
}
|
||||
)
|
||||
}
|
||||
const isBackendEnabled = computed(() => {
|
||||
return props.form.backend_type.$model !== BACKEND_NONE;
|
||||
});
|
||||
|
||||
return audioProcessingOptions;
|
||||
const isStereoToolEnabled = computed(() => {
|
||||
return props.form.backend_config.audio_processing_method.$model === AUDIO_PROCESSING_STEREO_TOOL;
|
||||
});
|
||||
|
||||
const {$gettext} = gettext;
|
||||
|
||||
const backendTypeOptions = computed(() => {
|
||||
return [
|
||||
{
|
||||
text: $gettext('Use Liquidsoap on this server.'),
|
||||
value: BACKEND_LIQUIDSOAP
|
||||
},
|
||||
charsetOptions() {
|
||||
return [
|
||||
{text: 'UTF-8', value: 'UTF-8'},
|
||||
{text: 'ISO-8859-1', value: 'ISO-8859-1'}
|
||||
];
|
||||
},
|
||||
performanceModeOptions() {
|
||||
return [
|
||||
{
|
||||
text: this.$gettext('Use Less Memory (Uses More CPU)'),
|
||||
value: 'less_memory'
|
||||
},
|
||||
{
|
||||
text: this.$gettext('Balanced'),
|
||||
value: 'balanced'
|
||||
},
|
||||
{
|
||||
text: this.$gettext('Use Less CPU (Uses More Memory)'),
|
||||
value: 'less_cpu'
|
||||
},
|
||||
{
|
||||
text: this.$gettext('Disable Optimizations'),
|
||||
value: 'disabled'
|
||||
}
|
||||
];
|
||||
{
|
||||
text: $gettext('Do not use an AutoDJ service.'),
|
||||
value: BACKEND_NONE
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
const crossfadeOptions = computed(() => {
|
||||
return [
|
||||
{
|
||||
text: $gettext('Smart Mode'),
|
||||
value: 'smart',
|
||||
},
|
||||
{
|
||||
text: $gettext('Normal Mode'),
|
||||
value: 'normal',
|
||||
},
|
||||
{
|
||||
text: $gettext('Disable Crossfading'),
|
||||
value: 'none',
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
const audioProcessingOptions = computed(() => {
|
||||
const audioProcessingOptions = [
|
||||
{
|
||||
text: $gettext('Liquidsoap'),
|
||||
value: AUDIO_PROCESSING_LIQUIDSOAP,
|
||||
},
|
||||
{
|
||||
text: $gettext('Disable Processing'),
|
||||
value: AUDIO_PROCESSING_NONE,
|
||||
}
|
||||
];
|
||||
|
||||
if (props.isStereoToolInstalled) {
|
||||
audioProcessingOptions.splice(1, 0,
|
||||
{
|
||||
text: $gettext('Stereo Tool'),
|
||||
value: AUDIO_PROCESSING_STEREO_TOOL,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return audioProcessingOptions;
|
||||
});
|
||||
|
||||
const charsetOptions = computed(() => {
|
||||
return [
|
||||
{text: 'UTF-8', value: 'UTF-8'},
|
||||
{text: 'ISO-8859-1', value: 'ISO-8859-1'}
|
||||
];
|
||||
});
|
||||
|
||||
const performanceModeOptions = computed(() => {
|
||||
return [
|
||||
{
|
||||
text: $gettext('Use Less Memory (Uses More CPU)'),
|
||||
value: 'less_memory'
|
||||
},
|
||||
{
|
||||
text: $gettext('Balanced'),
|
||||
value: 'balanced'
|
||||
},
|
||||
{
|
||||
text: $gettext('Use Less CPU (Uses More Memory)'),
|
||||
value: 'less_cpu'
|
||||
},
|
||||
{
|
||||
text: $gettext('Disable Optimizations'),
|
||||
value: 'disabled'
|
||||
}
|
||||
];
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -171,64 +171,65 @@
|
|||
</b-form-fieldset>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import BFormFieldset from "~/components/Form/BFormFieldset";
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import {FRONTEND_ICECAST, FRONTEND_REMOTE, FRONTEND_SHOUTCAST} from "~/components/Entity/RadioAdapters";
|
||||
import objectToFormOptions from "~/functions/objectToFormOptions";
|
||||
import {computed} from "vue";
|
||||
import gettext from "~/vendor/gettext";
|
||||
|
||||
export default {
|
||||
name: 'AdminStationsFrontendForm',
|
||||
components: {BWrappedFormGroup, BFormFieldset},
|
||||
props: {
|
||||
form: Object,
|
||||
isShoutcastInstalled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
countries: Object,
|
||||
showAdvanced: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
const props = defineProps({
|
||||
form: Object,
|
||||
isShoutcastInstalled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
computed: {
|
||||
frontendTypeOptions() {
|
||||
let frontendOptions = [
|
||||
{
|
||||
text: this.$gettext('Use Icecast 2.4 on this server.'),
|
||||
value: FRONTEND_ICECAST
|
||||
},
|
||||
];
|
||||
|
||||
if (this.isShoutcastInstalled) {
|
||||
frontendOptions.push({
|
||||
text: this.$gettext('Use Shoutcast DNAS 2 on this server.'),
|
||||
value: FRONTEND_SHOUTCAST
|
||||
});
|
||||
}
|
||||
|
||||
frontendOptions.push({
|
||||
text: this.$gettext('Only connect to a remote server.'),
|
||||
value: FRONTEND_REMOTE
|
||||
});
|
||||
|
||||
return frontendOptions;
|
||||
},
|
||||
countryOptions() {
|
||||
return objectToFormOptions(this.countries);
|
||||
},
|
||||
isLocalFrontend() {
|
||||
return this.form.frontend_type.$model !== FRONTEND_REMOTE;
|
||||
},
|
||||
isShoutcastFrontend() {
|
||||
return this.form.frontend_type.$model === FRONTEND_SHOUTCAST;
|
||||
}
|
||||
countries: Object,
|
||||
showAdvanced: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
methods: {
|
||||
clearCountries() {
|
||||
this.form.frontend_config.banned_countries.$model = [];
|
||||
}
|
||||
});
|
||||
|
||||
const {$gettext} = gettext;
|
||||
|
||||
const frontendTypeOptions = computed(() => {
|
||||
let frontendOptions = [
|
||||
{
|
||||
text: $gettext('Use Icecast 2.4 on this server.'),
|
||||
value: FRONTEND_ICECAST
|
||||
},
|
||||
];
|
||||
|
||||
if (props.isShoutcastInstalled) {
|
||||
frontendOptions.push({
|
||||
text: $gettext('Use Shoutcast DNAS 2 on this server.'),
|
||||
value: FRONTEND_SHOUTCAST
|
||||
});
|
||||
}
|
||||
|
||||
frontendOptions.push({
|
||||
text: $gettext('Only connect to a remote server.'),
|
||||
value: FRONTEND_REMOTE
|
||||
});
|
||||
|
||||
return frontendOptions;
|
||||
});
|
||||
|
||||
const countryOptions = computed(() => {
|
||||
return objectToFormOptions(props.countries);
|
||||
});
|
||||
|
||||
const isLocalFrontend = computed(() => {
|
||||
return props.form.frontend_type.$model !== FRONTEND_REMOTE;
|
||||
});
|
||||
|
||||
const isShoutcastFrontend = computed(() => {
|
||||
return props.form.frontend_type.$model === FRONTEND_SHOUTCAST;
|
||||
});
|
||||
|
||||
const clearCountries = () => {
|
||||
props.form.frontend_config.banned_countries.$model = [];
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -74,29 +74,24 @@
|
|||
<backend-disabled v-else></backend-disabled>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import BFormFieldset from "~/components/Form/BFormFieldset";
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import {BACKEND_NONE} from "~/components/Entity/RadioAdapters";
|
||||
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
|
||||
import BFormMarkup from "~/components/Form/BFormMarkup";
|
||||
import BackendDisabled from "./Common/BackendDisabled.vue";
|
||||
import {computed} from "vue";
|
||||
|
||||
export default {
|
||||
name: 'AdminStationsHlsForm',
|
||||
components: {BackendDisabled, BFormMarkup, BWrappedFormCheckbox, BWrappedFormGroup, BFormFieldset},
|
||||
props: {
|
||||
form: Object,
|
||||
station: Object,
|
||||
showAdvanced: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
const props = defineProps({
|
||||
form: Object,
|
||||
station: Object,
|
||||
showAdvanced: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
computed: {
|
||||
isBackendEnabled() {
|
||||
return this.form.backend_type.$model !== BACKEND_NONE;
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const isBackendEnabled = computed(() => {
|
||||
return props.form.backend_type.$model !== BACKEND_NONE;
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -140,39 +140,39 @@
|
|||
</b-form-fieldset>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import BFormFieldset from "~/components/Form/BFormFieldset";
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import objectToFormOptions from "~/functions/objectToFormOptions";
|
||||
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
|
||||
import {computed} from "vue";
|
||||
import gettext from "~/vendor/gettext";
|
||||
|
||||
export default {
|
||||
name: 'AdminStationsProfileForm',
|
||||
components: {BWrappedFormCheckbox, BWrappedFormGroup, BFormFieldset},
|
||||
props: {
|
||||
form: Object,
|
||||
timezones: Object,
|
||||
showAdvanced: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
const props = defineProps({
|
||||
form: Object,
|
||||
timezones: Object,
|
||||
showAdvanced: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
computed: {
|
||||
timezoneOptions() {
|
||||
return objectToFormOptions(this.timezones);
|
||||
});
|
||||
|
||||
const timezoneOptions = computed(() => {
|
||||
return objectToFormOptions(props.timezones);
|
||||
});
|
||||
|
||||
const {$gettext} = gettext;
|
||||
|
||||
const historyItemsOptions = computed(() => {
|
||||
return [
|
||||
{
|
||||
text: $gettext('Disabled'),
|
||||
value: 0,
|
||||
},
|
||||
historyItemsOptions() {
|
||||
return [
|
||||
{
|
||||
text: this.$gettext('Disabled'),
|
||||
value: 0,
|
||||
},
|
||||
{text: '1', value: 1},
|
||||
{text: '5', value: 5},
|
||||
{text: '10', value: 10},
|
||||
{text: '15', value: 15}
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
{text: '1', value: 1},
|
||||
{text: '5', value: 5},
|
||||
{text: '10', value: 10},
|
||||
{text: '15', value: 15}
|
||||
];
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -60,29 +60,24 @@
|
|||
<backend-disabled v-else></backend-disabled>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import BFormFieldset from "~/components/Form/BFormFieldset";
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import {BACKEND_NONE} from "~/components/Entity/RadioAdapters";
|
||||
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
|
||||
import BFormMarkup from "~/components/Form/BFormMarkup";
|
||||
import BackendDisabled from "./Common/BackendDisabled.vue";
|
||||
import {computed} from "vue";
|
||||
|
||||
export default {
|
||||
name: 'AdminStationsRequestsForm',
|
||||
components: {BackendDisabled, BFormMarkup, BWrappedFormCheckbox, BWrappedFormGroup, BFormFieldset},
|
||||
props: {
|
||||
form: Object,
|
||||
station: Object,
|
||||
showAdvanced: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
const props = defineProps({
|
||||
form: Object,
|
||||
station: Object,
|
||||
showAdvanced: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
computed: {
|
||||
isBackendEnabled() {
|
||||
return this.form.backend_type.$model !== BACKEND_NONE;
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const isBackendEnabled = computed(() => {
|
||||
return props.form.backend_type.$model !== BACKEND_NONE;
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -134,61 +134,58 @@
|
|||
<backend-disabled v-else></backend-disabled>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import BFormFieldset from "~/components/Form/BFormFieldset";
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import {BACKEND_NONE} from "~/components/Entity/RadioAdapters";
|
||||
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
|
||||
import BFormMarkup from "~/components/Form/BFormMarkup";
|
||||
import BackendDisabled from "./Common/BackendDisabled.vue";
|
||||
import {computed} from "vue";
|
||||
|
||||
export default {
|
||||
name: 'AdminStationsStreamersForm',
|
||||
components: {BackendDisabled, BFormMarkup, BWrappedFormCheckbox, BWrappedFormGroup, BFormFieldset},
|
||||
props: {
|
||||
form: Object,
|
||||
station: Object,
|
||||
showAdvanced: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
const props = defineProps({
|
||||
form: Object,
|
||||
station: Object,
|
||||
showAdvanced: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
computed: {
|
||||
isBackendEnabled() {
|
||||
return this.form.backend_type.$model !== BACKEND_NONE;
|
||||
});
|
||||
|
||||
const isBackendEnabled = computed(() => {
|
||||
return props.form.backend_type.$model !== BACKEND_NONE;
|
||||
});
|
||||
|
||||
const recordStreamsOptions = computed(() => {
|
||||
return [
|
||||
{
|
||||
text: 'MP3',
|
||||
value: 'mp3',
|
||||
},
|
||||
recordStreamsOptions() {
|
||||
return [
|
||||
{
|
||||
text: 'MP3',
|
||||
value: 'mp3',
|
||||
},
|
||||
{
|
||||
text: 'OGG Vorbis',
|
||||
value: 'ogg',
|
||||
},
|
||||
{
|
||||
text: 'OGG Opus',
|
||||
value: 'opus',
|
||||
},
|
||||
{
|
||||
text: 'AAC+ (MPEG4 HE-AAC v2)',
|
||||
value: 'aac'
|
||||
}
|
||||
];
|
||||
{
|
||||
text: 'OGG Vorbis',
|
||||
value: 'ogg',
|
||||
},
|
||||
recordBitrateOptions() {
|
||||
return [
|
||||
{text: '32', value: 32},
|
||||
{text: '48', value: 48},
|
||||
{text: '64', value: 64},
|
||||
{text: '96', value: 96},
|
||||
{text: '128', value: 128},
|
||||
{text: '192', value: 192},
|
||||
{text: '256', value: 256},
|
||||
{text: '320', value: 320}
|
||||
];
|
||||
{
|
||||
text: 'OGG Opus',
|
||||
value: 'opus',
|
||||
},
|
||||
}
|
||||
}
|
||||
{
|
||||
text: 'AAC+ (MPEG4 HE-AAC v2)',
|
||||
value: 'aac'
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
const recordBitrateOptions = computed(() => {
|
||||
return [
|
||||
{text: '32', value: 32},
|
||||
{text: '48', value: 48},
|
||||
{text: '64', value: 64},
|
||||
{text: '96', value: 96},
|
||||
{text: '128', value: 128},
|
||||
{text: '192', value: 192},
|
||||
{text: '256', value: 256},
|
||||
{text: '320', value: 320}
|
||||
];
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
{{ $gettext('Profile') }}
|
||||
</template>
|
||||
|
||||
<admin-stations-profile-form :form="v$.form" :timezones="timezones"
|
||||
<admin-stations-profile-form :form="v$" :timezones="timezones"
|
||||
:show-advanced="showAdvanced"></admin-stations-profile-form>
|
||||
</b-tab>
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
|||
{{ $gettext('Broadcasting') }}
|
||||
</template>
|
||||
|
||||
<admin-stations-frontend-form :form="v$.form"
|
||||
<admin-stations-frontend-form :form="v$"
|
||||
:is-shoutcast-installed="isShoutcastInstalled"
|
||||
:countries="countries"
|
||||
:show-advanced="showAdvanced"></admin-stations-frontend-form>
|
||||
|
@ -29,7 +29,7 @@
|
|||
{{ $gettext('AutoDJ') }}
|
||||
</template>
|
||||
|
||||
<admin-stations-backend-form :form="v$.form" :station="station"
|
||||
<admin-stations-backend-form :form="v$" :station="station"
|
||||
:is-stereo-tool-installed="isStereoToolInstalled"
|
||||
:show-advanced="showAdvanced"></admin-stations-backend-form>
|
||||
</b-tab>
|
||||
|
@ -39,7 +39,7 @@
|
|||
{{ $gettext('HLS') }}
|
||||
</template>
|
||||
|
||||
<admin-stations-hls-form :form="v$.form" :station="station" :show-advanced="showAdvanced">
|
||||
<admin-stations-hls-form :form="v$" :station="station" :show-advanced="showAdvanced">
|
||||
</admin-stations-hls-form>
|
||||
</b-tab>
|
||||
|
||||
|
@ -48,7 +48,7 @@
|
|||
{{ $gettext('Song Requests') }}
|
||||
</template>
|
||||
|
||||
<admin-stations-requests-form :form="v$.form" :station="station" :show-advanced="showAdvanced">
|
||||
<admin-stations-requests-form :form="v$" :station="station" :show-advanced="showAdvanced">
|
||||
</admin-stations-requests-form>
|
||||
</b-tab>
|
||||
|
||||
|
@ -57,7 +57,7 @@
|
|||
{{ $gettext('Streamers/DJs') }}
|
||||
</template>
|
||||
|
||||
<admin-stations-streamers-form :form="v$.form" :station="station" :show-advanced="showAdvanced">
|
||||
<admin-stations-streamers-form :form="v$" :station="station" :show-advanced="showAdvanced">
|
||||
</admin-stations-streamers-form>
|
||||
</b-tab>
|
||||
|
||||
|
@ -66,7 +66,7 @@
|
|||
{{ $gettext('Administration') }}
|
||||
</template>
|
||||
|
||||
<admin-stations-admin-form :form="v$.form"
|
||||
<admin-stations-admin-form :form="v$"
|
||||
:is-edit-mode="isEditMode"
|
||||
:storage-location-api-url="storageLocationApiUrl"
|
||||
:show-advanced="showAdvanced">
|
||||
|
@ -87,7 +87,7 @@
|
|||
</b-overlay>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import AdminStationsProfileForm from "./Form/ProfileForm";
|
||||
import AdminStationsFrontendForm from "./Form/FrontendForm";
|
||||
import AdminStationsBackendForm from "./Form/BackendForm";
|
||||
|
@ -95,13 +95,356 @@ import AdminStationsAdminForm from "./Form/AdminForm";
|
|||
import AdminStationsHlsForm from "./Form/HlsForm.vue";
|
||||
import AdminStationsRequestsForm from "./Form/RequestsForm.vue";
|
||||
import AdminStationsStreamersForm from "./Form/StreamersForm.vue";
|
||||
import useVuelidate from "@vuelidate/core";
|
||||
import {decimal, numeric, required, url} from '@vuelidate/validators';
|
||||
import {AUDIO_PROCESSING_NONE, BACKEND_LIQUIDSOAP, FRONTEND_ICECAST} from "~/components/Entity/RadioAdapters";
|
||||
|
||||
import _ from "lodash";
|
||||
import {computed, ref, watch} from "vue";
|
||||
import useVuelidate from "@vuelidate/core";
|
||||
import {useNotify} from "~/vendor/bootstrapVue";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
import mergeExisting from "~/functions/mergeExisting";
|
||||
|
||||
const props = defineProps({
|
||||
...StationFormProps.props,
|
||||
createUrl: String,
|
||||
editUrl: String,
|
||||
isEditMode: Boolean,
|
||||
isModal: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['error', 'submitted', 'loadingUpdate', 'validUpdate']);
|
||||
|
||||
const buildForm = () => {
|
||||
let validations = {
|
||||
name: {required},
|
||||
description: {},
|
||||
genre: {},
|
||||
url: {url},
|
||||
timezone: {},
|
||||
enable_public_page: {},
|
||||
enable_on_demand: {},
|
||||
enable_hls: {},
|
||||
default_album_art_url: {},
|
||||
enable_on_demand_download: {},
|
||||
frontend_type: {required},
|
||||
frontend_config: {
|
||||
sc_license_id: {},
|
||||
sc_user_id: {},
|
||||
source_pw: {},
|
||||
admin_pw: {},
|
||||
},
|
||||
backend_type: {required},
|
||||
backend_config: {
|
||||
hls_enable_on_public_player: {},
|
||||
hls_is_default: {},
|
||||
crossfade_type: {},
|
||||
crossfade: {decimal},
|
||||
audio_processing_method: {},
|
||||
stereo_tool_license_key: {},
|
||||
record_streams: {},
|
||||
record_streams_format: {},
|
||||
record_streams_bitrate: {},
|
||||
dj_buffer: {numeric},
|
||||
},
|
||||
enable_requests: {},
|
||||
request_delay: {numeric},
|
||||
request_threshold: {numeric},
|
||||
enable_streamers: {},
|
||||
disconnect_deactivate_streamer: {},
|
||||
$validationGroups: {
|
||||
profileTab: [
|
||||
'name', 'description', 'genre', 'url', 'timezone', 'enable_public_page',
|
||||
'enable_on_demand', 'enable_on_demand_download', 'default_album_art_url'
|
||||
],
|
||||
frontendTab: [
|
||||
'frontend_type', 'frontend_config'
|
||||
],
|
||||
backendTab: [
|
||||
'backend_type', 'backend_config',
|
||||
],
|
||||
hlsTab: [
|
||||
'enable_hls',
|
||||
],
|
||||
requestsTab: [
|
||||
'enable_requests',
|
||||
'request_delay',
|
||||
'request_threshold'
|
||||
],
|
||||
streamersTab: [
|
||||
'enable_streamers',
|
||||
'disconnect_deactivate_streamer'
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
let blankForm = {
|
||||
name: '',
|
||||
description: '',
|
||||
genre: '',
|
||||
url: '',
|
||||
timezone: 'UTC',
|
||||
enable_public_page: true,
|
||||
enable_on_demand: false,
|
||||
enable_hls: false,
|
||||
default_album_art_url: '',
|
||||
enable_on_demand_download: true,
|
||||
frontend_type: FRONTEND_ICECAST,
|
||||
frontend_config: {
|
||||
sc_license_id: '',
|
||||
sc_user_id: '',
|
||||
source_pw: '',
|
||||
admin_pw: '',
|
||||
},
|
||||
backend_type: BACKEND_LIQUIDSOAP,
|
||||
backend_config: {
|
||||
hls_enable_on_public_player: false,
|
||||
hls_is_default: false,
|
||||
crossfade_type: 'normal',
|
||||
crossfade: 2,
|
||||
audio_processing_method: AUDIO_PROCESSING_NONE,
|
||||
stereo_tool_license_key: '',
|
||||
record_streams: false,
|
||||
record_streams_format: 'mp3',
|
||||
record_streams_bitrate: 128,
|
||||
dj_buffer: 5,
|
||||
},
|
||||
enable_requests: false,
|
||||
request_delay: 5,
|
||||
request_threshold: 15,
|
||||
enable_streamers: false,
|
||||
disconnect_deactivate_streamer: 0,
|
||||
};
|
||||
|
||||
function mergeCustom(objValue, srcValue) {
|
||||
if (_.isArray(objValue)) {
|
||||
return objValue.concat(srcValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (props.showAdvanced) {
|
||||
const advancedValidations = {
|
||||
short_name: {},
|
||||
api_history_items: {},
|
||||
frontend_config: {
|
||||
port: {numeric},
|
||||
max_listeners: {},
|
||||
custom_config: {},
|
||||
banned_ips: {},
|
||||
banned_countries: {},
|
||||
allowed_ips: {},
|
||||
banned_user_agents: {}
|
||||
},
|
||||
backend_config: {
|
||||
hls_segment_length: {numeric},
|
||||
hls_segments_in_playlist: {numeric},
|
||||
hls_segments_overhead: {numeric},
|
||||
dj_port: {numeric},
|
||||
telnet_port: {numeric},
|
||||
dj_mount_point: {},
|
||||
enable_replaygain_metadata: {},
|
||||
autodj_queue_length: {},
|
||||
use_manual_autodj: {},
|
||||
charset: {},
|
||||
performance_mode: {},
|
||||
duplicate_prevention_time_range: {},
|
||||
},
|
||||
$validationGroups: {
|
||||
profileTab: [
|
||||
'short_name', 'api_history_items'
|
||||
],
|
||||
}
|
||||
};
|
||||
_.mergeWith(validations, advancedValidations, mergeCustom);
|
||||
|
||||
const advancedForm = {
|
||||
short_name: '',
|
||||
api_history_items: 5,
|
||||
frontend_config: {
|
||||
port: '',
|
||||
max_listeners: '',
|
||||
custom_config: '',
|
||||
banned_ips: '',
|
||||
banned_countries: [],
|
||||
allowed_ips: '',
|
||||
banned_user_agents: '',
|
||||
},
|
||||
backend_config: {
|
||||
hls_segment_length: 4,
|
||||
hls_segments_in_playlist: 5,
|
||||
hls_segments_overhead: 2,
|
||||
dj_port: '',
|
||||
telnet_port: '',
|
||||
dj_mount_point: '/',
|
||||
enable_replaygain_metadata: false,
|
||||
autodj_queue_length: 3,
|
||||
use_manual_autodj: false,
|
||||
charset: 'UTF-8',
|
||||
performance_mode: 'disabled',
|
||||
duplicate_prevention_time_range: 120,
|
||||
},
|
||||
};
|
||||
_.merge(blankForm, advancedForm);
|
||||
}
|
||||
|
||||
if (props.showAdminTab) {
|
||||
const adminValidations = {
|
||||
media_storage_location: {},
|
||||
recordings_storage_location: {},
|
||||
podcasts_storage_location: {},
|
||||
is_enabled: {},
|
||||
$validationGroups: {
|
||||
adminTab: [
|
||||
'media_storage_location', 'recordings_storage_location',
|
||||
'podcasts_storage_location', 'is_enabled'
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
_.mergeWith(validations, adminValidations, mergeCustom);
|
||||
|
||||
const adminForm = {
|
||||
media_storage_location: '',
|
||||
recordings_storage_location: '',
|
||||
podcasts_storage_location: '',
|
||||
is_enabled: true,
|
||||
};
|
||||
_.merge(blankForm, adminForm);
|
||||
|
||||
if (props.showAdvanced) {
|
||||
const advancedAdminValidations = {
|
||||
radio_base_dir: {},
|
||||
$validationGroups: {
|
||||
adminTab: [
|
||||
'radio_base_dir'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
_.mergeWith(validations, advancedAdminValidations, mergeCustom);
|
||||
|
||||
const adminAdvancedForm = {
|
||||
radio_base_dir: '',
|
||||
};
|
||||
_.merge(blankForm, adminAdvancedForm);
|
||||
}
|
||||
}
|
||||
|
||||
return {blankForm, validations};
|
||||
};
|
||||
|
||||
const {blankForm, validations} = buildForm();
|
||||
|
||||
const form = ref({...blankForm});
|
||||
|
||||
const v$ = useVuelidate(validations, form);
|
||||
|
||||
const isValid = computed(() => {
|
||||
return !v$.value?.$invalid ?? true;
|
||||
});
|
||||
|
||||
watch(isValid, (newValue) => {
|
||||
emit('validUpdate', newValue);
|
||||
});
|
||||
|
||||
const loading = ref(true);
|
||||
|
||||
watch(loading, (newValue) => {
|
||||
emit('loadingUpdate', newValue);
|
||||
});
|
||||
|
||||
const error = ref(null);
|
||||
|
||||
const blankStation = {
|
||||
stereo_tool_configuration_file_path: null,
|
||||
links: {
|
||||
stereo_tool_configuration: null
|
||||
}
|
||||
};
|
||||
|
||||
const station = ref({...blankStation});
|
||||
|
||||
const tabContentClass = computed(() => {
|
||||
return (props.isModal)
|
||||
? 'mt-3'
|
||||
: '';
|
||||
});
|
||||
|
||||
const getTabClass = (validationGroup) => {
|
||||
if (!loading.value && validationGroup.$invalid) {
|
||||
return 'text-danger';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
loading.value = false;
|
||||
error.value = null;
|
||||
station.value = {...blankStation};
|
||||
form.value = {...blankForm};
|
||||
};
|
||||
|
||||
const populateForm = (data) => {
|
||||
form.value = mergeExisting(form.value, data);
|
||||
};
|
||||
|
||||
const {wrapWithLoading, notifySuccess} = useNotify();
|
||||
const {axios} = useAxios();
|
||||
|
||||
const doLoad = () => {
|
||||
loading.value = true;
|
||||
|
||||
wrapWithLoading(
|
||||
axios.get(props.editUrl)
|
||||
).then((resp) => {
|
||||
populateForm(resp.data);
|
||||
}).catch((err) => {
|
||||
emit('error', err);
|
||||
}).finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
clear();
|
||||
if (props.isEditMode) {
|
||||
doLoad();
|
||||
}
|
||||
};
|
||||
|
||||
const submit = () => {
|
||||
v$.value.$touch();
|
||||
if (v$.value.$errors.length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
error.value = null;
|
||||
wrapWithLoading(
|
||||
axios({
|
||||
method: (props.isEditMode)
|
||||
? 'PUT'
|
||||
: 'POST',
|
||||
url: (props.isEditMode)
|
||||
? props.editUrl
|
||||
: props.createUrl,
|
||||
data: form.value
|
||||
})
|
||||
).then(() => {
|
||||
notifySuccess();
|
||||
emit('submitted');
|
||||
}).catch((err) => {
|
||||
error.value = err.response.data.message;
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
reset,
|
||||
submit
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export const StationFormProps = {
|
||||
props: {
|
||||
// Global
|
||||
|
@ -131,362 +474,6 @@ export const StationFormProps = {
|
|||
};
|
||||
|
||||
export default {
|
||||
name: 'AdminStationsForm',
|
||||
inheritAttrs: false,
|
||||
components: {
|
||||
AdminStationsStreamersForm,
|
||||
AdminStationsRequestsForm,
|
||||
AdminStationsHlsForm,
|
||||
AdminStationsAdminForm,
|
||||
AdminStationsBackendForm,
|
||||
AdminStationsFrontendForm,
|
||||
AdminStationsProfileForm
|
||||
},
|
||||
emits: ['error', 'submitted', 'loadingUpdate', 'validUpdate'],
|
||||
setup() {
|
||||
return {
|
||||
v$: useVuelidate()
|
||||
};
|
||||
},
|
||||
props: {
|
||||
createUrl: String,
|
||||
editUrl: String,
|
||||
isEditMode: Boolean,
|
||||
isModal: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
mixins: [
|
||||
StationFormProps
|
||||
],
|
||||
validations() {
|
||||
let formValidations = {
|
||||
form: {
|
||||
name: {required},
|
||||
description: {},
|
||||
genre: {},
|
||||
url: {url},
|
||||
timezone: {},
|
||||
enable_public_page: {},
|
||||
enable_on_demand: {},
|
||||
enable_hls: {},
|
||||
default_album_art_url: {},
|
||||
enable_on_demand_download: {},
|
||||
frontend_type: {required},
|
||||
frontend_config: {
|
||||
sc_license_id: {},
|
||||
sc_user_id: {},
|
||||
source_pw: {},
|
||||
admin_pw: {},
|
||||
},
|
||||
backend_type: {required},
|
||||
backend_config: {
|
||||
hls_enable_on_public_player: {},
|
||||
hls_is_default: {},
|
||||
crossfade_type: {},
|
||||
crossfade: {decimal},
|
||||
audio_processing_method: {},
|
||||
stereo_tool_license_key: {},
|
||||
record_streams: {},
|
||||
record_streams_format: {},
|
||||
record_streams_bitrate: {},
|
||||
dj_buffer: {numeric},
|
||||
},
|
||||
enable_requests: {},
|
||||
request_delay: {numeric},
|
||||
request_threshold: {numeric},
|
||||
enable_streamers: {},
|
||||
disconnect_deactivate_streamer: {},
|
||||
},
|
||||
$validationGroups: {
|
||||
profileTab: [
|
||||
'form.name', 'form.description', 'form.genre', 'form.url', 'form.timezone', 'form.enable_public_page',
|
||||
'form.enable_on_demand', 'form.enable_on_demand_download', 'form.default_album_art_url'
|
||||
],
|
||||
frontendTab: [
|
||||
'form.frontend_type', 'form.frontend_config'
|
||||
],
|
||||
backendTab: [
|
||||
'form.backend_type', 'form.backend_config',
|
||||
],
|
||||
hlsTab: [
|
||||
'form.enable_hls',
|
||||
],
|
||||
requestsTab: [
|
||||
'form.enable_requests',
|
||||
'form.request_delay',
|
||||
'form.request_threshold'
|
||||
],
|
||||
streamersTab: [
|
||||
'form.enable_streamers',
|
||||
'form.disconnect_deactivate_streamer'
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
function mergeCustom(objValue, srcValue) {
|
||||
if (_.isArray(objValue)) {
|
||||
return objValue.concat(srcValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.showAdvanced) {
|
||||
const advancedValidations = {
|
||||
form: {
|
||||
short_name: {},
|
||||
api_history_items: {},
|
||||
frontend_config: {
|
||||
port: {numeric},
|
||||
max_listeners: {},
|
||||
custom_config: {},
|
||||
banned_ips: {},
|
||||
banned_countries: {},
|
||||
allowed_ips: {},
|
||||
banned_user_agents: {}
|
||||
},
|
||||
backend_config: {
|
||||
hls_segment_length: {numeric},
|
||||
hls_segments_in_playlist: {numeric},
|
||||
hls_segments_overhead: {numeric},
|
||||
dj_port: {numeric},
|
||||
telnet_port: {numeric},
|
||||
dj_mount_point: {},
|
||||
enable_replaygain_metadata: {},
|
||||
autodj_queue_length: {},
|
||||
use_manual_autodj: {},
|
||||
charset: {},
|
||||
performance_mode: {},
|
||||
duplicate_prevention_time_range: {},
|
||||
},
|
||||
},
|
||||
$validationGroups: {
|
||||
profileTab: [
|
||||
'form.short_name', 'form.api_history_items'
|
||||
],
|
||||
}
|
||||
};
|
||||
|
||||
_.mergeWith(formValidations, advancedValidations, mergeCustom);
|
||||
}
|
||||
|
||||
if (this.showAdminTab) {
|
||||
const adminValidations = {
|
||||
form: {
|
||||
media_storage_location: {},
|
||||
recordings_storage_location: {},
|
||||
podcasts_storage_location: {},
|
||||
is_enabled: {},
|
||||
},
|
||||
$validationGroups: {
|
||||
adminTab: [
|
||||
'form.media_storage_location', 'form.recordings_storage_location',
|
||||
'form.podcasts_storage_location', 'form.is_enabled'
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
_.mergeWith(formValidations, adminValidations, mergeCustom);
|
||||
|
||||
if (this.showAdvanced) {
|
||||
const advancedAdminValidations = {
|
||||
form: {
|
||||
radio_base_dir: {},
|
||||
},
|
||||
$validationGroups: {
|
||||
adminTab: [
|
||||
'form.radio_base_dir'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
_.mergeWith(formValidations, advancedAdminValidations, mergeCustom);
|
||||
}
|
||||
}
|
||||
|
||||
return formValidations;
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
error: null,
|
||||
form: this.getEmptyForm(),
|
||||
station: {},
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
loading(newValue) {
|
||||
this.$emit('loadingUpdate', newValue);
|
||||
},
|
||||
isValid(newValue) {
|
||||
this.$emit('validUpdate', newValue);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isValid() {
|
||||
return !this.v$?.form?.$invalid ?? true;
|
||||
},
|
||||
tabContentClass() {
|
||||
return (this.isModal)
|
||||
? 'mt-3'
|
||||
: '';
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getTabClass(validationGroup) {
|
||||
if (!this.loading && validationGroup.$invalid) {
|
||||
return 'text-danger';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
getEmptyForm() {
|
||||
let form = {
|
||||
name: '',
|
||||
description: '',
|
||||
genre: '',
|
||||
url: '',
|
||||
timezone: 'UTC',
|
||||
enable_public_page: true,
|
||||
enable_on_demand: false,
|
||||
enable_hls: false,
|
||||
default_album_art_url: '',
|
||||
enable_on_demand_download: true,
|
||||
frontend_type: FRONTEND_ICECAST,
|
||||
frontend_config: {
|
||||
sc_license_id: '',
|
||||
sc_user_id: '',
|
||||
source_pw: '',
|
||||
admin_pw: '',
|
||||
},
|
||||
backend_type: BACKEND_LIQUIDSOAP,
|
||||
backend_config: {
|
||||
hls_enable_on_public_player: false,
|
||||
hls_is_default: false,
|
||||
crossfade_type: 'normal',
|
||||
crossfade: 2,
|
||||
audio_processing_method: AUDIO_PROCESSING_NONE,
|
||||
stereo_tool_license_key: '',
|
||||
record_streams: false,
|
||||
record_streams_format: 'mp3',
|
||||
record_streams_bitrate: 128,
|
||||
dj_buffer: 5,
|
||||
},
|
||||
enable_requests: false,
|
||||
request_delay: 5,
|
||||
request_threshold: 15,
|
||||
enable_streamers: false,
|
||||
disconnect_deactivate_streamer: 0,
|
||||
};
|
||||
|
||||
if (this.showAdvanced) {
|
||||
const advancedForm = {
|
||||
short_name: '',
|
||||
api_history_items: 5,
|
||||
frontend_config: {
|
||||
port: '',
|
||||
max_listeners: '',
|
||||
custom_config: '',
|
||||
banned_ips: '',
|
||||
banned_countries: [],
|
||||
allowed_ips: '',
|
||||
banned_user_agents: '',
|
||||
},
|
||||
backend_config: {
|
||||
hls_segment_length: 4,
|
||||
hls_segments_in_playlist: 5,
|
||||
hls_segments_overhead: 2,
|
||||
dj_port: '',
|
||||
telnet_port: '',
|
||||
dj_mount_point: '/',
|
||||
enable_replaygain_metadata: false,
|
||||
autodj_queue_length: 3,
|
||||
use_manual_autodj: false,
|
||||
charset: 'UTF-8',
|
||||
performance_mode: 'disabled',
|
||||
duplicate_prevention_time_range: 120,
|
||||
},
|
||||
};
|
||||
_.merge(form, advancedForm);
|
||||
}
|
||||
|
||||
if (this.showAdminTab) {
|
||||
const adminForm = {
|
||||
media_storage_location: '',
|
||||
recordings_storage_location: '',
|
||||
podcasts_storage_location: '',
|
||||
is_enabled: true,
|
||||
};
|
||||
_.merge(form, adminForm);
|
||||
|
||||
if (this.showAdvanced) {
|
||||
const adminAdvancedForm = {
|
||||
radio_base_dir: '',
|
||||
};
|
||||
_.merge(form, adminAdvancedForm);
|
||||
}
|
||||
}
|
||||
|
||||
return form;
|
||||
},
|
||||
clear() {
|
||||
this.loading = false;
|
||||
this.error = null;
|
||||
this.station = {
|
||||
stereo_tool_configuration_file_path: null,
|
||||
links: {
|
||||
stereo_tool_configuration: null
|
||||
}
|
||||
};
|
||||
this.form = this.getEmptyForm();
|
||||
},
|
||||
reset() {
|
||||
this.clear();
|
||||
if (this.isEditMode) {
|
||||
this.doLoad();
|
||||
}
|
||||
},
|
||||
doLoad() {
|
||||
this.$wrapWithLoading(
|
||||
this.axios.get(this.editUrl)
|
||||
).then((resp) => {
|
||||
this.populateForm(resp.data);
|
||||
}).catch((error) => {
|
||||
this.$emit('error', error);
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
populateForm(data) {
|
||||
this.form = mergeExisting(this.form, data);
|
||||
},
|
||||
getSubmittableFormData() {
|
||||
return this.form;
|
||||
},
|
||||
submit() {
|
||||
this.v$.$touch();
|
||||
if (this.v$.$errors.length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.error = null;
|
||||
|
||||
this.$wrapWithLoading(
|
||||
this.axios({
|
||||
method: (this.isEditMode)
|
||||
? 'PUT'
|
||||
: 'POST',
|
||||
url: (this.isEditMode)
|
||||
? this.editUrl
|
||||
: this.createUrl,
|
||||
data: this.getSubmittableFormData()
|
||||
})
|
||||
).then(() => {
|
||||
this.$notifySuccess();
|
||||
this.$emit('submitted');
|
||||
}).catch((error) => {
|
||||
this.error = error.response.data.message;
|
||||
});
|
||||
},
|
||||
}
|
||||
inheritAttrs: false
|
||||
}
|
||||
</script>
|
||||
|
|
Loading…
Reference in New Issue