diff --git a/app/controllers/venue.js b/app/controllers/venue.js index 4648832..9c11ac5 100644 --- a/app/controllers/venue.js +++ b/app/controllers/venue.js @@ -18,6 +18,9 @@ class VenueController extends SiteController { const welcomeLimiter = limiterService.createMiddleware(limiterService.config.welcome); const router = express.Router(); + + router.use(this.dtp.services.venue.channelMiddleware()); + this.dtp.app.use('/venue', welcomeLimiter, async (req, res, next) => { res.locals.currentView = 'venue'; return next(); diff --git a/app/services/venue.js b/app/services/venue.js index 66bc3ba..681402c 100644 --- a/app/services/venue.js +++ b/app/services/venue.js @@ -23,6 +23,8 @@ class VenueService extends SiteService { return next(); } res.locals.shingChannelFeed = await this.getChannelFeed(res.locals.site.shingChannelSlug, { allowCache: true }); + res.locals.shingChannelStatus = await this.getChannelStatus(res.locals.site.shingChannelSlug, { allowCache: true }); + this.log.debug('channel status', { status: res.locals.shingChannelStatus }); return next(); } catch (error) { this.log.error('failed to populate Shing.tv channel feed', { error }); @@ -34,29 +36,50 @@ class VenueService extends SiteService { async getChannelFeed (channelSlug, options) { const { cache: cacheService } = this.dtp.services; const cacheKey = `venue:ch:${channelSlug}`; - - options = Object.assign({ - allowCache: true, - }, options); + options = Object.assign({ allowCache: true }, options); let json; if (options.allowCache) { json = await cacheService.getObject(cacheKey); - if (json) { - return json; - } + if (json) { return json; } } + this.log.info('fetching Shing channel feed', { channelSlug }); const response = await fetch(`https://shing.tv/channel/${channelSlug}/feed/json`); if (!response.ok) { throw new SiteError(500, 'Failed to fetch Shing channel feed'); } - json = await response.json(); + json = await response.json(); await cacheService.setObjectEx(cacheKey, CACHE_DURATION, json); return json; } + + async getChannelStatus (channelSlug, options) { + const { cache: cacheService } = this.dtp.services; + const cacheKey = `venue:ch:${channelSlug}:status`; + options = Object.assign({ allowCache: true }, options); + + let json; + if (options.allowCache) { + json = await cacheService.getObject(cacheKey); + if (json) { return json; } + } + + this.log.info('fetching Shing channel status', { channelSlug }); + const response = await fetch(`https://shing.tv/channel/${channelSlug}/status`); + if (!response.ok) { + throw new SiteError(500, 'Failed to fetch Shing channel status'); + } + + json = await response.json(); + + const { channel } = json; + await cacheService.setObjectEx(cacheKey, 10, channel); + + return channel; + } } module.exports = { diff --git a/app/views/components/navbar.pug b/app/views/components/navbar.pug index ca5e25d..8f8bba1 100644 --- a/app/views/components/navbar.pug +++ b/app/views/components/navbar.pug @@ -1,5 +1,7 @@ include ../user/components/profile-icon +- var isLive = shingChannelStatus && shingChannelStatus.isLive; + nav(uk-navbar).uk-navbar-container.uk-position-fixed.uk-position-top .uk-navbar-left .uk-navbar-item @@ -25,9 +27,12 @@ nav(uk-navbar).uk-navbar-container.uk-position-fixed.uk-position-top if site.shingWidgetKey && site.shingChannelSlug li(class={ 'uk-active': currentView === 'venue' }) a(href="/venue", title= "Live") - span - i.fas.fa-tv - span(class="uk-visible@m").uk-margin-small-left Live + if isLive + span 🔴 + else + span + i.fas.fa-tv + span(class="uk-visible@m").uk-margin-small-left= isLive ? 'Live Now' : 'Live' each menuItem in mainMenu li(class={ 'uk-active': (pageSlug === menuItem.slug) }) diff --git a/app/views/components/page-sidebar.pug b/app/views/components/page-sidebar.pug index d0916c8..04c0a3a 100644 --- a/app/views/components/page-sidebar.pug +++ b/app/views/components/page-sidebar.pug @@ -1,5 +1,7 @@ include ../announcement/components/announcement +- var isLive = !!shingChannelStatus && shingChannelStatus.isLive && !!shingChannelStatus.liveEpisode; + mixin renderSidebarEpisode(episode) .uk-card.uk-card-default.uk-card-small.uk-card-hover @@ -25,6 +27,33 @@ mixin renderPageSidebar ( ) //- //- Shing.tv Channel Integration //- + if isLive + .uk-margin + +renderSectionTitle('Live Now!', { + label: 'Tune In', + title: shingChannelStatus.name, + url: '/venue', + }) + + .uk-card.uk-card-default.uk-card-small.uk-card-hover.uk-margin + if shingChannelStatus.liveThumbnail + .uk-card-media-top + a(href="/venue") + img( + src= shingChannelStatus.liveThumbnail.url, + onerror=`this.src = '${shingChannelStatus.thumbnailUrl}';`, + title="Tune in now", + ) + if shingChannelStatus.liveEpisode && shingChannelStatus.liveEpisode.title + .uk-card-body + .uk-card-title.uk-margin-remove.uk-text-truncate + a(href="/venue", uk-tooltip= `Watch "${shingChannelStatus.liveEpisode.title}" now!`)= shingChannelStatus.liveEpisode.title + .uk-text-small + div(uk-grid).uk-grid-small.uk-flex-between + .uk-width-auto + div Started: #{moment(shingChannelStatus.liveEpisode.created).fromNow()} + .uk-width-auto #[i.fas.fa-eye] #{formatCount(shingChannelStatus.liveEpisode.stats.currentViewerCount)} + if shingChannelFeed && Array.isArray(shingChannelFeed.items) && (shingChannelFeed.items.length > 0) .uk-margin +renderSectionTitle(shingChannelFeed.title, {