From cf5e232488dc1389ca2ab45d1870bd0387aa3b7b Mon Sep 17 00:00:00 2001 From: Konrad Mohrfeldt <konrad.mohrfeldt@farbdev.org> Date: Tue, 28 May 2024 11:51:11 +0200 Subject: [PATCH] feat: add m3u playlist entry type refs #291 --- src/components/playlist/AM3uUrlDialog.vue | 37 +++++++++++++++++++ src/components/playlist/APlaylistEditor.vue | 20 ++++++++++ .../playlist/APlaylistEntryEditor.vue | 6 +++ src/i18n/de.js | 6 +++ src/i18n/en.js | 6 +++ 5 files changed, 75 insertions(+) create mode 100644 src/components/playlist/AM3uUrlDialog.vue diff --git a/src/components/playlist/AM3uUrlDialog.vue b/src/components/playlist/AM3uUrlDialog.vue new file mode 100644 index 00000000..d92fc94a --- /dev/null +++ b/src/components/playlist/AM3uUrlDialog.vue @@ -0,0 +1,37 @@ +<template> + <AEditDialog + ref="dialog" + :title="t('playlist.editor.addM3uDialog.title')" + :save-label="t('playlist.editor.addM3uDialog.saveLabel')" + :can-save="canSave" + :save="() => emit('save', url)" + class="md:tw-w-[600px]" + > + <FormTable> + <FormGroup v-slot="attrs" :label="t('file.name')" center> + <input v-bind="attrs" v-model="name" type="text" /> + </FormGroup> + </FormTable> + </AEditDialog> +</template> + +<script setup lang="ts"> +import { computed, onMounted, ref } from 'vue' + +import { useI18n } from '@/i18n' +import FormGroup from '@/components/generic/FormGroup.vue' +import FormTable from '@/components/generic/FormTable.vue' +import AEditDialog from '@/components/generic/AEditDialog.vue' + +const emit = defineEmits<{ + save: [string] +}>() + +const { t } = useI18n() +const dialog = ref() +const name = ref('') +const url = computed(() => 'm3u://' + name.value.trim().replace(/^m3u:\/\//i, '')) +const canSave = computed(() => /\.m3u$/i.test(name.value)) + +onMounted(() => dialog.value.open()) +</script> diff --git a/src/components/playlist/APlaylistEditor.vue b/src/components/playlist/APlaylistEditor.vue index 23e711ab..7657f926 100644 --- a/src/components/playlist/APlaylistEditor.vue +++ b/src/components/playlist/APlaylistEditor.vue @@ -132,6 +132,12 @@ {{ t('playlist.editor.control.addInput') }} </button> </APermissionGuard> + <APermissionGuard show-permissions="program.add__m3ufile"> + <button type="button" class="btn btn-default" @click="addM3utoPlaylist"> + <icon-ph-playlist-light class="tw-flex-none" /> + {{ t('playlist.editor.control.addM3u') }} + </button> + </APermissionGuard> </div> </div> </fieldset> @@ -154,6 +160,12 @@ <AInputUrlDialog @save="resolve($event)" @close="resolve(null)" /> </GetInputUrl> </APermissionGuard> + + <APermissionGuard show-permissions="programm.add__m3ufile"> + <GetM3uUrl v-slot="{ resolve }"> + <AM3uUrlDialog @save="resolve($event)" @close="resolve(null)" /> + </GetM3uUrl> + </APermissionGuard> </template> <script lang="ts" setup> @@ -170,6 +182,7 @@ import { ensureError, getFilenameFromURL, useAsyncFunction } from '@/util' import AStreamURLDialog from '@/components/playlist/AStreamURLDialog.vue' import AFileUrlDialog from '@/components/playlist/AFileUrlDialog.vue' import AInputUrlDialog from '@/components/playlist/AInputUrlDialog.vue' +import AM3uUrlDialog from '@/components/playlist/AM3uUrlDialog.vue' import Loading from '@/components/generic/Loading.vue' import AUploadProgress from '@/components/playlist/AUploadProgress.vue' import SaveIndicator from '@/components/generic/SaveIndicator.vue' @@ -201,6 +214,7 @@ const playlistStore = usePlaylistStore() const GetStreamUrl = createTemplatePromise<string | null>() const GetFileImportUrl = createTemplatePromise<string | null>() const GetInputUrl = createTemplatePromise<string | null>() +const GetM3uUrl = createTemplatePromise<string | null>() const entries = useCopy(() => props.playlist?.entries ?? [], { save: () => updatePlaylistEntries(), @@ -324,6 +338,12 @@ async function addInputToPlaylist() { await updatePlaylistEntries({ uri: inputUrl }) } +async function addM3utoPlaylist() { + const m3uUrl = await GetM3uUrl.start() + if (!m3uUrl) return + await updatePlaylistEntries({ uri: m3uUrl }) +} + const { fn: updatePlaylistEntries, isProcessing: isUpdatingPlaylist } = useAsyncFunction( async function (...newEntries: Partial<PlaylistEntry>[]) { try { diff --git a/src/components/playlist/APlaylistEntryEditor.vue b/src/components/playlist/APlaylistEntryEditor.vue index ce2f57fe..a0766df3 100644 --- a/src/components/playlist/APlaylistEntryEditor.vue +++ b/src/components/playlist/APlaylistEntryEditor.vue @@ -44,6 +44,12 @@ {{ entry.uri }} </span> </template> + <template v-else-if="type === 'm3u'"> + <icon-ph-playlist-light class="tw-flex-none" /> + <span class="tw-truncate"> + {{ uri.pathname.replace(/^\/*/, '') }} + </span> + </template> </span> <span class="tw-ml-auto"> diff --git a/src/i18n/de.js b/src/i18n/de.js index 68a9759f..975c8bdc 100644 --- a/src/i18n/de.js +++ b/src/i18n/de.js @@ -238,6 +238,7 @@ export default { file: { url: 'URL', + name: 'Dateiname', unnamed: 'Unbenannte Datei', duration: 'Dauer', durationUnknown: 'Unbekannte Dauer', @@ -291,6 +292,7 @@ export default { importFile: 'Datei von URL importieren', addStream: 'Stream hinzufügen', addInput: 'Eingang hinzufügen', + addM3u: 'M3U hinzufügen', }, importFileDialog: { title: 'Datei von URL importieren', @@ -304,6 +306,10 @@ export default { title: 'Stream als Medienquelle hinzufügen', saveLabel: 'Stream hinzufügen', }, + addM3uDialog: { + title: 'M3U als Medienquelle hinzufügen', + saveLabel: 'M3U hinzufügen', + }, }, state: { ok: { title: 'Perfekt' }, diff --git a/src/i18n/en.js b/src/i18n/en.js index e4ac7217..921cb608 100644 --- a/src/i18n/en.js +++ b/src/i18n/en.js @@ -239,6 +239,7 @@ export default { file: { url: 'URL', + name: 'Filename', unnamed: 'Unnamed file', duration: 'Duration', durationUnknown: 'Unknown duration', @@ -292,6 +293,7 @@ export default { importFile: 'Import file from URL', addStream: 'Add stream', addInput: 'Add input', + addM3u: 'Add M3U', }, importFileDialog: { title: 'Import file from URL', @@ -305,6 +307,10 @@ export default { title: 'Add stream as media source', saveLabel: 'Add stream', }, + addM3uDialog: { + title: 'Add M3U as media source', + saveLabel: 'Add M3U', + }, }, state: { ok: { title: 'Perfect' }, -- GitLab