Implemented basic channel guide, needs moar polish
This commit is contained in:
parent
c78b056cab
commit
f7db5ea31d
3 changed files with 109 additions and 20 deletions
|
|
@ -47,7 +47,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||||
}
|
}
|
||||||
|
|
||||||
.channel-guide-schedule-row{
|
.channel-guide-schedule-row{
|
||||||
height: 2.2em;
|
height: 3.4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.channel-guide-channel-list-entry {
|
.channel-guide-channel-list-entry {
|
||||||
|
|
@ -67,15 +67,20 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||||
|
|
||||||
.channel-guide-schedule-track {
|
.channel-guide-schedule-track {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.channel-guide-schedule-entry {
|
.channel-guide-schedule-entry {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
.channel-guide-schedule-entry h3 {
|
.channel-guide-schedule-entry h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
text-wrap: nowrap;
|
text-wrap: nowrap;
|
||||||
}
|
}
|
||||||
|
|
@ -393,6 +393,20 @@ input.control-prompt, input.control-prompt:focus{
|
||||||
border-bottom: 1px solid var(--accent0);
|
border-bottom: 1px solid var(--accent0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.channel-guide-schedule-entry{
|
||||||
|
padding: 0 0.7em;
|
||||||
|
background-color: var(--bg1);
|
||||||
|
border-left: 1px solid var(--accent0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-guide-schedule-entry.starts-before{
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-guide-schedule-entry.last-ends-before{
|
||||||
|
border-right: 1px solid var(--accent0);
|
||||||
|
}
|
||||||
|
|
||||||
/* channel settings */
|
/* channel settings */
|
||||||
.channel-info-label{
|
.channel-info-label{
|
||||||
color: var(--accent1-alt0);
|
color: var(--accent1-alt0);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@ class ChannelGuide{
|
||||||
//define property to hold refresh timer
|
//define property to hold refresh timer
|
||||||
this.refreshTimer;
|
this.refreshTimer;
|
||||||
|
|
||||||
|
//define property to hold schedule cache
|
||||||
|
this.cache;
|
||||||
|
|
||||||
//Grab DOM Nodes
|
//Grab DOM Nodes
|
||||||
this.scheduleIndex = document.querySelector('#channel-guide-schedule-index');
|
this.scheduleIndex = document.querySelector('#channel-guide-schedule-index');
|
||||||
this.channelList = document.querySelector('#channel-guide-channel-list');
|
this.channelList = document.querySelector('#channel-guide-channel-list');
|
||||||
|
|
@ -28,14 +31,17 @@ class ChannelGuide{
|
||||||
this.refreshList();
|
this.refreshList();
|
||||||
}
|
}
|
||||||
|
|
||||||
async refreshList(){
|
async refreshList(now = new Date()){
|
||||||
//Fetch latest channel list and render it to the schedule page
|
//Freshen up the local schedule cache
|
||||||
this.renderList(await utils.ajax.getChannels());
|
this.cache = await utils.ajax.getChannels();
|
||||||
|
|
||||||
|
//render the freshly pulled schedule data to the page
|
||||||
|
this.renderList(this.cache, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderList(schedule, now = new Date()){
|
renderList(schedule, now = new Date()){
|
||||||
this.renderIndex(now);
|
this.renderIndex(now);
|
||||||
this.renderChannelList(schedule, now);
|
this.renderChannelList(schedule);
|
||||||
this.renderSchedule(schedule, now);
|
this.renderSchedule(schedule, now);
|
||||||
|
|
||||||
//if we've got a job to refresh the list
|
//if we've got a job to refresh the list
|
||||||
|
|
@ -70,7 +76,7 @@ class ChannelGuide{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderChannelList(schedule, now = new Date()){
|
renderChannelList(schedule){
|
||||||
//Clean out channel list
|
//Clean out channel list
|
||||||
this.channelList.innerHTML = '';
|
this.channelList.innerHTML = '';
|
||||||
|
|
||||||
|
|
@ -96,27 +102,24 @@ class ChannelGuide{
|
||||||
//Clear out the schedule
|
//Clear out the schedule
|
||||||
this.scheduledMediaDiv.innerHTML = '';
|
this.scheduledMediaDiv.innerHTML = '';
|
||||||
|
|
||||||
|
schedule = this.fillDeadAir(schedule, now);
|
||||||
|
|
||||||
//Iterate through all of the received channels
|
//Iterate through all of the received channels
|
||||||
for(const channel of schedule){
|
for(const channel of schedule){
|
||||||
|
|
||||||
//Create a div to hold all of the current channels entries
|
//Create a div to hold all of the current channels entries
|
||||||
const channelTrack = document.createElement('div');
|
const channelTrack = document.createElement('div');
|
||||||
channelTrack.classList.add('channel-guide-schedule-track');
|
channelTrack.classList.add('channel-guide-schedule-track', 'channel-guide-schedule-row');
|
||||||
|
|
||||||
//For every scheduled video
|
//For every scheduled video
|
||||||
for(const entry of channel.schedule){
|
for(const entryIndex in channel.schedule){
|
||||||
//Create div for current schedule entry
|
//Get entry by index
|
||||||
const entryDiv = document.createElement('div');
|
const entry = channel.schedule[entryIndex];
|
||||||
entryDiv.classList.add('channel-guide-schedule-entry', 'channel-guide-schedule-row');
|
//Check if this is the last item
|
||||||
|
const last = entryIndex == channel.schedule.length - 1;
|
||||||
//Throw down an entry label
|
|
||||||
const entryLabel = document.createElement('h3');
|
|
||||||
entryLabel.textContent = utils.unescapeEntities(entry.title);
|
|
||||||
|
|
||||||
//Assemble the entry
|
|
||||||
entryDiv.appendChild(entryLabel);
|
|
||||||
|
|
||||||
//slot entry into schedule track
|
//slot entry into schedule track
|
||||||
channelTrack.appendChild(entryDiv);
|
channelTrack.appendChild(this.renderScheduleItem(entry, now, last));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Inject channel track into schedule div
|
//Inject channel track into schedule div
|
||||||
|
|
@ -124,7 +127,74 @@ class ChannelGuide{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderScheduleItem(item){
|
|
||||||
|
fillDeadAir(schedule){
|
||||||
|
//For each video in the schedule
|
||||||
|
for(const video of schedule){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Return processed schedule
|
||||||
|
return schedule;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderScheduleItem(item, now = new Date(), last = false){
|
||||||
|
//Create div for current schedule entry
|
||||||
|
const entryDiv = document.createElement('div');
|
||||||
|
entryDiv.classList.add('channel-guide-schedule-entry', 'channel-guide-schedule-row');
|
||||||
|
|
||||||
|
//Throw down an entry label
|
||||||
|
const entryLabel = document.createElement('h3');
|
||||||
|
entryLabel.textContent = utils.unescapeEntities(item.title);
|
||||||
|
|
||||||
|
//calculate end epoch
|
||||||
|
const end = item.startTime + (item.duration * 1000);
|
||||||
|
|
||||||
|
//Place entryDiv by scheduled time
|
||||||
|
entryDiv.style.left = `${this.offsetByEpoch(item.startTime, now)}px`;
|
||||||
|
entryDiv.style.right = `${this.offsetByEpoch(end, now, true)}px`;
|
||||||
|
|
||||||
|
//if this started before the schedule time range
|
||||||
|
if(item.startTime < now.getTime()){
|
||||||
|
//mark it for css
|
||||||
|
entryDiv.classList.add('starts-before');
|
||||||
|
}
|
||||||
|
|
||||||
|
//if this is the last item and it ends before the schedule time range
|
||||||
|
if(last && end < now.getTime() + 5400000){
|
||||||
|
//mark it for css
|
||||||
|
entryDiv.classList.add('last-ends-before');
|
||||||
|
}
|
||||||
|
|
||||||
|
//Assemble the entry
|
||||||
|
entryDiv.appendChild(entryLabel);
|
||||||
|
|
||||||
|
//Return assembled entry div
|
||||||
|
return entryDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
offsetByEpoch(scheduleEpoch, now = new Date(), rightOffset = false){
|
||||||
|
//Calculate how many milliseconds after the current time our scheduled item is
|
||||||
|
const ms = scheduleEpoch - now.getTime();
|
||||||
|
|
||||||
|
//Calculate and return offset by milliseconds
|
||||||
|
return this.offsetByMilliseconds(ms, rightOffset, rightOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
offsetByMilliseconds(ms, rightOffset = false){
|
||||||
|
//Calculate place in schedule as float between 0 and 1 by deviding input by schedules range (90 minutes)
|
||||||
|
//Making sure to reverse value if rightOffset is thrown
|
||||||
|
const timeFloat = rightOffset ? 1 - ms / 5400000 : ms / 5400000;
|
||||||
|
|
||||||
|
//Get maximum position relative to the range itself
|
||||||
|
const offsetMax = this.scheduledMediaDiv.getBoundingClientRect().width;
|
||||||
|
|
||||||
|
//Calculate offset by timefloat and offset max
|
||||||
|
const offset = (offsetMax * timeFloat) < 0 ? 0 : (offsetMax * timeFloat);
|
||||||
|
|
||||||
|
//return position relative to parent, adding channel list width to left side to handle offset
|
||||||
|
return offset;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue