-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Schedules on the Calendar page #501
base: develop
Are you sure you want to change the base?
Changes from 8 commits
83f2168
84e80f3
6622290
6fdb152
27caa51
b58ce4f
522c964
bb4a238
76e391d
b1ca6aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
const daysOfWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; | ||
|
||
const updateSchedules = function(tzText) { | ||
const schedules = document.getElementsByClassName("schedule"); | ||
const tzParts = tzText.match( | ||
"^\\(GMT(?<sign>[+-])(?<hours>[0-9]{2}):(?<minutes>[0-9]{2})\\) (?<name>[a-zA-Z ]+)( -|$)" | ||
); | ||
const tzSign = tzParts[1]; | ||
const tzMinute = Number.parseInt(tzSign + tzParts[3], 10); | ||
|
||
// show data uses Pacific time, adjust by 8 hours | ||
const tzHour = Number.parseInt(tzSign + tzParts[2], 10) + 8; | ||
|
||
for (let x = 0; x < schedules.length; x++) { | ||
const type = schedules[x].getAttribute("data-live-schedule-type"); | ||
let day = Number.parseInt(schedules[x].getAttribute("data-live-schedule-day"), 10); | ||
let hour = Number.parseInt(schedules[x].getAttribute("data-live-schedule-hour"), 10); | ||
let minute = Number.parseInt(schedules[x].getAttribute("data-live-schedule-minute") || "0", 10); | ||
|
||
minute += tzMinute; | ||
if (minute < 0) { | ||
hour -= 1; | ||
minute += 60; | ||
} else if (minute >= 60) { | ||
hour += 1; | ||
minute -= 60; | ||
} | ||
|
||
hour += tzHour; | ||
if (hour < 0) { | ||
day -= 1; | ||
hour += 24; | ||
} else if (hour >= 24) { | ||
day += 1; | ||
hour -= 24; | ||
} | ||
|
||
if (day < 0) { | ||
day += 7; | ||
} else if (day >= 7) { | ||
day -= 7; | ||
} | ||
|
||
let ampm = "am"; | ||
if (hour >= 12) { | ||
ampm = "pm"; | ||
if (hour > 12) { | ||
hour -= 12; | ||
} | ||
} else if (hour == 0) { | ||
hour = 12; | ||
} | ||
|
||
const tzName = tzParts[4]; | ||
|
||
let scheduleHtml = ""; | ||
if (type != "weekly") { | ||
scheduleHtml += "Alternating "; | ||
} | ||
const minuteText = minute.toString().padStart(2, '0'); | ||
scheduleHtml += `${daysOfWeek[day]}s<br>${hour}:${minuteText}${ampm} ${tzName}`; | ||
|
||
schedules[x].innerHTML = scheduleHtml; | ||
} | ||
} | ||
|
||
const calendarOnLoad = function() { | ||
const iframe = document.querySelector('iframe'); | ||
const calendarBase = iframe.dataset.src; | ||
|
||
// Detect timezone automatically | ||
var tz = Intl.DateTimeFormat().resolvedOptions().timeZone; | ||
var tzname = encodeURIComponent(tz); | ||
iframe.src = calendarBase + "&ctz=" + tzname; | ||
|
||
const ctz = document.querySelector('#ctz'); | ||
ctz.value = tz; | ||
|
||
updateSchedules(ctz.options[ctz.selectedIndex].text); | ||
|
||
// Change on timezone after dropdown | ||
ctz.onchange = function () { | ||
var tzname = ctz.value; | ||
updateSchedules(ctz.options[ctz.selectedIndex].text) | ||
|
||
if(tzname && tzname != "none") { | ||
iframe.src = calendarBase + "&ctz=" + tzname; | ||
} | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,21 @@ | ||
{{ define "headcontent" }} | ||
|
||
{{ $calendarJs := resources.Get "js/calendar.js" }} | ||
{{ if hugo.IsProduction }} | ||
{{ $calendarJs = $calendarJs | minify | fingerprint }} | ||
{{ end }} | ||
<script type="text/javascript" src="{{ $calendarJs.Permalink }}" integrity="{{ $calendarJs.Data.Integrity }}"></script> | ||
<script> | ||
window.onload = () => { | ||
calendarOnLoad(); | ||
} | ||
</script> | ||
{{end}} | ||
{{ define "main" }} | ||
<div class="container"> | ||
<div class="content"> | ||
<h1>{{.Title}}</h1> | ||
Subscribe To The Calendar: <a href="{{.Site.Params.calendar.rss}}">iCalendar</a> | ||
|
||
<iframe frameborder="0" scrolling="no" data-src="//www.google.com/calendar/embed?showTitle=0&showNav=0&showPrint=0&showTabs=0&showCalendars=0&mode=AGENDA&wkst=1&bgcolor=%23FFFFFF&src={{.Site.Params.calendar.embedd}}&color=%235229A3" width="100%" height="400px"></iframe> | ||
|
||
<select name="ctz" id="ctz" style="width: 100%;"> | ||
<h2>Regular Live Show Times</h2> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was thinking about how these shows have two schedules: a live show schedule and a recorded show release schedule. Not sure how much this header helps differentiate but wanted to try something. |
||
<select name="ctz" id="ctz" style="float: right;"> | ||
<option value="none">-- Select Your Timezone --</option> | ||
<option value="Pacific/Niue">(GMT-11:00) Niue</option> | ||
<option value="Pacific/Pago_Pago">(GMT-11:00) Pago Pago</option> | ||
|
@@ -320,24 +326,30 @@ <h1>{{.Title}}</h1> | |
<option value="Pacific/Tongatapu">(GMT+13:00) Tongatapu</option> | ||
<option value="Pacific/Kiritimati">(GMT+14:00) Kiritimati</option> | ||
</select> | ||
</div> | ||
</div> | ||
|
||
<script> | ||
var calendarBase = document.querySelector('iframe').dataset.src; | ||
<br> | ||
<br> | ||
|
||
// Detect timezone automatically | ||
var tz = Intl.DateTimeFormat().resolvedOptions().timeZone; | ||
var tzname = encodeURIComponent(tz); | ||
document.querySelector('iframe').src = calendarBase + "&ctz=" + tzname; | ||
<div class="container"> | ||
<div class="columns is-multiline"> | ||
{{ range where .Site.Pages "Section" "show" }} | ||
{{ if (isset .Params "live") }} | ||
<div class="column is-6 is-3-fullhd is-3-desktop is-12-mobile" style="display: flex;"> | ||
{{ partial "episode/schedule.html" . }} | ||
</div> | ||
{{ end }} | ||
{{ end }} | ||
</div> | ||
</div> | ||
|
||
// Change on timezone after dropdown | ||
document.querySelector('#ctz').onchange = function () { | ||
var tzname = document.querySelector('#ctz').value; | ||
|
||
if(tzname && tzname != "none") { | ||
document.querySelector('iframe').src = calendarBase + "&ctz=" + tzname; | ||
} | ||
}; | ||
</script> | ||
<br> | ||
<br> | ||
|
||
Subscribe To The Calendar: <a href="{{.Site.Params.calendar.rss}}">iCalendar</a> | ||
|
||
<iframe frameborder="0" scrolling="no" data-src="//www.google.com/calendar/embed?showTitle=0&showNav=0&showPrint=0&showTabs=0&showCalendars=0&mode=AGENDA&wkst=1&bgcolor=%23FFFFFF&src={{.Site.Params.calendar.embedd}}&color=%235229A3" width="100%" height="400px"></iframe> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So personally I try to avoid I am thinking this is fine for this PR. But a follow up (of either a calendar rework using or of a styling change) could be where this will happen. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added a div and some Bulma classes and removed the |
||
|
||
|
||
</div> | ||
</div> | ||
{{end}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<a href="{{ .Permalink }}"> | ||
<div class="card card-episode"> | ||
<div class="card-image"> | ||
<img src="{{.Params.header_image }}" width="432" height="242" alt="{{.Title}}"> | ||
</div> | ||
<div class="card-content"> | ||
<div class="content"> | ||
<h3>{{.Title}}</h3> | ||
<p class="schedule" | ||
data-live-schedule-type="{{ index .Params.live.type }}" | ||
data-live-schedule-day="{{ index .Params.live.day }}" | ||
data-live-schedule-hour="{{ index .Params.live.hour }}" | ||
{{ if (isset .Params.live "minute") }} | ||
data-live-schedule-minute="{{ index .Params.live.minute }}" | ||
{{ end }}></p> | ||
</div> | ||
</div> | ||
</div> | ||
</a> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Coder Radio card seems to be ahead of the Google Calendar by about 3 hours.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is because today's time is not the regular time. It should match if you look at the time for next week. I can ask around too though.
But I guess it does bring up a non-technical question, is there a way we can make the reason these don't match more clear? Not something we can do in the website, but could the calendar items add "(Special Time)" to the title, or something similar?
(And I will take a swing at the other comments later, thanks!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Chris confirmed in matrix that today's time is not the usual time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like I should've looked farther ahead! I think we the calendar should have some kind of note if possible to specify that the time is different from normal. I haven't used Google Calendar so I am not sure if that is an option. We can ask Chris about that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another crazy thought... Could we use the Google Calendar API to get the time of the next event? Maybe outside the scope of this PR (unless you really want to tackle it). But that could be a good next step on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We were looking into how to handle the contact form with its API as well. I had proposed a separate backend just handle API requests like those. There was some discussion about it in #232
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can look into settings to protect and scope the Google Calendar API key properly. Such as only allowing access to the JB Calendar from jupiterbroadcasting.com, and nothing else from Google Calendar. I haven't worked with the Google Calendar API, but I've seen other APIs allow these kinds of settings, so it should work with Google Calendar as well. Quickly glancing at the API, it seems to be possible with https://cloud.google.com/docs/authentication/api-keys#api_key_restrictions.
I see https://irc.twit.tv/ is using a solution based on the Google Calendar API, we might be able to build something similar. You can search for "calendar" in the Network tab of your browser and see what Google API they are using. I'm hoping they've done their research on not expoing their API key.
If we have an API key, this might just be a separate AJAX request to a JSON API, similar to what TWiT is using.
Edit: This seems to be the endpoint we want. https://developers.google.com/calendar/api/v3/reference/calendars/get?apix_params=%7B%22calendarId%22%3A%22primary%22%7D#http-request
What is weird is the examples from Google only list backend languages (Java, Python, PHP, and Ruby), so maybe the API is not intended to be client-side. But as CGBassPlayer mentioned in #232, we could use a separate backend service for that.
I agree, but I think if we change the calendar, we should make sure it's correct and not too confusing. I think the design of the cards looks great, and it's definitely a great addition. Just hard-coding the events might make it more confusing. A better solution could be using the Google Calendar API, in my opinion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did get excited to have something merged here, but makes sense to back up and reassess. 😅
Are we still talking about adding "Next Showtime" to the cards? And potentially using the Google Calendar API to determine that?
We'd still need to indicate when the "Next Showtime" is not a regular show time. We could maybe do that by calculating when the next regular time should be, and if they don't match, we know it's special.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That could work. Maybe looking at the last 3-4 shows and determining a pattern could be an idea.
We should also take permanent changes in the live calendar into account, like how LUP was moved from Tuesday to Sunday.
I also noticed that some event in the calendar have a different name to make it clear it was a different live time.
Maybe this will make it more difficult to automatically detect which show is live? We could detect any show with "Coder Radio" in the title, but what about false positives like "No Coder Radio this week"? Have we had this before? 😁
Or maybe it's good enough to have a system that works most of the time? Google has changed the API before, and there will be changes in the future, so there might always be unforeseen breakages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nevermind I give up.
Just kidding, but really my goal here was to have somewhere on the website to find general live schedules for each show. We immediately hit a corner case where it was confusing, so it became more difficult to proceed. If I have time I'll check out the Google Calendar API.
I'd hope we can be more precise, either by looking at the recurrence of the Google Calendar events, or having something like I have in the
live
property of shows in this PR.