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{
|
||||
height: 2.2em;
|
||||
height: 3.4em;
|
||||
}
|
||||
|
||||
.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 {
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.channel-guide-schedule-entry {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.channel-guide-schedule-entry h3 {
|
||||
margin: 0;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
text-wrap: nowrap;
|
||||
}
|
||||
|
|
@ -393,6 +393,20 @@ input.control-prompt, input.control-prompt:focus{
|
|||
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-info-label{
|
||||
color: var(--accent1-alt0);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ class ChannelGuide{
|
|||
//define property to hold refresh timer
|
||||
this.refreshTimer;
|
||||
|
||||
//define property to hold schedule cache
|
||||
this.cache;
|
||||
|
||||
//Grab DOM Nodes
|
||||
this.scheduleIndex = document.querySelector('#channel-guide-schedule-index');
|
||||
this.channelList = document.querySelector('#channel-guide-channel-list');
|
||||
|
|
@ -28,14 +31,17 @@ class ChannelGuide{
|
|||
this.refreshList();
|
||||
}
|
||||
|
||||
async refreshList(){
|
||||
//Fetch latest channel list and render it to the schedule page
|
||||
this.renderList(await utils.ajax.getChannels());
|
||||
async refreshList(now = new Date()){
|
||||
//Freshen up the local schedule cache
|
||||
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()){
|
||||
this.renderIndex(now);
|
||||
this.renderChannelList(schedule, now);
|
||||
this.renderChannelList(schedule);
|
||||
this.renderSchedule(schedule, now);
|
||||
|
||||
//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
|
||||
this.channelList.innerHTML = '';
|
||||
|
||||
|
|
@ -96,27 +102,24 @@ class ChannelGuide{
|
|||
//Clear out the schedule
|
||||
this.scheduledMediaDiv.innerHTML = '';
|
||||
|
||||
schedule = this.fillDeadAir(schedule, now);
|
||||
|
||||
//Iterate through all of the received channels
|
||||
for(const channel of schedule){
|
||||
|
||||
//Create a div to hold all of the current channels entries
|
||||
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(const entry of channel.schedule){
|
||||
//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(entry.title);
|
||||
|
||||
//Assemble the entry
|
||||
entryDiv.appendChild(entryLabel);
|
||||
for(const entryIndex in channel.schedule){
|
||||
//Get entry by index
|
||||
const entry = channel.schedule[entryIndex];
|
||||
//Check if this is the last item
|
||||
const last = entryIndex == channel.schedule.length - 1;
|
||||
|
||||
//slot entry into schedule track
|
||||
channelTrack.appendChild(entryDiv);
|
||||
channelTrack.appendChild(this.renderScheduleItem(entry, now, last));
|
||||
}
|
||||
|
||||
//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