gitoriaLog in with ident

tracker

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Commita97c0295a97c0295tracker#4: show page /shows/:slug (header, seasons, episodes, watch checks) + tools/relink-episode-seasons.hlmrea97c0295/shows.hl

3.4 KB

  1. // shows.hl — READ-ONLY data access for a show's page (tracker.worldapi.org#4): shows, seasons,
  2. // episodes, persons, genres (storage/mpackdb/, migrated by tools/migrate.hl, tracker.worldapi.org#2).
  3. // Kept apart from watches.hl (the per-user watch state) and from components/show.hl (the page itself)
  4. // so /unwatched and /schedule (tickets #5/#6, "reuse, don't copy") can import the same functions.
  5. //
  6. // No declared index beyond the migration's own ['!oldId'] (opening a table with indexes it wasn't
  7. // created with is untested territory, hybriel#21 "opening a table rewrites its files") — a slug
  8. // lookup is a linear scan of ~9500 shows, cheap for one page load.
  9. import { MPackDB } from 'hl:mpackdb'
  10. import { env } from 'hl:proc'
  11. static envOr = (name, fallback) => {
  12. let v = env(name)
  13. return v != null && v.trim() != '' ? v.trim() : fallback
  14. }
  15. static storageDir = envOr('TRACKER_STORAGE', './storage/mpackdb')
  16. static genresTable = new MPackDB(file = storageDir + '/genres.db', primaryKey = '@id', indexes = ['!oldId'])
  17. static personsTable = new MPackDB(file = storageDir + '/persons.db', primaryKey = '@id', indexes = ['!oldId'])
  18. static showsTable = new MPackDB(file = storageDir + '/shows.db', primaryKey = '@id', indexes = ['!oldId'])
  19. static seasonsTable = new MPackDB(file = storageDir + '/seasons.db', primaryKey = '@id', indexes = ['!oldId'])
  20. static episodesTable = new MPackDB(file = storageDir + '/episodes.db', primaryKey = '@id', indexes = ['!oldId'])
  21. // the show with this urlSegment (slug), or null
  22. static showBySlug = (slug) => {
  23. if (slug == null || hlTypeName(slug) != 'String' || slug == '') { return null }
  24. for (s of showsTable.find(null, null)) { if (s.urlSegment == slug) { return s } }
  25. return null
  26. }
  27. static genreById = (id) => { return id == null ? null : genresTable.fetch(id) }
  28. static personById = (id) => { return id == null ? null : personsTable.fetch(id) }
  29. static seasonById = (id) => { return id == null ? null : seasonsTable.fetch(id) }
  30. // insertion sort, hand-written (no list sort(), hybriel#1) — a show has a handful of seasons at most
  31. static insertDesc = (sorted, s) => {
  32. let out = []
  33. let inserted = false
  34. for (x of sorted) {
  35. if (!inserted && s.seasonNumber >= x.seasonNumber) { out.push(s) inserted = true }
  36. out.push(x)
  37. }
  38. if (!inserted) { out.push(s) }
  39. return out
  40. }
  41. static insertAsc = (sorted, e) => {
  42. let out = []
  43. let inserted = false
  44. for (x of sorted) {
  45. if (!inserted && e.episodeNumber <= x.episodeNumber) { out.push(e) inserted = true }
  46. out.push(x)
  47. }
  48. if (!inserted) { out.push(e) }
  49. return out
  50. }
  51. // a show's seasons, latest (highest seasonNumber) first — creator: "all seasons in reverse order,
  52. // latest on top"
  53. static seasonsOfShow = (show) => {
  54. let sorted = []
  55. for (id of show.seasons) {
  56. let s = seasonsTable.fetch(id)
  57. if (s != null) { sorted = insertDesc(sorted, s) }
  58. }
  59. return sorted
  60. }
  61. // a season's episodes, in episode-number order
  62. static episodesOfSeason = (season) => {
  63. let sorted = []
  64. for (id of season.episodes) {
  65. let e = episodesTable.fetch(id)
  66. if (e != null) { sorted = insertAsc(sorted, e) }
  67. }
  68. return sorted
  69. }
  70. // the poster file name (oldId + the migrated extension) — null when either is missing; served at
  71. // /posters/<name> (project.hl), which falls back to a placeholder when the file itself isn't there
  72. // yet (the real poster files are not part of the mongo export, see the report's `open`)
  73. static posterName = (show) => {
  74. if (show.oldId == null || show.image == null || show.image == '') { return null }
  75. return show.oldId + '.' + show.image
  76. }

Branches

Latest commits

  • a97c0295tracker#4: show page /shows/:slug (header, seasons, episodes, watch checks) + tools/relink-episode-seasons.hlmre
  • 05f407c5tracker: no border on any button except inverted ones (Log out, ident status and identities too); header brand weight 100mre
  • 17375427tracker#2: tools/migrate.hl + tools/verify.hl — old MongoDB data into mpackdb with new idsmre
  • 31aac936tracker#3: no border on the header and on filled buttons; inverted buttons keep theirsmre
  • 2ad9d29ctracker#1: login exactly like calendar (identity selector in the header, empty homepage)mre
  • 3691e176tracker#1: empty tracker with the ident login (state of 2026-09-27)mre