diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 9bd8ced..0000000 --- a/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# .NET build artifacts -bin/ -obj/ -*.dll - -# Nix -.result/ -result - -# IDE -.vs/ -.vscode/ -*.user -*.suo diff --git a/deps.json b/deps.json deleted file mode 100644 index 0243907..0000000 --- a/deps.json +++ /dev/null @@ -1,152 +0,0 @@ -[ - { - "pname": "Diacritics", - "version": "3.3.29", - "hash": "sha256-sIbdJ3yMthnmJHly3WheUdYjtwPakcczTJx9ycxtgrY=" - }, - { - "pname": "ICU4N", - "version": "60.1.0-alpha.356", - "hash": "sha256-1QyOgO7pNMeoEgBtl6o8IG4o91wD2hFUgRI0jM0ltxY=" - }, - { - "pname": "ICU4N.Transliterator", - "version": "60.1.0-alpha.356", - "hash": "sha256-RLNwQNVqNz8Omfb/mC/rzQWVq8c7uCnNdG2qi4xJmds=" - }, - { - "pname": "J2N", - "version": "2.0.0", - "hash": "sha256-YvtIWErlm2O49hg3lIRm5Ha8/owkQkfMudzuldC3EhA=" - }, - { - "pname": "Jellyfin.Common", - "version": "10.10.7", - "hash": "sha256-9EIigrDheob4vRP+UBAoIPHH4fyz6Cl27GUpelEGpBg=" - }, - { - "pname": "Jellyfin.Controller", - "version": "10.10.7", - "hash": "sha256-/obWAuxWpSn+NlMES+fjyrf1g+qbxmSYQUBvgXQYltQ=" - }, - { - "pname": "Jellyfin.Data", - "version": "10.10.7", - "hash": "sha256-lRQjg/HkFAtCN0woL1gX6j5dMfVLP/fzQTKjFTcRth4=" - }, - { - "pname": "Jellyfin.Extensions", - "version": "10.10.7", - "hash": "sha256-AOGJ2IoT2v+LnlEqnb2O4FnXapcQiH0V9ny8GUysNHg=" - }, - { - "pname": "Jellyfin.Model", - "version": "10.10.7", - "hash": "sha256-ubsClGTLq/aFnMiBCaHVUX2b88beuL07Yn5VXNbTCjQ=" - }, - { - "pname": "Jellyfin.Naming", - "version": "10.10.7", - "hash": "sha256-/jlIS0X4FuBo6Ac1cjLGzgdJ3vR6VotBspxpNrqfMzo=" - }, - { - "pname": "Microsoft.Extensions.Caching.Abstractions", - "version": "2.0.0", - "hash": "sha256-Eg1MES40kzkGW9tZmjaKtbWI00Kbv7fLJQmjrigjxqk=" - }, - { - "pname": "Microsoft.Extensions.Caching.Memory", - "version": "2.0.0", - "hash": "sha256-1fnNvp62KrviVwYlqVl1CbdaZVpCDah9eCZeNDGDbWM=" - }, - { - "pname": "Microsoft.Extensions.Configuration.Abstractions", - "version": "8.0.0", - "hash": "sha256-4eBpDkf7MJozTZnOwQvwcfgRKQGcNXe0K/kF+h5Rl8o=" - }, - { - "pname": "Microsoft.Extensions.Configuration.Binder", - "version": "8.0.2", - "hash": "sha256-aGB0VuoC34YadAEqrwoaXLc5qla55pswDV2xLSmR7SE=" - }, - { - "pname": "Microsoft.Extensions.DependencyInjection", - "version": "8.0.1", - "hash": "sha256-O9g0jWS+jfGoT3yqKwZYJGL+jGSIeSbwmvomKDC3hTU=" - }, - { - "pname": "Microsoft.Extensions.DependencyInjection.Abstractions", - "version": "2.0.0", - "hash": "sha256-H1rEnq/veRWvmp8qmUsrQkQIcVlKilUNzmmKsxJ0md8=" - }, - { - "pname": "Microsoft.Extensions.DependencyInjection.Abstractions", - "version": "8.0.0", - "hash": "sha256-75KzEGWjbRELczJpCiJub+ltNUMMbz5A/1KQU+5dgP8=" - }, - { - "pname": "Microsoft.Extensions.DependencyInjection.Abstractions", - "version": "8.0.2", - "hash": "sha256-UfLfEQAkXxDaVPC7foE/J3FVEXd31Pu6uQIhTic3JgY=" - }, - { - "pname": "Microsoft.Extensions.Logging", - "version": "8.0.1", - "hash": "sha256-vkfVw4tQEg86Xg18v6QO0Qb4Ysz0Njx57d1XcNuj6IU=" - }, - { - "pname": "Microsoft.Extensions.Logging.Abstractions", - "version": "8.0.2", - "hash": "sha256-cHpe8X2BgYa5DzulZfq24rg8O2K5Lmq2OiLhoyAVgJc=" - }, - { - "pname": "Microsoft.Extensions.Options", - "version": "2.0.0", - "hash": "sha256-EMvaXxGzueI8lT97bYJQr0kAj1IK0pjnAcWN82hTnzw=" - }, - { - "pname": "Microsoft.Extensions.Options", - "version": "8.0.2", - "hash": "sha256-AjcldddddtN/9aH9pg7ClEZycWtFHLi9IPe1GGhNQys=" - }, - { - "pname": "Microsoft.Extensions.Primitives", - "version": "2.0.0", - "hash": "sha256-q44LtMvyNEKSvgERvA+BrasKapP92Sc91QR4u2TJ9/Y=" - }, - { - "pname": "Microsoft.Extensions.Primitives", - "version": "8.0.0", - "hash": "sha256-FU8qj3DR8bDdc1c+WeGZx/PCZeqqndweZM9epcpXjSo=" - }, - { - "pname": "Microsoft.NETCore.Platforms", - "version": "1.1.0", - "hash": "sha256-FeM40ktcObQJk4nMYShB61H/E8B7tIKfl9ObJ0IOcCM=" - }, - { - "pname": "Microsoft.NETCore.Targets", - "version": "1.1.0", - "hash": "sha256-0AqQ2gMS8iNlYkrD+BxtIg7cXMnr9xZHtKAuN4bjfaQ=" - }, - { - "pname": "System.Globalization", - "version": "4.3.0", - "hash": "sha256-caL0pRmFSEsaoeZeWN5BTQtGrAtaQPwFi8YOZPZG5rI=" - }, - { - "pname": "System.Runtime", - "version": "4.3.0", - "hash": "sha256-51813WXpBIsuA6fUtE5XaRQjcWdQ2/lmEokJt97u0Rg=" - }, - { - "pname": "System.Text.Json", - "version": "8.0.5", - "hash": "sha256-yKxo54w5odWT6nPruUVsaX53oPRe+gKzGvLnnxtwP68=" - }, - { - "pname": "System.Threading.Tasks.Dataflow", - "version": "8.0.1", - "hash": "sha256-hgCfF91BDd/eOtLEd5jhjzgJdvwmVv4/b42fXRr3nvo=" - } -] diff --git a/flake.lock b/flake.lock deleted file mode 100644 index 0b0400a..0000000 --- a/flake.lock +++ /dev/null @@ -1,27 +0,0 @@ -{ - "nodes": { - "nixpkgs": { - "locked": { - "lastModified": 1778443072, - "narHash": "sha256-zi7/fsqM/kFdNuED//4WOCUtezGtKKqRNORjMvfwjnA=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "da5ad661ba4e5ef59ba743f0d112cbc30e474f32", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "nixpkgs": "nixpkgs" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix deleted file mode 100644 index 2645a68..0000000 --- a/flake.nix +++ /dev/null @@ -1,72 +0,0 @@ -{ - description = "Jellyfin Lessons — a Jellyfin plugin"; - - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - }; - - outputs = - { self, nixpkgs }: - let - forAllSystems = - fn: nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed fn; - in - { - devShells = forAllSystems ( - system: - let - pkgs = nixpkgs.legacyPackages.${system}; - in - { - default = pkgs.mkShell { - packages = [ - pkgs.dotnetCorePackages.sdk_9_0 - pkgs.typst - pkgs.nodejs - ]; - - shellHook = '' - echo "jellyfin-lessons dev shell" - echo " dotnet: $(dotnet --version)" - echo " typst: $(typst --version)" - echo " node: $(node --version)" - ''; - }; - } - ); - - packages = forAllSystems ( - system: - let - pkgs = nixpkgs.legacyPackages.${system}; - in - { - default = pkgs.callPackage ( - { - buildDotnetModule, - dotnetCorePackages, - lib, - }: - buildDotnetModule { - pname = "jellyfin-lessons"; - version = "0.1.0"; - - src = self; - - projectFile = "plugin/Jellyfin.Plugin.Lessons.csproj"; - nugetDeps = ./deps.json; - - dotnet-sdk = dotnetCorePackages.sdk_9_0; - dotnet-runtime = dotnetCorePackages.aspnetcore_9_0; - - meta = { - description = "Jellyfin Lessons plugin"; - license = lib.licenses.mit; - platforms = lib.platforms.all; - }; - } - ) { }; - } - ); - }; -} diff --git a/plugin/Jellyfin.Plugin.Lessons.csproj b/plugin/Jellyfin.Plugin.Lessons.csproj deleted file mode 100644 index 37bd5cc..0000000 --- a/plugin/Jellyfin.Plugin.Lessons.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - net9.0 - JellyfinLessons - jellyfin-lessons - - - - - runtime - - - runtime - - - diff --git a/templates/example-lesson.typ b/templates/example-lesson.typ new file mode 100644 index 0000000..44122e7 --- /dev/null +++ b/templates/example-lesson.typ @@ -0,0 +1,83 @@ +// example-lesson.typ — Complete example demonstrating the lesson template +// ============================================================ +// Frontmatter: +// title: God's Creation: The Water Cycle +// grade: 3 +// subject: Science +// date: 2026-01-15 +// media: jellyfin://uuid-water-cycle, jellyfin://uuid-cloud-formation +// description: Learn how God designed water to move through His creation — +// evaporation, condensation, and precipitation working together to sustain life. + +#import "lesson.typ": lesson-template, media-ref + +#show: doc => lesson-template( + doc, + title: "God's Creation: The Water Cycle", + grade: "3", + subject: "Science", + date: "2026-01-15", + media: ( + ("uuid-water-cycle", "The Water Cycle Explained"), + ("uuid-cloud-formation", "Cloud Formation and Weather"), + ), + description: "Learn how God designed water to move through His creation — evaporation, condensation, and precipitation working together to sustain life on Earth.", +) + += What Is the Water Cycle? + +Water is one of God's most amazing creations! The water cycle is how water moves +all around our planet. It never runs out — it just keeps going around and around. +There are four main steps: evaporation, condensation, precipitation, and collection. + +== Evaporation + +When the sun shines on oceans, lakes, and rivers, the water gets warm and turns +into a gas called *water vapor*. This gas rises up into the sky. You can't see it, +but it's there! Evaporation happens every day, especially on warm, sunny days. + +== Condensation + +When the water vapor goes high up where it's cold, it turns back into tiny water +droplets. These droplets come together to make clouds. Have you ever looked at +clouds and seen shapes? Those shapes are made of millions of tiny water droplets +sticking together! + +== Precipitation + +When the clouds get too heavy with water droplets, the water falls back down to +Earth. This is called *precipitation*. It can be: + +- Rain — liquid water falling from the sky +- Snow — frozen crystals that fall in cold weather +- Sleet — tiny ice pellets that bounce when they land +- Hail — hard balls of ice that form in big storms + +God sends precipitation to water the plants and fill the rivers, lakes, and oceans. + +== Collection + +The water that falls onto the ground collects in rivers, lakes, and oceans. Some +of it soaks into the ground and becomes *groundwater* — water stored underground +that plants can reach with their roots. Then the sun warms the water, and the +whole cycle starts all over again! + += Why Is the Water Cycle Important? + +God designed the water cycle to do important work: + +- Give plants the water they need to grow +- Provide fresh water for animals and people to drink +- Keep our rivers and lakes full of water +- Help control the temperature of our whole planet +- Clean the water naturally as it moves through the cycle + +*"He causes the vapors to ascend from the ends of the earth; He makes lightning +for the rain; He brings the wind out of His treasuries."* — Psalm 135:7 + += Think About It + +1. What happens to water when the sun shines on a lake? +2. Why do clouds form high up in the sky? +3. What are the four types of precipitation? +4. How does the water cycle show God's care for His creation? diff --git a/templates/lesson.typ b/templates/lesson.typ new file mode 100644 index 0000000..a85cab3 --- /dev/null +++ b/templates/lesson.typ @@ -0,0 +1,90 @@ +// lesson.typ — Typst template for homeschool lessons +// ============================================================ +// This template produces clean, structured lesson documents. +// Designed to compile to HTML for rendering inside Jellyfin. +// +// Frontmatter convention (documented as comments at top of each lesson): +// // title: The Lesson Title +// // grade: 3 +// // subject: Science +// // date: 2026-01-15 +// // media: jellyfin://uuid-1, jellyfin://uuid-2 +// // description: Short description of the lesson +// +// Usage: +// #import "lesson.typ": lesson-template, media-ref +// #show: doc => lesson-template( +// doc, +// title: "The Water Cycle", +// grade: "3", +// subject: "Science", +// date: "2026-01-15", +// media: (), +// description: "Learn about evaporation and condensation.", +// ) + +// Render a single Jellyfin media reference. +// Produces a element in HTML output +// that the Jellyfin plugin can parse and link to the player. +#let media-ref(id, title) = { + raw(lang: "jellyfin-media", id + "|" + title) +} + +// Render a list of media references as a formatted section. +#let media-section(media-items) = { + if media-items.len() > 0 { + heading(level: 2)[Media] + for item in media-items { + list.item(media-ref(item.at(0), item.at(1))) + } + } +} + +// The main lesson template. +// - body: The lesson content (passed via show rule) +// - title: Lesson title (string) +// - grade: Grade level (string, e.g. "3") +// - subject: Subject name (string) +// - date: Lesson date in YYYY-MM-DD format +// - media: Array of (id, title) pairs for linked Jellyfin media +// - description: Short description of the lesson +#let lesson-template( + body, + title: "Untitled Lesson", + grade: none, + subject: none, + date: none, + media: (), + description: none, +) = { + // Document metadata for PDF output + set document(title: title) + + // Title — prominent heading + heading(level: 1, title) + + // Metadata line: Grade X — Subject — Date + let meta-parts = () + if grade != none { meta-parts.push([Grade ] + grade) } + if subject != none { meta-parts.push(subject) } + if date != none { meta-parts.push(date) } + if meta-parts.len() > 0 { + let sep = [ — ] + let meta-text = meta-parts.first() + for i in range(1, meta-parts.len()) { + meta-text += sep + meta-parts.at(i) + } + par(text(style: "italic", size: 0.9em, meta-text)) + } + + // Description paragraph + if description != none { + par([*Description:* ] + description) + } + + // Lesson body content (renders user-authored sections, paragraphs, lists, etc.) + body + + // Media references section — listed with identifiable jellyfin-media codes + media-section(media) +}