121 lines
3.0 KiB
TypeScript
121 lines
3.0 KiB
TypeScript
import { VideoDescription } from "./main.ts";
|
|
|
|
|
|
export const SMALL_WORDS = new Set([
|
|
"a",
|
|
"an",
|
|
"and",
|
|
"as",
|
|
"at",
|
|
"because",
|
|
"but",
|
|
"by",
|
|
"en",
|
|
"for",
|
|
"if",
|
|
"in",
|
|
"neither",
|
|
"nor",
|
|
"of",
|
|
"on",
|
|
"only",
|
|
"or",
|
|
"over",
|
|
"per",
|
|
"so",
|
|
"some",
|
|
"than",
|
|
"that",
|
|
"the",
|
|
"to",
|
|
"up",
|
|
"upon",
|
|
"v",
|
|
"versus",
|
|
"via",
|
|
"vs",
|
|
"when",
|
|
"with",
|
|
"without",
|
|
"yet",
|
|
]);
|
|
|
|
function capitalize(word: string): string {
|
|
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
}
|
|
|
|
function camelToTitleCase(camelCaseStr: string): string {
|
|
// Insert a space before each uppercase letter
|
|
const titleCaseStr = camelCaseStr.replace(/([A-Z])/g, ' $1');
|
|
|
|
// Split the string into words and process each word using map
|
|
const words = titleCaseStr.split(' ')
|
|
.map(v => v.toLowerCase())
|
|
.map(word => {
|
|
if (SMALL_WORDS.has(word)) {
|
|
return word;
|
|
}
|
|
return capitalize(word)
|
|
});
|
|
|
|
return capitalize(words.join(' '));
|
|
}
|
|
|
|
export function singleVideoDescription(video: VideoDescription): string {
|
|
const teachersList = video.teachers.map(v => "[[" + v + "]]").join(" & ");
|
|
|
|
const nagElement = video.nags.length > 0 ? `<span title="${video.nags.join("
")}">🔴</span>` : "";
|
|
return `=== ${camelToTitleCase(video.title)} ===
|
|
Date: {{#time: Y-m-d (D) | ${video.date}}} ${nagElement}<br>
|
|
Teachers: ${teachersList}<br>
|
|
Level: ${video.level}
|
|
|
|
[[${video.path}|left|400px|thumb|${video.title}]]
|
|
|
|
<div style="float:left">
|
|
==== Shown Patterns ====
|
|
${video.patterns}
|
|
|
|
==== Notes ====
|
|
${video.notes}
|
|
</div>
|
|
|
|
<br clear=all>`;
|
|
}
|
|
|
|
export function writeSections(events: VideoDescription[][]): string {
|
|
return events.map(v => {
|
|
const token = v[0]
|
|
const event_name = token.event === token.location ? token.event : token.event + " " + token.location
|
|
|
|
// FIXME: This will break with videos in 75 years
|
|
const event_contains_year = event_name.match(/\d{2}|20\d{2}/) !== null
|
|
const event_date = event_contains_year ? "" : new Date(token.date).getFullYear().toString()
|
|
|
|
let r = `== ${event_name} ${event_date} ==\n`
|
|
r += `${v.length} Video${v.length <= 1 ? "" : "s"}\n`
|
|
r += v.map(video => singleVideoDescription(video)).join("\n\n")
|
|
return r
|
|
}).join("\n\n\n")
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param videos
|
|
* @returns Bucket of videos for of each event, grouped by `name`, `location` and `year`
|
|
*/
|
|
export function bucketEvents(videos: VideoDescription[]): VideoDescription[][] {
|
|
const buckets = Object.groupBy(videos, (video) => {
|
|
return `${video.event}${video.location}${new Date(video.date).getFullYear()}`;
|
|
|
|
})
|
|
|
|
const sortedBuckets = Object.values(buckets)
|
|
.filter(v => v !== undefined)
|
|
.map(b =>
|
|
b.sort((a, b) =>
|
|
new Date(a.date).getTime() - new Date(b.date).getTime()))
|
|
|
|
return sortedBuckets
|
|
.sort((a, b) => new Date(a[0].date).getTime() - new Date(b[0].date).getTime())
|
|
} |