diff --git a/dashboard-ui/bower_components/emby-webcomponents/.bower.json b/dashboard-ui/bower_components/emby-webcomponents/.bower.json index 270b73a86f..6ca547c633 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/.bower.json +++ b/dashboard-ui/bower_components/emby-webcomponents/.bower.json @@ -16,12 +16,12 @@ }, "devDependencies": {}, "ignore": [], - "version": "1.2.39", - "_release": "1.2.39", + "version": "1.2.45", + "_release": "1.2.45", "_resolution": { "type": "version", - "tag": "1.2.39", - "commit": "956d151bb5506eea13c56b69f21220b55d2b7d35" + "tag": "1.2.45", + "commit": "9c7b62bb1c95ce96c86da19d7d961eda9042acf7" }, "_source": "https://github.com/MediaBrowser/emby-webcomponents.git", "_target": "^1.2.0", diff --git a/dashboard-ui/bower_components/emby-webcomponents/clearbutton.css b/dashboard-ui/bower_components/emby-webcomponents/clearbutton.css new file mode 100644 index 0000000000..2d3f8d6800 --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/clearbutton.css @@ -0,0 +1,12 @@ +.clearButton { + background: transparent; + border: 0 !important; + padding: 0 !important; + cursor: pointer; + outline: none !important; + color: inherit; + width: 100%; + vertical-align: middle; + font-family: inherit; + font-size: inherit; +} \ No newline at end of file diff --git a/dashboard-ui/bower_components/emby-webcomponents/guide/guide.css b/dashboard-ui/bower_components/emby-webcomponents/guide/guide.css new file mode 100644 index 0000000000..8026047144 --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/guide/guide.css @@ -0,0 +1,382 @@ +.tvguide { + display: flex; + flex-direction: column; + align-items: initial; +} + +.tvGuideHeader { + white-space: nowrap; + width: 100%; + flex-shrink: 0; +} + + .tvGuideHeader.headroom--unpinned { + -webkit-transform: translateY(-98px); + transform: translateY(-98px); + } + +.tvProgramSectionHeader { + margin: 0; +} + +.tvProgram { + display: block; + text-decoration: none; + white-space: nowrap; + position: relative; +} + +.tvProgramTimeSlotInner { + padding: .5em; +} + +.tvProgramInfo { + vertical-align: middle; + padding: .5em .5em; + border-bottom: .65vh solid #121212; +} + +.tvProgramCurrentTimeSlot { + background-color: green; +} + +.tvProgramName { + color: #fff; + margin-bottom: .5em; +} + +.tvProgramTime { + color: #fff; +} + +.newTvProgram { + color: yellow; + text-transform: uppercase; +} + +.liveTvProgram { + color: #64A239; + text-transform: uppercase; +} + +.premiereTvProgram { + color: orange; + text-transform: uppercase; +} + +.programAccent { + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 2px; +} + +.sportsProgramInfo .programAccent { + background-color: #0A7C33; +} + +.newsProgramInfo .programAccent { + background-color: #523378; +} + +.movieProgramInfo .programAccent { + background-color: #A43913; +} + +.childProgramInfo .programAccent { + background-color: #0B487D; +} + +.timerCircle { + display: inline-block; + width: 1em; + height: 1em; + border-radius: 50%; + background: #cc0000; + border: 1px solid #cc3333; + margin-left: 1em; +} + +.seriesTimerCircle { + position: relative; + margin-left: 0; + left: 21px; + opacity: .3; +} + +.itemMiscInfo .seriesTimerCircle:first-child { + margin-left: 1em; +} + +.seriesTimerCircle + .seriesTimerCircle { + opacity: .65; + left: 0; +} + + .seriesTimerCircle + .seriesTimerCircle + .seriesTimerCircle { + opacity: 1; + left: -21px; + } + +.channelTimeslotHeader { + float: left; +} + +.timeslotHeaders { + white-space: nowrap; +} + +.mobileGuide .timeslotHeaders { + overflow-x: hidden; +} + +.programContainer { + white-space: nowrap; + position: relative; +} + +.programGridContainer { + margin-left: 12.2vw; +} + +.channelPrograms { + white-space: nowrap; + position: relative; +} + +.channelPrograms, .timeslotHeadersInner { + width: 1800vw; +} + +@media all and (min-width: 600px) { + + .channelPrograms, .timeslotHeadersInner { + width: 1400vw; + } +} + +@media all and (min-width: 800px) { + + .channelPrograms, .timeslotHeadersInner { + width: 1200vw; + } +} + +@media all and (min-width: 1280px) { + + .channelPrograms, .timeslotHeadersInner { + width: 660vw; + } +} + +.timeslotHeader { + display: inline-flex; + align-items: center; + text-indent: .35em; +} + +.channelHeaderCell, .channelTimeslotHeader { + overflow: hidden; + text-overflow: ellipsis; + border-right: 1px solid #121212; + width: 24vw; + background: rgba(40, 40, 40, .9); + display: flex; + align-items: center; + color: #fff !important; + text-decoration: none; +} + +@media all and (min-width: 500px) { + + .channelHeaderCell, .channelTimeslotHeader { + width: 16vw; + } +} + +@media all and (min-width: 600px) { + + .channelHeaderCell, .channelTimeslotHeader { + width: 16vw; + } +} + +@media all and (min-width: 800px) { + + .channelHeaderCell, .channelTimeslotHeader { + width: 14vw; + } +} + +@media all and (min-width: 1280px) { + + .channelHeaderCell, .channelTimeslotHeader { + width: 12vw; + } +} + +.btnSelectDate { + color: #fff; + padding-left: .5em; +} + +.channelHeaderCell { + border-bottom: .65vh solid #121212 !important; + background-size: auto 65.7%; + background-position: 90% center; + background-repeat: no-repeat; +} + +@media all and (max-width: 800px) { + + .guideCurrentDay { + display: none; + } +} + +@media all and (max-width: 1280px) { + + .guideChannelInfoWithImage .guideChannelName { + display: none; + } +} + +.channelPrograms, .channelHeaderCell { + height: 15vh; +} + +@media all and (min-height: 500px) { + + .channelPrograms, .channelHeaderCell { + height: 10.5vh; + } +} + +@media all and (min-height: 600px) { + + .channelPrograms, .channelHeaderCell { + height: 9vh; + } +} + +@media all and (min-height: 720px) { + + .channelPrograms, .channelHeaderCell { + height: 6vh; + } + + .layout-tv .channelPrograms, .layout-tv .channelHeaderCell { + height: 7.6vh; + } +} + +.channelTimeslotHeader { + border-right-color: transparent; +} + +.channelTimeslotHeader, .timeslotHeader { + background: transparent; +} + +.timeslotHeader, .channelTimeslotHeader { + height: 5.75vh; +} + +.pointerInput .channelHeaderCell:hover { + background-color: #444; +} + +.channelList { + float: left; +} + +.programGrid { + padding-bottom: 4px; +} + +.timeslotHeader { + width: 2.0833333333333333333333333333333%; +} + +.programCell { + position: absolute; + top: 0; + /* Unfortunately the borders using vh get rounded while the bottom property doesn't. So this is a little hack to try and make them even*/ + bottom: .59vh; + border-left: .65vh solid #121212 !important; + background-color: rgba(32, 32, 32, .95); + display: flex; + color: #fff !important; + text-decoration: none; + overflow: hidden; + align-items: center; +} + +.timeslotCellInner { + position: absolute; + bottom: 0; + overflow: hidden; + width: 100%; + top: 0; + display: block; + text-decoration: none; + color: #fff !important; +} + +.guideProgramName { + padding: 0 .5em 0; + overflow: hidden; + text-overflow: ellipsis; +} + +.guideProgramTime { + padding: 0 .5em .35em; + color: #bbb; +} + +.programCell iron-icon { + margin-left: auto; + margin-right: .5em; + height: 3.5vh; + width: 3.5vh; + color: #ddd; + flex-shrink: 0; +} + + .programCell iron-icon + iron-icon { + margin-left: .25em; + } + +.guideChannelInfo { + display: inline-block; + max-width: 110px; + overflow: hidden; + white-space: nowrap; + padding-left: .7em; +} + +.guideChannelName { + margin-left: auto; + margin-right: .3em; + max-width: 6vw; + text-overflow: ellipsis; + overflow: hidden; +} + +.channelList, .programGrid { + height: auto !important; +} + +.programCell:focus, .channelHeaderCell:focus, .btnSelectDate:focus { + background-color: #52B54B; + outline: none !important; +} + + .programCell:focus .programAccent { + background-color: transparent !important; + } + +.timerIcon, .seriesTimerIcon { + color: #cc3333 !important; +} diff --git a/dashboard-ui/bower_components/emby-webcomponents/guide/guide.js b/dashboard-ui/bower_components/emby-webcomponents/guide/guide.js new file mode 100644 index 0000000000..a591c808bd --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/guide/guide.js @@ -0,0 +1,633 @@ +define(['globalize', 'connectionManager', 'loading', 'scrollHelper', 'datetime', 'focusManager', 'imageLoader', 'events', 'layoutManager', 'itemShortcuts', 'registrationservices', 'clearButtonStyle', 'css!./guide.css', 'scrollStyles'], function (globalize, connectionManager, loading, scrollHelper, datetime, focusManager, imageLoader, events, layoutManager, itemShortcuts, registrationServices) { + + var baseUrl; + + function Guide(options) { + + var self = this; + var items = {}; + + self.refresh = function () { + reloadPage(options.element); + }; + + self.destroy = function () { + itemShortcuts.off(options.element); + items = {}; + }; + + // 30 mins + var cellCurationMinutes = 30; + var cellDurationMs = cellCurationMinutes * 60 * 1000; + var msPerDay = 86400000; + + var currentDate; + + var channelQuery = { + + StartIndex: 0, + EnableFavoriteSorting: true + }; + + var channelsPromise; + + function normalizeDateToTimeslot(date) { + + var minutesOffset = date.getMinutes() - cellCurationMinutes; + + if (minutesOffset >= 0) { + + date.setHours(date.getHours(), cellCurationMinutes, 0, 0); + + } else { + + date.setHours(date.getHours(), 0, 0, 0); + } + + return date; + } + + function showLoading() { + loading.show(); + } + + function hideLoading() { + loading.hide(); + } + + function getChannelLimit(context) { + + return registrationServices.validateFeature('livetv').then(function () { + + var limit = 400; + + context.querySelector('.guideRequiresUnlock').classList.add('hide'); + + return limit; + + }, function () { + + var limit = 5; + + context.querySelector('.guideRequiresUnlock').classList.remove('hide'); + context.querySelector('.unlockText').innerHTML = globalize.translate('MessageLiveTvGuideRequiresUnlock', limit); + + return limit; + }); + } + + function reloadGuide(context, newStartDate) { + + var apiClient = connectionManager.currentApiClient(); + + channelQuery.UserId = apiClient.getCurrentUserId(); + + getChannelLimit(context).then(function (channelLimit) { + + showLoading(); + + channelQuery.Limit = channelLimit; + channelQuery.AddCurrentProgram = false; + + channelsPromise = channelsPromise || apiClient.getLiveTvChannels(channelQuery); + + var date = newStartDate; + // Add one second to avoid getting programs that are just ending + date = new Date(date.getTime() + 1000); + + // Subtract to avoid getting programs that are starting when the grid ends + var nextDay = new Date(date.getTime() + msPerDay - 2000); + + console.log(nextDay); + channelsPromise.then(function (channelsResult) { + + apiClient.getLiveTvPrograms({ + UserId: apiClient.getCurrentUserId(), + MaxStartDate: nextDay.toISOString(), + MinEndDate: date.toISOString(), + channelIds: channelsResult.Items.map(function (c) { + return c.Id; + }).join(','), + ImageTypeLimit: 1, + EnableImageTypes: "Primary,Backdrop", + SortBy: "StartDate" + + }).then(function (programsResult) { + + renderGuide(context, date, channelsResult.Items, programsResult.Items, apiClient); + + hideLoading(); + + }); + }); + }); + } + + function getDisplayTime(date) { + + if ((typeof date).toString().toLowerCase() === 'string') { + try { + + date = datetime.parseISO8601Date(date, { toLocal: true }); + + } catch (err) { + return date; + } + } + + return datetime.getDisplayTime(date).toLowerCase(); + } + + function getTimeslotHeadersHtml(startDate, endDateTime) { + + var html = ''; + + // clone + startDate = new Date(startDate.getTime()); + + html += '