Move several components fully into Vue renders.

This commit is contained in:
Buster "Silver Eagle" Neece 2021-10-07 23:13:21 -05:00
parent 798bfd1eb2
commit 3865224d31
No known key found for this signature in database
GPG Key ID: 6D9E12FF03411F4E
23 changed files with 534 additions and 555 deletions

View File

@ -14,12 +14,12 @@ export default {
components: {FullCalendar},
props: {
scheduleUrl: String,
stationTimeZone: String,
locale: String
stationTimeZone: String
},
data() {
return {
calendarOptions: {
locale: App.locale_short,
locales: allLocales,
plugins: [luxonPlugin, timeGridPlugin],
initialView: 'timeGridWeek',
@ -27,7 +27,6 @@ export default {
themeSystem: 'bootstrap',
nowIndicator: true,
defaultTimedEventDuration: '00:20',
locale: this.locale,
headerToolbar: false,
footerToolbar: false,
height: 'auto',

View File

@ -1,49 +1,53 @@
<template>
<div class="card" style="height: 100%;">
<div class="card-header bg-primary-dark">
<div class="d-flex align-items-center">
<div class="flex-shrink">
<h2 class="card-title py-2">
<template v-if="stationName">
{{ stationName }}
<section id="content" role="main" class="d-flex align-items-stretch" style="height: 100vh;">
<div class="container pt-5 pb-5 h-100" style="flex: 1;">
<div class="card" style="height: 100%;">
<div class="card-header bg-primary-dark">
<div class="d-flex align-items-center">
<div class="flex-shrink">
<h2 class="card-title py-2">
<template v-if="stationName">
{{ stationName }}
</template>
<template v-else>
<translate key="lang_title">On-Demand Media</translate>
</template>
</h2>
</div>
<div class="flex-fill text-right">
<inline-player ref="player"></inline-player>
</div>
</div>
</div>
<data-table ref="datatable" id="station_on_demand_table" paginated select-fields
:fields="fields" :api-url="listUrl">
<template #cell(download_url)="row">
<play-button class="file-icon" icon-class="outlined" :url="row.item.download_url"
:is-stream="false"></play-button>
<template v-if="showDownloadButton">
&nbsp;
<a class="name" :href="row.item.download_url" target="_blank" :title="langDownload">
<icon icon="cloud_download"></icon>
</a>
</template>
</template>
<template #cell(media_art)="row">
<a :href="row.item.media_art" class="album-art" target="_blank"
data-fancybox="gallery">
<img class="media_manager_album_art" :alt="langAlbumArt" :src="row.item.media_art">
</a>
</template>
<template #cell(size)="row">
<template v-if="!row.item.size">&nbsp;</template>
<template v-else>
<translate key="lang_title">On-Demand Media</translate>
{{ formatFileSize(row.item.size) }}
</template>
</h2>
</div>
<div class="flex-fill text-right">
<inline-player ref="player"></inline-player>
</div>
</template>
</data-table>
</div>
</div>
<data-table ref="datatable" id="station_on_demand_table" paginated select-fields
:fields="fields" :api-url="listUrl">
<template #cell(download_url)="row">
<play-button class="file-icon" icon-class="outlined" :url="row.item.download_url"
:is-stream="false"></play-button>
<template v-if="showDownloadButton">
&nbsp;
<a class="name" :href="row.item.download_url" target="_blank" :title="langDownload">
<icon icon="cloud_download"></icon>
</a>
</template>
</template>
<template #cell(media_art)="row">
<a :href="row.item.media_art" class="album-art" target="_blank"
data-fancybox="gallery">
<img class="media_manager_album_art" :alt="langAlbumArt" :src="row.item.media_art">
</a>
</template>
<template #cell(size)="row">
<template v-if="!row.item.size">&nbsp;</template>
<template v-else>
{{ formatFileSize(row.item.size) }}
</template>
</template>
</data-table>
</div>
</section>
</template>
<style lang="scss">

View File

@ -1,25 +1,29 @@
<template>
<div class="card" style="height: 100%;">
<div class="card-header bg-primary-dark">
<div class="d-flex align-items-center">
<div class="flex-shrink">
<h2 class="card-title py-2">
<template v-if="stationName">
{{ stationName }}
</template>
<template v-else>
<translate key="lang_title">Schedule</translate>
</template>
</h2>
<section id="content" role="main" class="d-flex align-items-stretch" style="height: 100vh;">
<div class="container pt-5 pb-5 h-100" style="flex: 1;">
<div class="card" style="height: 100%;">
<div class="card-header bg-primary-dark">
<div class="d-flex align-items-center">
<div class="flex-shrink">
<h2 class="card-title py-2">
<template v-if="stationName">
{{ stationName }}
</template>
<template v-else>
<translate key="lang_title">Schedule</translate>
</template>
</h2>
</div>
</div>
</div>
<div id="station-schedule-calendar">
<schedule ref="schedule" :schedule-url="scheduleUrl"
:station-time-zone="stationTimeZone"></schedule>
</div>
</div>
</div>
<div id="station-schedule-calendar">
<schedule ref="schedule" :schedule-url="scheduleUrl" :station-time-zone="stationTimeZone"
:locale="locale"></schedule>
</div>
</div>
</section>
</template>
<style lang="scss">
@ -43,7 +47,6 @@ export default {
props: {
scheduleUrl: String,
stationName: String,
locale: String,
stationTimeZone: String
},
};

View File

@ -1,30 +1,34 @@
<template>
<div class="row">
<div class="col-md-4 mb-sm-4">
<settings-panel v-bind="{ stationName, baseUri, libUrls }"></settings-panel>
</div>
<div class="col-md-8">
<section id="content" role="main" style="height: 100vh;">
<div class="container pt-5">
<div class="row">
<div class="col-md-8 mb-sm-4">
<microphone-panel></microphone-panel>
</div>
<div class="col-md-4 mb-sm-4">
<mixer-panel></mixer-panel>
</div>
</div>
<div class="row mb-4">
<div class="col-md-6 mb-sm-4">
<playlist-panel id="playlist_1"></playlist-panel>
<settings-panel v-bind="{ stationName, baseUri, libUrls }"></settings-panel>
</div>
<div class="col-md-6">
<playlist-panel id="playlist_2"></playlist-panel>
<div class="col-md-8">
<div class="row">
<div class="col-md-8 mb-sm-4">
<microphone-panel></microphone-panel>
</div>
<div class="col-md-4 mb-sm-4">
<mixer-panel></mixer-panel>
</div>
</div>
<div class="row mb-4">
<div class="col-md-6 mb-sm-4">
<playlist-panel id="playlist_1"></playlist-panel>
</div>
<div class="col-md-6">
<playlist-panel id="playlist_2"></playlist-panel>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</template>
<script>

View File

@ -109,7 +109,7 @@
</b-tab>
<b-tab :title="langScheduleViewTab" no-body>
<schedule ref="schedule" :schedule-url="scheduleUrl" :station-time-zone="stationTimeZone"
:locale="locale" @click="doCalendarClick"></schedule>
@click="doCalendarClick"></schedule>
</b-tab>
</b-tabs>
</b-card>
@ -143,7 +143,6 @@ export default {
props: {
listUrl: String,
scheduleUrl: String,
locale: String,
filesUrl: String,
stationTimeZone: String,
enableAdvancedFeatures: Boolean

View File

@ -1,59 +1,66 @@
<template>
<div>
<b-card no-body>
<b-card-header header-bg-variant="primary-dark">
<b-row class="align-items-center">
<b-col md="6">
<h2 class="card-title" key="lang_title" v-translate>Streamer/DJ Accounts</h2>
</b-col>
<b-col md="6" class="text-right text-muted">
<translate key="lang_station_tz" :translate-params="{ tz: stationTimeZone }">This station's time zone is currently %{tz}.</translate>
</b-col>
</b-row>
</b-card-header>
<div class="row">
<div class="col-md-8">
<b-card no-body>
<b-card-header header-bg-variant="primary-dark">
<b-row class="align-items-center">
<b-col md="6">
<h2 class="card-title" key="lang_title" v-translate>Streamer/DJ Accounts</h2>
</b-col>
<b-col md="6" class="text-right text-muted">
<translate key="lang_station_tz" :translate-params="{ tz: stationTimeZone }">This station's time zone is currently %{tz}.</translate>
</b-col>
</b-row>
</b-card-header>
<b-tabs pills card lazy>
<b-tab :title="langAccountListTab" no-body>
<b-card-body body-class="card-padding-sm">
<b-button variant="outline-primary" @click.prevent="doCreate">
<icon icon="add"></icon>
<translate key="lang_add_streamer">Add Streamer</translate>
</b-button>
</b-card-body>
<b-tabs pills card lazy>
<b-tab :title="langAccountListTab" no-body>
<b-card-body body-class="card-padding-sm">
<b-button variant="outline-primary" @click.prevent="doCreate">
<icon icon="add"></icon>
<translate key="lang_add_streamer">Add Streamer</translate>
</b-button>
</b-card-body>
<data-table ref="datatable" id="station_streamers" :show-toolbar="false" :fields="fields"
:api-url="listUrl">
<template #cell(streamer_username)="row">
<code>{{ row.item.streamer_username }}</code>
<div>
<data-table ref="datatable" id="station_streamers" :show-toolbar="false" :fields="fields"
:api-url="listUrl">
<template #cell(streamer_username)="row">
<code>{{ row.item.streamer_username }}</code>
<div>
<span class="badge badge-danger" v-if="!row.item.is_active">
<translate key="lang_disabled">Disabled</translate>
</span>
</div>
</template>
<template #cell(actions)="row">
<b-button-group size="sm">
<b-button size="sm" variant="primary" @click.prevent="doEdit(row.item.links.self)">
<translate key="lang_btn_edit">Edit</translate>
</b-button>
<b-button size="sm" variant="default" @click.prevent="doShowBroadcasts(row.item.links.broadcasts)">
<translate key="lang_btn_broadcasts">Broadcasts</translate>
</b-button>
<b-button size="sm" variant="danger" @click.prevent="doDelete(row.item.links.self)">
<translate key="lang_btn_delete">Delete</translate>
</b-button>
</b-button-group>
</template>
</data-table>
</b-tab>
<b-tab :title="langScheduleViewTab" no-body>
<schedule ref="schedule" :schedule-url="scheduleUrl" :station-time-zone="stationTimeZone"
:locale="locale" @click="doCalendarClick"></schedule>
</b-tab>
</b-tabs>
</b-card>
</div>
</template>
<template #cell(actions)="row">
<b-button-group size="sm">
<b-button size="sm" variant="primary" @click.prevent="doEdit(row.item.links.self)">
<translate key="lang_btn_edit">Edit</translate>
</b-button>
<b-button size="sm" variant="default"
@click.prevent="doShowBroadcasts(row.item.links.broadcasts)">
<translate key="lang_btn_broadcasts">Broadcasts</translate>
</b-button>
<b-button size="sm" variant="danger" @click.prevent="doDelete(row.item.links.self)">
<translate key="lang_btn_delete">Delete</translate>
</b-button>
</b-button-group>
</template>
</data-table>
</b-tab>
<b-tab :title="langScheduleViewTab" no-body>
<schedule ref="schedule" :schedule-url="scheduleUrl" :station-time-zone="stationTimeZone"
:locale="locale" @click="doCalendarClick"></schedule>
</b-tab>
</b-tabs>
</b-card>
</div>
<div class="col-md-4">
<connection-info :connection-info="connectionInfo"></connection-info>
</div>
<edit-modal ref="editModal" :create-url="listUrl" :station-time-zone="stationTimeZone" @relist="relist"></edit-modal>
<edit-modal ref="editModal" :create-url="listUrl" :station-time-zone="stationTimeZone"
@relist="relist"></edit-modal>
<broadcasts-modal ref="broadcastsModal"></broadcasts-modal>
</div>
</template>
@ -65,18 +72,19 @@ import BroadcastsModal from './Streamers/BroadcastsModal';
import Schedule from '~/components/Common/ScheduleView';
import Icon from '~/components/Common/Icon';
import confirmDelete from "~/functions/confirmDelete";
import ConnectionInfo from "./Streamers/ConnectionInfo";
export default {
name: 'StationStreamers',
components: {Icon, EditModal, BroadcastsModal, DataTable, Schedule},
components: {ConnectionInfo, Icon, EditModal, BroadcastsModal, DataTable, Schedule},
props: {
listUrl: String,
scheduleUrl: String,
filesUrl: String,
locale: String,
stationTimeZone: String
stationTimeZone: String,
connectionInfo: Object
},
data () {
data() {
return {
fields: [
{key: 'display_name', label: this.$gettext('Display Name'), sortable: false},

View File

@ -0,0 +1,90 @@
<template>
<div class="card">
<div class="card-header bg-primary-dark">
<h2 class="card-title">
<translate key="lang_connection_info_hdr">Connection Information</translate>
</h2>
</div>
<div class="card-body">
<h3 class="card-subtitle mt-0">
<translate key="lang_connection_icecast_hdr">Icecast Clients</translate>
</h3>
<dl>
<dt class="mb-1">
<translate key="lang_connection_info_server">Server:</translate>
</dt>
<dd>
<code>{{ connectionInfo.serverUrl }}</code>
</dd>
<dd v-if="connectionInfo.ip">
<translate
key="lang_connection_ip">You may need to connect directly via your IP address:</translate>
<code>{{ connectionInfo.ip }}</code>
</dd>
<dt class="mb-1">
<translate key="lang_connection_info_port">Port:</translate>
</dt>
<dd><code>{{ connectionInfo.streamPort }}</code></dd>
<dt class="mb-1">
<translate key="lang_connection_info_mount">Mount Name:</translate>
</dt>
<dd><code>{{ connectionInfo.djMountPoint }}</code></dd>
</dl>
</div>
<div class="card-body">
<h3 class="card-subtitle mt-0">
<translate key="lang_connection_shoutcast_hdr">SHOUTcast Clients</translate>
</h3>
<dl>
<dt class="mb-1">
<translate key="lang_connection_info_server">Server:</translate>
</dt>
<dd>
<code>{{ connectionInfo.serverUrl }}</code>
</dd>
<dd v-if="connectionInfo.ip">
<translate
key="lang_connection_ip">You may need to connect directly via your IP address:</translate>
<code>{{ connectionInfo.ip }}</code>
</dd>
<dt class="mb-1">
<translate key="lang_connection_info_port">Port:</translate>
</dt>
<dd><code>{{ connectionInfo.streamPort }}</code></dd>
<dd>
<translate key="lang_connection_info_legacy">For some clients, use port:</translate>
<code>{{ connectionInfo.streamPort + 1 }}</code>
</dd>
<dt class="mb-1">
<translate key="lang_connection_info_password">Password:</translate>
</dt>
<dd>
<code>dj_username:dj_password</code>
<translate key="lang_or">or</translate>
<code>dj_username,dj_password</code>
</dd>
</dl>
</div>
<div class="card-body">
<p class="card-text">
<translate key="lang_connection_wiki">Setup instructions for broadcasting software are available on the AzuraCast wiki.</translate>
<br>
<a href="https://docs.azuracast.com/en/user-guide/streaming-software" target="_blank">
<translate key="lang_connection_wiki_link">AzuraCast Wiki</translate>
</a>
</p>
</div>
</div>
</template>
<script>
export default {
name: 'ConnectionInfo',
props: {
connectionInfo: Object
}
}
</script>

View File

@ -29,12 +29,31 @@ class HistoryAction
$np = $npApiGenerator->currentOrEmpty($station);
$np->resolveUrls($request->getRouter()->getBaseUrl());
$customization = $request->getCustomization();
$router = $request->getRouter();
$useNChan = $customization->useWebSocketsForNowPlaying();
return $request->getView()->renderToResponse(
$response,
'frontend/public/embedhistory',
'system/vue',
[
'station' => $station,
'nowplaying' => $np,
'title' => __('History') . ' - ' . $station->getName(),
'id' => 'song-history',
'layout' => 'minimal',
'layoutParams' => [
'page_class' => 'embed station-' . $station->getShortName(),
'hide_footer' => true,
],
'component' => 'Vue_PublicHistory',
'props' => [
'initialNowPlaying' => $np,
'showAlbumArt' => !$customization->hideAlbumArt(),
'useNchan' => $useNChan,
'nowPlayingUri' => $useNChan
? '/api/live/nowplaying/' . urlencode($station->getShortName())
: (string)$router->named('api:nowplaying:index', ['station_id' => $station->getId()]),
],
]
);
}

View File

@ -49,13 +49,31 @@ class OnDemandAction
];
}
$router = $request->getRouter();
$pageClass = 'ondemand station-' . $station->getShortName();
if ($embed) {
$pageClass .= ' embed';
}
return $request->getView()->renderToResponse(
$response,
'frontend/public/ondemand',
'system/vue',
[
'embed' => $embed,
'station' => $station,
'custom_fields' => $customFields,
'title' => __('On-Demand Media') . ' - ' . $station->getName(),
'id' => 'station-on-demand',
'layout' => 'minimal',
'layoutParams' => [
'page_class' => $pageClass,
'hide_footer' => true,
],
'component' => 'Vue_PublicOnDemand',
'props' => [
'listUrl' => (string)$router->fromHere('api:stations:ondemand:list'),
'showDownloadButton' => $station->getEnableOnDemandDownload(),
'customFields' => $customFields,
'stationName' => $station->getName(),
],
]
);
}

View File

@ -26,12 +26,27 @@ class RequestsAction
throw new StationNotFoundException();
}
$router = $request->getRouter();
$customization = $request->getCustomization();
return $request->getView()->renderToResponse(
$response,
'frontend/public/embedrequests',
'system/vue',
[
'station' => $station,
'customFields' => $customFieldRepo->fetchArray(),
'title' => __('Requests') . ' - ' . $station->getName(),
'id' => 'song-requests',
'layout' => 'minimal',
'layoutParams' => [
'page_class' => 'embed station-' . $station->getShortName(),
'hide_footer' => true,
],
'component' => 'Vue_PublicRequests',
'props' => [
'customFields' => $customFieldRepo->fetchArray(),
'showAlbumArt' => !$customization->hideAlbumArt(),
'requestListUri' => (string)$router->named('api:requests:list', ['station_id' => $station->getId()]
),
],
]
);
}

View File

@ -25,13 +25,31 @@ class ScheduleAction
throw new StationNotFoundException();
}
$router = $request->getRouter();
$pageClass = 'schedule station-' . $station->getShortName();
if ($embed) {
$pageClass .= ' embed';
}
return $request->getView()->renderToResponse(
$response,
'frontend/public/schedule',
'system/vue',
[
'embed' => $embed,
'station' => $station,
'station_tz' => $station->getTimezone(),
'title' => __('Schedule') . ' - ' . $station->getName(),
'id' => 'station-schedule',
'layout' => 'minimal',
'layoutParams' => [
'page_class' => $pageClass,
'hide_footer' => true,
],
'component' => 'Vue_PublicSchedule',
'props' => [
'scheduleUrl' => (string)$router->named('api:stations:schedule', ['station_id' => $station->getId()]
),
'stationName' => $station->getName(),
'stationTimeZone' => $station->getTimezone(),
],
]
);
}

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Controller\Frontend\PublicPages;
use App\Assets;
use App\Exception\StationNotFoundException;
use App\Exception\StationUnsupportedException;
use App\Http\Response;
@ -16,6 +17,7 @@ class WebDjAction
public function __invoke(
ServerRequest $request,
Response $response,
Assets $assets
): ResponseInterface {
// Override system-wide iframe refusal
$response = $response->withHeader('X-Frame-Options', '*');
@ -36,12 +38,36 @@ class WebDjAction
throw new StationUnsupportedException();
}
$router = $request->getRouter();
$wss_url = (string)$backend->getWebStreamingUrl($station, $request->getRouter()->getBaseUrl());
$wss_url = str_replace('wss://', '', $wss_url);
return $request->getView()->renderToResponse($response, 'frontend/public/dj', [
'station' => $station,
'base_uri' => $wss_url,
]);
$libUrls = [];
$lib = $assets->getLibrary('Vue_PublicWebDJ');
foreach (array_slice($lib['files']['js'], 0, -1) as $script) {
$libUrls[] = (string)($router->getBaseUrl()->withPath($assets->getUrl($script['src'])));
}
return $request->getView()->renderToResponse(
$response,
'system/vue',
[
'title' => __('Web DJ') . ' - ' . $station->getName(),
'id' => 'web_dj',
'layout' => 'minimal',
'layoutParams' => [
'page_class' => 'dj station-' . $station->getShortName(),
'hide_footer' => true,
],
'component' => 'Vue_PublicWebDJ',
'props' => [
'stationName' => $station->getName(),
'libUrls' => $libUrls,
'baseUri' => $wss_url,
],
]
);
}
}

View File

@ -26,7 +26,6 @@ class PlaylistsAction
$settings = $settingsRepo->readSettings();
$router = $request->getRouter();
$customization = $request->getCustomization();
return $request->getView()->renderToResponse(
$response,
@ -38,7 +37,6 @@ class PlaylistsAction
'props' => [
'listUrl' => (string)$router->fromHere('api:stations:playlists'),
'scheduleUrl' => (string)$router->fromHere('api:stations:playlists:schedule'),
'locale' => substr($customization->getLocale()->getLocale(), 0, 2),
'filesUrl' => (string)$router->fromHere('stations:files:index'),
'stationTimeZone' => $station->getTimezone(),
'enableAdvancedFeatures' => $settings->getEnableAdvancedFeatures(),

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Controller\Stations;
use App\Acl;
use App\Entity;
use App\Form\StationForm;
use App\Http\Response;
@ -54,18 +55,157 @@ class ProfileController
)->setParameter('station_id', $station->getId())
->getSingleScalarResult();
$view->addData([
'num_songs' => (int)$num_songs,
'num_playlists' => (int)$num_playlists,
'backend_type' => $station->getBackendType(),
'backend_config' => $station->getBackendConfig(),
'frontend_type' => $station->getFrontendType(),
'frontend_config' => $station->getFrontendConfig(),
'user' => $request->getUser(),
'csrf' => $request->getCsrf()->generate($this->csrf_namespace),
]);
$csrf = $request->getCsrf()->generate($this->csrf_namespace);
return $view->renderToResponse($response, 'stations/profile/index');
$backend = $request->getStationBackend();
$frontend = $request->getStationFrontend();
$backendConfig = $station->getBackendConfig();
$frontendConfig = $station->getFrontendConfig();
$acl = $request->getAcl();
$router = $request->getRouter();
return $request->getView()->renderToResponse(
$response,
'system/vue',
[
'title' => __('Profile'),
'id' => 'profile',
'component' => 'Vue_StationsProfile',
'props' => [
// Common
'backendType' => $station->getBackendType(),
'frontendType' => $station->getFrontendType(),
'stationTimeZone' => $station->getTimezone(),
'stationSupportsRequests' => $backend->supportsRequests(),
'stationSupportsStreamers' => $backend->supportsStreamers(),
'enableRequests' => $station->getEnableRequests(),
'enableStreamers' => $station->getEnableStreamers(),
'enablePublicPage' => $station->getEnablePublicPage(),
'enableOnDemand' => $station->getEnableOnDemand(),
'profileApiUri' => (string)$router->fromHere('api:stations:profile'),
// ACL
'userCanManageMedia' => $acl->isAllowed(Acl::STATION_MEDIA, $station->getId()),
'userCanManageBroadcasting' => $acl->isAllowed(Acl::STATION_BROADCASTING, $station->getId()),
'userCanManageProfile' => $acl->isAllowed(Acl::STATION_PROFILE, $station->getId()),
'userCanManageReports' => $acl->isAllowed(Acl::STATION_REPORTS, $station->getId()),
'userCanManageStreamers' => $acl->isAllowed(Acl::STATION_STREAMERS, $station->getId()),
// Header
'stationName' => $station->getName(),
'stationDescription' => $station->getDescription(),
'manageProfileUri' => (string)$router->fromHere('stations:profile:edit'),
// Now Playing
'backendSkipSongUri' => (string)$router->fromHere('api:stations:backend', ['do' => 'skip']),
'backendDisconnectStreamerUri' => (string)$router->fromHere(
'api:stations:backend',
['do' => 'disconnect']
),
// Requests
'requestsViewUri' => (string)$router->fromHere('stations:reports:requests'),
'requestsToggleUri' => (string)$router->fromHere(
'stations:profile:toggle',
['feature' => 'requests', 'csrf' => $csrf]
),
// Streamers
'streamersViewUri' => (string)$router->fromHere('stations:streamers:index'),
'streamersToggleUri' => (string)$router->fromHere(
'stations:profile:toggle',
['feature' => 'streamers', 'csrf' => $csrf]
),
// Public Pages
'publicPageUri' => (string)$router->named(
'public:index',
['station_id' => $station->getShortName()],
[],
true
),
'publicPageEmbedUri' => (string)$router->named(
'public:index',
['station_id' => $station->getShortName(), 'embed' => 'embed'],
[],
true
),
'publicWebDjUri' => (string)$router->named(
'public:dj',
['station_id' => $station->getShortName()],
[],
true
),
'publicOnDemandUri' => (string)$router->named(
'public:ondemand',
['station_id' => $station->getShortName()],
[],
true
),
'publicPodcastsUri' => (string)$router->named(
'public:podcasts',
['station_id' => $station->getShortName()],
[],
true
),
'publicScheduleUri' => (string)$router->named(
'public:schedule',
['station_id' => $station->getShortName()],
[],
true
),
'publicOnDemandEmbedUri' => (string)$router->named(
'public:ondemand',
['station_id' => $station->getShortName(), 'embed' => 'embed'],
[],
true
),
'publicRequestEmbedUri' => (string)$router->named(
'public:embedrequests',
['station_id' => $station->getShortName()],
[],
true
),
'publicHistoryEmbedUri' => (string)$router->named(
'public:history',
['station_id' => $station->getShortName()],
[],
true
),
'publicScheduleEmbedUri' => (string)$router->named(
'public:schedule',
['station_id' => $station->getShortName(), 'embed' => 'embed'],
[],
true
),
'togglePublicPageUri' => (string)$router->fromHere(
'stations:profile:toggle',
['feature' => 'public', 'csrf' => $csrf]
),
// Frontend
'frontendAdminUri' => (string)$frontend->getAdminUrl($station, $router->getBaseUrl()),
'frontendAdminPassword' => $frontendConfig->getAdminPassword(),
'frontendSourcePassword' => $frontendConfig->getSourcePassword(),
'frontendRelayPassword' => $frontendConfig->getRelayPassword(),
'frontendRestartUri' => (string)$router->fromHere('api:stations:frontend', ['do' => 'restart']),
'frontendStartUri' => (string)$router->fromHere('api:stations:frontend', ['do' => 'start']),
'frontendStopUri' => (string)$router->fromHere('api:stations:frontend', ['do' => 'stop']),
// Backend
'numSongs' => (int)$num_songs,
'numPlaylists' => (int)$num_playlists,
'manageMediaUri' => (string)$router->fromHere('stations:files:index'),
'managePlaylistsUri' => (string)$router->fromHere('stations:playlists:index'),
'backendRestartUri' => (string)$router->fromHere('api:stations:backend', ['do' => 'restart']),
'backendStartUri' => (string)$router->fromHere('api:stations:backend', ['do' => 'start']),
'backendStopUri' => (string)$router->fromHere('api:stations:backend', ['do' => 'stop']),
],
]
);
}
public function editAction(ServerRequest $request, Response $response): ResponseInterface

View File

@ -50,17 +50,28 @@ class StreamersAction
}
$settings = $settingsRepo->readSettings();
$be_settings = $station->getBackendConfig();
$backendConfig = $station->getBackendConfig();
return $view->renderToResponse(
$router = $request->getRouter();
return $request->getView()->renderToResponse(
$response,
'stations/streamers/index',
'system/vue',
[
'server_url' => $settings->getBaseUrl(),
'stream_port' => $backend->getStreamPort($station),
'ip' => $acCentral->getIp(),
'dj_mount_point' => $be_settings['dj_mount_point'] ?? '/',
'station_tz' => $station->getTimezone(),
'title' => __('Streamer/DJ Accounts'),
'id' => 'station-streamers',
'component' => 'Vue_StationsStreamers',
'props' => [
'listUrl' => (string)$router->fromHere('api:stations:streamers'),
'scheduleUrl' => (string)$router->fromHere('api:stations:streamers:schedule'),
'stationTimeZone' => $station->getTimezone(),
'connectionInfo' => [
'serverUrl' => $settings->getBaseUrl(),
'streamPort' => $backend->getStreamPort($station),
'ip' => $acCentral->getIp(),
'djMountPoint' => $backendConfig->getDjMountPoint(),
],
],
]
);
}

View File

@ -1,35 +0,0 @@
<?php
$this->layout(
'minimal',
[
'page_class' => 'dj station-' . $station->getShortName(),
'title' => 'Web DJ - ' . $this->e($station->getName()),
'hide_footer' => true,
]
);
/** @var \App\Assets $assets */
$libUrls = [];
$lib = $assets->getLibrary('Vue_PublicWebDJ');
$scripts = array_slice($lib['files']['js'], 0, -1);
foreach ($scripts as $script) {
$libUrls[] = $router->getBaseUrl() . $assets->getUrl($script['src']);
}
$props = [
'stationName' => $station->getName(),
'libUrls' => $libUrls,
'baseUri' => $base_uri,
];
$assets->addVueRender('Vue_PublicWebDJ', '#web_dj', $props);
?>
<section id="content" role="main" style="height: 100vh;">
<div class="container pt-5">
<div id="web_dj"></div>
</div>
</section>

View File

@ -1,31 +0,0 @@
<?php
/** @var App\Entity\Station $station */
$this->layout(
'minimal',
[
'page_class' => 'embed station-' . $station->getShortName(),
'title' => $this->e($station->getName()),
'hide_footer' => true,
]
);
$props = [
'initialNowPlaying' => $nowplaying,
'showAlbumArt' => !$customization->hideAlbumArt(),
];
if ($customization->useWebSocketsForNowPlaying()) {
$props['useNchan'] = true;
$props['nowPlayingUri'] = '/api/live/nowplaying/' . urlencode($station->getShortName());
} else {
$props['useNchan'] = false;
$props['nowPlayingUri'] = (string)$router->named('api:nowplaying:index', ['station_id' => $station->getId()]);
}
/** @var \App\Assets $assets */
$assets
->addVueRender('Vue_PublicHistory', '#song-history', $props);
?>
<div id="song-history"></div>

View File

@ -1,23 +0,0 @@
<?php
/** @var App\Entity\Station $station */
$this->layout(
'minimal',
[
'page_class' => 'embed station-' . $station->getShortName(),
'title' => $this->e($station->getName()),
'hide_footer' => true,
]
);
$props = [
'customFields' => $customFields,
'showAlbumArt' => !$customization->hideAlbumArt(),
'requestListUri' => (string)$router->named('api:requests:list', ['station_id' => $station->getId()]),
];
/** @var \App\Assets $assets */
$assets->addVueRender('Vue_PublicRequests', '#song-requests', $props);
?>
<div id="song-requests"></div>

View File

@ -1,31 +0,0 @@
<?php
$pageClass = 'ondemand station-' . $station->getShortName();
if ($embed) {
$pageClass .= ' embed';
}
$this->layout(
'minimal',
[
'page_class' => $pageClass,
'title' => 'On-Demand Media - ' . $this->e($station->getName()),
'hide_footer' => true,
]
);
$props = [
'listUrl' => (string)$router->fromHere('api:stations:ondemand:list'),
'showDownloadButton' => $station->getEnableOnDemandDownload(),
'customFields' => $custom_fields,
'stationName' => $station->getName(),
];
/** @var \App\Assets $assets */
$assets->addVueRender('Vue_PublicOnDemand', '#station_on_demand', $props);
?>
<section id="content" role="main" class="d-flex align-items-stretch" style="height: 100vh;">
<div class="container pt-5 pb-5 h-100" style="flex: 1;">
<div id="station_on_demand"></div>
</div>
</section>

View File

@ -1,33 +0,0 @@
<?php
/** @var App\Entity\Station $station */
$pageClass = 'schedule station-' . $station->getShortName();
if ($embed) {
$pageClass .= ' embed';
}
$this->layout(
'minimal',
[
'page_class' => $pageClass,
'title' => __('Schedule') . ' - ' . $this->e($station->getName()),
'hide_footer' => true,
]
);
$props = [
'scheduleUrl' => (string)$router->named('api:stations:schedule', ['station_id' => $station->getId()]),
'stationName' => $station->getName(),
'locale' => substr($customization->getLocale()->getLocale(), 0, 2),
'stationTimeZone' => $station_tz,
];
/** @var \App\Assets $assets */
$assets->addVueRender('Vue_PublicSchedule', '#station-schedule', $props);
?>
<section id="content" role="main" class="d-flex align-items-stretch" style="height: 100vh;">
<div class="container pt-5 pb-5 h-100" style="flex: 1;">
<div id="station-schedule"></div>
</div>
</section>

View File

@ -1,142 +0,0 @@
<?php
/**
* @var App\Entity\Station $station
* @var App\Assets $assets
* @var App\Http\RouterInterface $router
*/
$this->layout(
'main',
[
'title' => __('Profile'),
'manual' => true,
'sidebar_tab' => 'profile',
]
);
$frontendConfig = $station->getFrontendConfig();
$props = [
// Common
'backendType' => $station->getBackendType(),
'frontendType' => $station->getFrontendType(),
'stationTimeZone' => $station->getTimezone(),
'stationSupportsRequests' => $backend->supportsRequests(),
'stationSupportsStreamers' => $backend->supportsStreamers(),
'enableRequests' => $station->getEnableRequests(),
'enableStreamers' => $station->getEnableStreamers(),
'enablePublicPage' => $station->getEnablePublicPage(),
'enableOnDemand' => $station->getEnableOnDemand(),
'profileApiUri' => (string)$router->fromHere('api:stations:profile'),
// ACL
'userCanManageMedia' => $acl->isAllowed(App\Acl::STATION_MEDIA, $station->getId()),
'userCanManageBroadcasting' => $acl->isAllowed(App\Acl::STATION_BROADCASTING, $station->getId()),
'userCanManageProfile' => $acl->isAllowed(App\Acl::STATION_PROFILE, $station->getId()),
'userCanManageReports' => $acl->isAllowed(App\Acl::STATION_REPORTS, $station->getId()),
'userCanManageStreamers' => $acl->isAllowed(App\Acl::STATION_STREAMERS, $station->getId()),
// Header
'stationName' => $station->getName(),
'stationDescription' => $station->getDescription(),
'manageProfileUri' => (string)$router->fromHere('stations:profile:edit'),
// Now Playing
'backendSkipSongUri' => (string)$router->fromHere('api:stations:backend', ['do' => 'skip']),
'backendDisconnectStreamerUri' => (string)$router->fromHere('api:stations:backend', ['do' => 'disconnect']),
// Requests
'requestsViewUri' => (string)$router->fromHere('stations:reports:requests'),
'requestsToggleUri' => (string)$router->fromHere(
'stations:profile:toggle',
['feature' => 'requests', 'csrf' => $csrf]
),
// Streamers
'streamersViewUri' => (string)$router->fromHere('stations:streamers:index'),
'streamersToggleUri' => (string)$router->fromHere(
'stations:profile:toggle',
['feature' => 'streamers', 'csrf' => $csrf]
),
// Public Pages
'publicPageUri' => (string)$router->named('public:index', ['station_id' => $station->getShortName()], [], true),
'publicPageEmbedUri' => (string)$router->named(
'public:index',
['station_id' => $station->getShortName(), 'embed' => 'embed'],
[],
true
),
'publicWebDjUri' => (string)$router->named('public:dj', ['station_id' => $station->getShortName()], [], true),
'publicOnDemandUri' => (string)$router->named(
'public:ondemand',
['station_id' => $station->getShortName()],
[],
true
),
'publicPodcastsUri' => (string)$router->named(
'public:podcasts',
['station_id' => $station->getShortName()],
[],
true
),
'publicScheduleUri' => (string)$router->named(
'public:schedule',
['station_id' => $station->getShortName()],
[],
true
),
'publicOnDemandEmbedUri' => (string)$router->named(
'public:ondemand',
['station_id' => $station->getShortName(), 'embed' => 'embed'],
[],
true
),
'publicRequestEmbedUri' => (string)$router->named(
'public:embedrequests',
['station_id' => $station->getShortName()],
[],
true
),
'publicHistoryEmbedUri' => (string)$router->named(
'public:history',
['station_id' => $station->getShortName()],
[],
true
),
'publicScheduleEmbedUri' => (string)$router->named(
'public:schedule',
['station_id' => $station->getShortName(), 'embed' => 'embed'],
[],
true
),
'togglePublicPageUri' => (string)$router->fromHere(
'stations:profile:toggle',
['feature' => 'public', 'csrf' => $csrf]
),
// Frontend
'frontendAdminUri' => (string)$frontend->getAdminUrl($station, $router->getBaseUrl()),
'frontendAdminPassword' => $frontendConfig->getAdminPassword(),
'frontendSourcePassword' => $frontendConfig->getSourcePassword(),
'frontendRelayPassword' => $frontendConfig->getRelayPassword(),
'frontendRestartUri' => (string)$router->fromHere('api:stations:frontend', ['do' => 'restart']),
'frontendStartUri' => (string)$router->fromHere('api:stations:frontend', ['do' => 'start']),
'frontendStopUri' => (string)$router->fromHere('api:stations:frontend', ['do' => 'stop']),
// Backend
'numSongs' => (int)$num_songs,
'numPlaylists' => (int)$num_playlists,
'manageMediaUri' => (string)$router->fromHere('stations:files:index'),
'managePlaylistsUri' => (string)$router->fromHere('stations:playlists:index'),
'backendRestartUri' => (string)$router->fromHere('api:stations:backend', ['do' => 'restart']),
'backendStartUri' => (string)$router->fromHere('api:stations:backend', ['do' => 'start']),
'backendStopUri' => (string)$router->fromHere('api:stations:backend', ['do' => 'stop']),
];
$assets
->addVueRender('Vue_StationsProfile', '#profile', $props);
?>
<div id="profile"></div>

View File

@ -1,81 +0,0 @@
<?php
$this->layout('main', ['title' => __('Streamer/DJ Accounts'), 'manual' => true]);
/** @var App\Http\RouterInterface $router */
$props = [
'listUrl' => (string)$router->fromHere('api:stations:streamers'),
'scheduleUrl' => (string)$router->fromHere('api:stations:streamers:schedule'),
'locale' => substr($customization->getLocale(), 0, 2),
'stationTimeZone' => $station_tz,
];
/** @var App\Assets $assets */
$assets->addVueRender('Vue_StationsStreamers', '#station-streamers', $props);
?>
<div class="row">
<div class="col-md-8">
<div id="station-streamers"></div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header bg-primary-dark">
<h2 class="card-title"><?=__('Connection Information')?></h2>
</div>
<div class="card-body">
<h3 class="card-title"><?=__('IceCast Clients')?></h3>
<dl>
<dt class="mb-1"><?=__('Server')?>:</dt>
<dd><code><?=$this->e($server_url)?></code></dd>
<?php
if ($ip): ?>
<dd><?=__(
'You may need to connect directly via your IP address, which is <code>%s</code>.',
$ip
)?></dd>
<?php
endif; ?>
<dt class="mb-1"><?=__('Port')?>:</dt>
<dd><code><?=(int)$stream_port?></code></dd>
<dt class="mb-1"><?=__('Mount Name')?>:</dt>
<dd><code><?=$this->e($dj_mount_point)?></code></dd>
</dl>
<h3 class="card-title mt-3"><?=__('ShoutCast v1 Clients')?></h3>
<dl>
<dt class="mb-1"><?=__('Server')?>:</dt>
<dd><code><?=$this->e($server_url)?></code></dd>
<?php
if ($ip): ?>
<dd><?=__(
'You may need to connect directly via your IP address, which is <code>%s</code>.',
$ip
)?></dd>
<?php
endif; ?>
<dt class="mb-1"><?=__('Port')?>:</dt>
<dd><code><?=__('%d (%d for some clients)', (int)$stream_port, ((int)$stream_port + 1))?></code>
</dd>
<dt class="mb-1"><?=__('Password')?>:</dt>
<dd>
<code>dj_username:dj_password</code> <?=__('or')?>
<code>dj_username,dj_password</code><br/>
<small><?=__('(DJ username and password separated by a colon or comma)')?></small>
</dd>
</dl>
<p><?=sprintf(
__(
'Setup instructions for broadcasting software are available <a href="%s" target="_blank">on the AzuraCast Wiki</a>.'
),
'https://docs.azuracast.com/en/user-guide/streaming-software'
)?></p>
</div>
</div>
</div>
</div>

View File

@ -11,10 +11,13 @@
$this->layout(
$layout ?? 'main',
[
'title' => $title,
'manual' => true,
]
array_merge(
[
'title' => $title,
'manual' => true,
],
$layoutParams ?? []
)
);
$id ??= $component;