diff --git a/.vscode/launch.json b/.vscode/launch.json index ecacfa7..8f09d83 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,21 +1,38 @@ { - "version": "0.2.0", - "configurations": [ - { - "name": "FastAPI: Uvicorn", - "type": "debugpy", - "request": "launch", - "module": "uvicorn", - "args": [ - "app.main:app", - "--reload" - ], - "jinja": true, - "justMyCode": true, - "env": { - "PYTHONPATH": "${workspaceFolder}/app", - } + "version": "0.2.0", + "configurations": [ + { + "name": "Server", + "type": "debugpy", + "request": "launch", + "module": "uvicorn", + "args": [ + "app.main:app", + "--reload" + ], + "jinja": true, + "justMyCode": true, + "env": { + "PYTHONPATH": "${workspaceFolder}/app", + "DATA_DIR": "${workspaceFolder}/app/data" } - ] - } - \ No newline at end of file + }, + { + "name": "Client", + "type": "node", + "request": "launch", + "cwd": "${workspaceFolder}/frontend", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "dev"], + "env": { + "/data": "${workspaceFolder}/app/data", + } + } + ], + "compounds": [ + { + "name": "Run FastAPI + Svelte", + "configurations": ["Server", "Client"] + } + ] +} diff --git a/app/data/dropout.json b/app/data/dropout.json new file mode 100644 index 0000000..9782b6e --- /dev/null +++ b/app/data/dropout.json @@ -0,0 +1,362 @@ +[ + { + "SHOW": "Game Changer", + "URL": "https://www.dropout.tv/game-changer", + "LINK": "game-changer", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Game_Changer.jpg" + }, + { + "SHOW": "Dimension 20: Cloudward, Ho!", + "URL": "https://www.dropout.tv/dimension-20-cloudward-ho", + "LINK": "dimension-20-cloudward-ho", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Cloudward_Ho.jpg" + }, + { + "SHOW": "Dimension 20's Adventuring Party", + "URL": "https://www.dropout.tv/dimension-20-s-adventuring-party", + "LINK": "dimension-20-s-adventuring-party", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20s_Adventuring_Party.jpg" + }, + { + "SHOW": "Dirty Laundry", + "URL": "https://www.dropout.tv/dirty-laundry", + "LINK": "dirty-laundry", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dirty_Laundry.jpg" + }, + { + "SHOW": "Parlor Room", + "URL": "https://www.dropout.tv/parlor-room", + "LINK": "parlor-room", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Parlor_Room.jpg" + }, + { + "SHOW": "Smartypants", + "URL": "https://www.dropout.tv/smartypants", + "LINK": "smartypants", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Smartypants.jpg" + }, + { + "SHOW": "Adventuring Academy", + "URL": "https://www.dropout.tv/adventuring-academy", + "LINK": "adventuring-academy", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Adventuring_Academy.jpg" + }, + { + "SHOW": "Dimension 20", + "URL": "https://www.dropout.tv/dimension-20", + "LINK": "dimension-20", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20.jpg" + }, + { + "SHOW": "Dimension 20 Live", + "URL": "https://www.dropout.tv/dimension-20-live", + "LINK": "dimension-20-live", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Live.jpg" + }, + { + "SHOW": "Fatal Decision", + "URL": "https://www.dropout.tv/fatal-decision", + "LINK": "fatal-decision", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Fatal_Decision.jpg" + }, + { + "SHOW": "Um, Actually", + "URL": "https://www.dropout.tv/um-actually", + "LINK": "um-actually", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Um_Actually.jpg" + }, + { + "SHOW": "Very Important People", + "URL": "https://www.dropout.tv/very-important-people", + "LINK": "very-important-people", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Very_Important_People.jpg" + }, + { + "SHOW": "Dimension 20: Titan Takedown", + "URL": "https://www.dropout.tv/dimension-20-titan-takedown", + "LINK": "dimension-20-titan-takedown", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Titan_Takedown.jpg" + }, + { + "SHOW": "Make Some Noise", + "URL": "https://www.dropout.tv/make-some-noise", + "LINK": "make-some-noise", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Make_Some_Noise.jpg" + }, + { + "SHOW": "Dimension 20: Dungeons and Drag Queens", + "URL": "https://www.dropout.tv/dimension-20-dungeons-and-drag-queens", + "LINK": "dimension-20-dungeons-and-drag-queens", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Dungeons_and_Drag_Queens.jpg" + }, + { + "SHOW": "Nobody Asked", + "URL": "https://www.dropout.tv/nobody-asked", + "LINK": "nobody-asked", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Nobody_Asked.jpg" + }, + { + "SHOW": "Game Changer Animated", + "URL": "https://www.dropout.tv/game-changer-animated", + "LINK": "game-changer-animated", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Game_Changer_Animated.jpg" + }, + { + "SHOW": "Dimension 20 Live: Time Quangle", + "URL": "https://www.dropout.tv/dimension-20-live-time-quangle", + "LINK": "dimension-20-live-time-quangle", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Live_Time_Quangle.jpg" + }, + { + "SHOW": "Gastronauts", + "URL": "https://www.dropout.tv/gastronauts", + "LINK": "gastronauts", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Gastronauts.png" + }, + { + "SHOW": "Dimension 20: Misfits and Magic", + "URL": "https://www.dropout.tv/dimension-20-misfits-and-magic", + "LINK": "dimension-20-misfits-and-magic", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Misfits_and_Magic.jpg" + }, + { + "SHOW": "Breaking News: No Laugh Newsroom", + "URL": "https://www.dropout.tv/breaking-news-no-laugh-newsroom", + "LINK": "breaking-news-no-laugh-newsroom", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Breaking_News_No_Laugh_Newsroom.jpg" + }, + { + "SHOW": "Mon\u00e9t's Slumber Party", + "URL": "https://www.dropout.tv/monet-s-slumber-party", + "LINK": "monet-s-slumber-party", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Monts_Slumber_Party.jpg" + }, + { + "SHOW": "Dimension 20: Never Stop Blowing Up", + "URL": "https://www.dropout.tv/dimension-20-never-stop-blowing-up", + "LINK": "dimension-20-never-stop-blowing-up", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Never_Stop_Blowing_Up.jpg" + }, + { + "SHOW": "Thousandaires", + "URL": "https://www.dropout.tv/thousandaires", + "LINK": "thousandaires", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Thousandaires.jpg" + }, + { + "SHOW": "Dimension 20: Fantasy High Junior Year", + "URL": "https://www.dropout.tv/dimension-20-fantasy-high-junior-year", + "LINK": "dimension-20-fantasy-high-junior-year", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Fantasy_High_Junior_Year.jpg" + }, + { + "SHOW": "Dimension 20: Burrow's End", + "URL": "https://www.dropout.tv/dimension-20-burrow-s-end", + "LINK": "dimension-20-burrow-s-end", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Burrows_End.jpg" + }, + { + "SHOW": "Play It By Ear", + "URL": "https://www.dropout.tv/play-it-by-ear", + "LINK": "play-it-by-ear", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Play_It_By_Ear.jpg" + }, + { + "SHOW": "Dimension 20: Mentopolis", + "URL": "https://www.dropout.tv/dimension-20-mentopolis", + "LINK": "dimension-20-mentopolis", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Mentopolis.jpg" + }, + { + "SHOW": "Dimension 20: The Ravening War", + "URL": "https://www.dropout.tv/dimension-20-the-ravening-war", + "LINK": "dimension-20-the-ravening-war", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_The_Ravening_War.jpg" + }, + { + "SHOW": "Game Changer: Battle Royale", + "URL": "https://www.dropout.tv/game-changer-battle-royale", + "LINK": "game-changer-battle-royale", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Game_Changer_Battle_Royale.jpg" + }, + { + "SHOW": "Dimension 20: Neverafter", + "URL": "https://www.dropout.tv/dimension-20-neverafter", + "LINK": "dimension-20-neverafter", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Neverafter.jpg" + }, + { + "SHOW": "Dimension 20: A Court of Fey & Flowers", + "URL": "https://www.dropout.tv/dimension-20-a-court-of-fey-flowers", + "LINK": "dimension-20-a-court-of-fey-flowers", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_A_Court_of_Fey__Flowers.jpg" + }, + { + "SHOW": "Dimension 20: Fantasy High", + "URL": "https://www.dropout.tv/dimension-20-fantasy-high", + "LINK": "dimension-20-fantasy-high", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Fantasy_High.jpg" + }, + { + "SHOW": "Dimension 20: A Crown Of Candy", + "URL": "https://www.dropout.tv/dimension-20-a-crown-of-candy", + "LINK": "dimension-20-a-crown-of-candy", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_A_Crown_Of_Candy.jpg" + }, + { + "SHOW": "Dimension 20: Coffin Run", + "URL": "https://www.dropout.tv/dimension-20-coffin-run", + "LINK": "dimension-20-coffin-run", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Coffin_Run.jpg" + }, + { + "SHOW": "Total Forgiveness", + "URL": "https://www.dropout.tv/total-forgiveness", + "LINK": "total-forgiveness", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Total_Forgiveness.jpg" + }, + { + "SHOW": "Dimension 20 [Audio Only]", + "URL": "https://www.dropout.tv/dimension-20-audio-only", + "LINK": "dimension-20-audio-only", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Audio_Only.jpg" + }, + { + "SHOW": "Dimension 20: A Starstruck Odyssey", + "URL": "https://www.dropout.tv/dimension-20-a-starstruck-odyssey", + "LINK": "dimension-20-a-starstruck-odyssey", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_A_Starstruck_Odyssey.jpg" + }, + { + "SHOW": "Bad Internet", + "URL": "https://www.dropout.tv/bad-internet", + "LINK": "bad-internet", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Bad_Internet.jpg" + }, + { + "SHOW": "Dimension 20: Shriek Week", + "URL": "https://www.dropout.tv/dimension-20-shriek-week", + "LINK": "dimension-20-shriek-week", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Shriek_Week.jpg" + }, + { + "SHOW": "Dimension 20 Animated", + "URL": "https://www.dropout.tv/dimension-20-animated", + "LINK": "dimension-20-animated", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Animated.png" + }, + { + "SHOW": "Dimension 20: The Seven", + "URL": "https://www.dropout.tv/dimension-20-the-seven", + "LINK": "dimension-20-the-seven", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_The_Seven.jpg" + }, + { + "SHOW": "Dimension 20: Mice & Murder", + "URL": "https://www.dropout.tv/mice-murder", + "LINK": "mice-murder", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Mice__Murder.jpg" + }, + { + "SHOW": "Troopers: Animated", + "URL": "https://www.dropout.tv/troopers-animated", + "LINK": "troopers-animated", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Troopers_Animated.jpg" + }, + { + "SHOW": "Erotic Clubhouse", + "URL": "https://www.dropout.tv/erotic-clubhouse", + "LINK": "erotic-clubhouse", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Erotic_Clubhouse.jpg" + }, + { + "SHOW": "Dimension 20: The Unsleeping City", + "URL": "https://www.dropout.tv/dimension-20-the-unsleeping-city", + "LINK": "dimension-20-the-unsleeping-city", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_The_Unsleeping_City.jpg" + }, + { + "SHOW": "Fantasy High: Extra Credit", + "URL": "https://www.dropout.tv/fantasy-high-extra-credit", + "LINK": "fantasy-high-extra-credit", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Fantasy_High_Extra_Credit.jpg" + }, + { + "SHOW": "Dimension 20: Escape From the Bloodkeep", + "URL": "https://www.dropout.tv/dimension-20-escape-from-the-bloodkeep", + "LINK": "dimension-20-escape-from-the-bloodkeep", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Escape_From_the_Bloodkeep.jpg" + }, + { + "SHOW": "Dimension 20: Tiny Heist", + "URL": "https://www.dropout.tv/dimension-20-tiny-heist", + "LINK": "dimension-20-tiny-heist", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Tiny_Heist.jpg" + }, + { + "SHOW": "Dimension 20: Leviathan", + "URL": "https://www.dropout.tv/dimension-20-leviathan", + "LINK": "dimension-20-leviathan", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Dimension_20_Leviathan.jpg" + }, + { + "SHOW": "Ultramechatron Team Go!", + "URL": "https://www.dropout.tv/ultramechatron-team-go-1", + "LINK": "ultramechatron-team-go-1", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Ultramechatron_Team_Go.jpg" + }, + { + "SHOW": "Total Forgiveness: Early Payoff", + "URL": "https://www.dropout.tv/total-forgiveness-early-payoff", + "LINK": "total-forgiveness-early-payoff", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Total_Forgiveness_Early_Payoff.jpg" + }, + { + "SHOW": "Troopers", + "URL": "https://www.dropout.tv/troopers-1", + "LINK": "troopers-1", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Troopers.jpg" + }, + { + "SHOW": "WTF 101", + "URL": "https://www.dropout.tv/wtf-101", + "LINK": "wtf-101", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/WTF_101.jpg" + }, + { + "SHOW": "What the Facts 101", + "URL": "https://www.dropout.tv/what-the-facts-101", + "LINK": "what-the-facts-101", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/What_the_Facts_101.jpg" + }, + { + "SHOW": "Cartoon Hell", + "URL": "https://www.dropout.tv/cartoon-hell", + "LINK": "cartoon-hell", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Cartoon_Hell.jpg" + }, + { + "SHOW": "Paranoia", + "URL": "https://www.dropout.tv/paranoia", + "LINK": "paranoia", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Paranoia.jpg" + }, + { + "SHOW": "Where in the Eff is Sarah Cincinnati", + "URL": "https://www.dropout.tv/where-in-the-eff-is-sarah-cincinnati", + "LINK": "where-in-the-eff-is-sarah-cincinnati", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Where_in_the_Eff_is_Sarah_Cincinnati.jpg" + }, + { + "SHOW": "Gods of Food", + "URL": "https://www.dropout.tv/gods-of-food", + "LINK": "gods-of-food", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Gods_of_Food.jpg" + }, + { + "SHOW": "Kingpin Katie", + "URL": "https://www.dropout.tv/kingpin-katie", + "LINK": "kingpin-katie", + "POSTER": "/Users/tyler/Documents/GitHub/syllabus/app/data/posters/Kingpin_Katie.jpg" + } +] \ No newline at end of file diff --git a/app/data/logs/syllabus.log b/app/data/logs/syllabus.log new file mode 100644 index 0000000..1ba74e9 --- /dev/null +++ b/app/data/logs/syllabus.log @@ -0,0 +1,45 @@ +2025-07-26 06:43:39,675 - INFO - request_client=127.0.0.1:61250, request_method=GET, request_url=http://127.0.0.1:8000/, status_code=500 +2025-07-26 06:43:39,782 - INFO - request_client=127.0.0.1:61250, request_method=GET, request_url=http://127.0.0.1:8000/favicon.ico, status_code=404 +2025-07-26 06:43:44,039 - INFO - request_client=127.0.0.1:61250, request_method=GET, request_url=http://127.0.0.1:8000/docs, status_code=200 +2025-07-26 06:43:44,297 - INFO - request_client=127.0.0.1:61250, request_method=GET, request_url=http://127.0.0.1:8000/openapi.json, status_code=200 +2025-07-26 06:43:49,749 - INFO - request_client=127.0.0.1:61258, request_method=GET, request_url=http://127.0.0.1:8000/docs, status_code=200 +2025-07-26 06:43:49,811 - INFO - request_client=127.0.0.1:61258, request_method=GET, request_url=http://127.0.0.1:8000/openapi.json, status_code=200 +2025-07-26 07:01:30,665 - INFO - request_client=127.0.0.1:62205, request_method=GET, request_url=http://127.0.0.1:8000/dropout, status_code=500 +2025-07-26 07:13:42,415 - INFO - request_client=127.0.0.1:62742, request_method=GET, request_url=http://127.0.0.1:8000/dropout/series, status_code=200 +2025-07-26 07:13:59,487 - INFO - request_client=127.0.0.1:62744, request_method=GET, request_url=http://127.0.0.1:8000/dropout/update, status_code=500 +2025-07-26 07:16:10,070 - INFO - request_client=127.0.0.1:62896, request_method=GET, request_url=http://127.0.0.1:8000/dropout/series, status_code=200 +2025-07-26 07:16:17,027 - INFO - request_client=127.0.0.1:62896, request_method=GET, request_url=http://127.0.0.1:8000/dropout/series, status_code=200 +2025-07-26 07:16:52,735 - INFO - request_client=127.0.0.1:62997, request_method=GET, request_url=http://127.0.0.1:8000/dropout/series, status_code=200 +2025-07-26 07:17:39,236 - INFO - request_client=127.0.0.1:63017, request_method=GET, request_url=http://127.0.0.1:8000/dropout/series, status_code=200 +2025-07-26 07:18:32,238 - INFO - request_client=127.0.0.1:63094, request_method=GET, request_url=http://127.0.0.1:8000/.well-known/appspecific/com.chrome.devtools.json, status_code=404 +2025-07-26 07:20:15,403 - INFO - request_client=127.0.0.1:63209, request_method=GET, request_url=http://127.0.0.1:8000/dropout/series, status_code=200 +2025-07-26 07:20:39,381 - INFO - request_client=127.0.0.1:63215, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-26 07:22:18,292 - INFO - request_client=127.0.0.1:63367, request_method=GET, request_url=http://127.0.0.1:8000/dropout/series, status_code=200 +2025-07-26 07:23:42,194 - INFO - request_client=127.0.0.1:63467, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-26 07:25:06,534 - INFO - request_client=127.0.0.1:63502, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-26 07:26:26,274 - INFO - request_client=127.0.0.1:63508, request_method=GET, request_url=http://127.0.0.1:8000/dropout/update, status_code=200 +2025-07-26 07:26:31,503 - INFO - request_client=127.0.0.1:63510, request_method=GET, request_url=http://127.0.0.1:8000/dropout/series, status_code=200 +2025-07-26 07:27:44,038 - INFO - request_client=127.0.0.1:63534, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-26 07:28:11,207 - INFO - request_client=127.0.0.1:63544, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-26 07:28:17,562 - INFO - request_client=127.0.0.1:63551, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-26 07:28:21,421 - INFO - request_client=127.0.0.1:63556, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-26 07:31:17,961 - INFO - request_client=127.0.0.1:63938, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-26 07:33:19,790 - INFO - request_client=127.0.0.1:63978, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-26 07:33:32,260 - INFO - request_client=127.0.0.1:64042, request_method=GET, request_url=http://127.0.0.1:8000/dropout/series, status_code=200 +2025-07-26 07:34:21,229 - INFO - request_client=127.0.0.1:64131, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-26 08:06:05,007 - INFO - request_client=127.0.0.1:65325, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-27 13:11:26,063 - INFO - request_client=127.0.0.1:54260, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-27 13:15:30,578 - INFO - request_client=127.0.0.1:54329, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-27 13:16:10,175 - INFO - request_client=127.0.0.1:54340, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-27 13:16:10,251 - INFO - request_client=127.0.0.1:54340, request_method=GET, request_url=http://localhost:8000/favicon.ico, status_code=404 +2025-07-27 13:16:54,705 - INFO - request_client=127.0.0.1:54358, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-27 13:17:51,810 - INFO - request_client=127.0.0.1:54370, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-27 13:18:27,819 - INFO - request_client=127.0.0.1:54382, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-27 13:18:29,264 - INFO - request_client=127.0.0.1:54382, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-27 13:18:32,449 - INFO - request_client=127.0.0.1:54382, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-27 13:18:33,023 - INFO - request_client=127.0.0.1:54382, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-27 13:18:33,608 - INFO - request_client=127.0.0.1:54382, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-27 13:28:36,283 - INFO - request_client=127.0.0.1:54475, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-27 17:55:59,835 - INFO - request_client=127.0.0.1:60472, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-27 19:20:51,674 - INFO - request_client=127.0.0.1:49204, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 +2025-07-27 20:23:38,460 - INFO - request_client=127.0.0.1:50407, request_method=GET, request_url=http://localhost:8000/dropout/series, status_code=200 diff --git a/app/data/posters/Adventuring_Academy.jpg b/app/data/posters/Adventuring_Academy.jpg new file mode 100644 index 0000000..9572088 Binary files /dev/null and b/app/data/posters/Adventuring_Academy.jpg differ diff --git a/app/data/posters/Bad_Internet.jpg b/app/data/posters/Bad_Internet.jpg new file mode 100644 index 0000000..da91695 Binary files /dev/null and b/app/data/posters/Bad_Internet.jpg differ diff --git a/app/data/posters/Breaking_News_No_Laugh_Newsroom.jpg b/app/data/posters/Breaking_News_No_Laugh_Newsroom.jpg new file mode 100644 index 0000000..ca2e33a Binary files /dev/null and b/app/data/posters/Breaking_News_No_Laugh_Newsroom.jpg differ diff --git a/app/data/posters/Cartoon_Hell.jpg b/app/data/posters/Cartoon_Hell.jpg new file mode 100644 index 0000000..0b566d5 Binary files /dev/null and b/app/data/posters/Cartoon_Hell.jpg differ diff --git a/app/data/posters/Dimension_20.jpg b/app/data/posters/Dimension_20.jpg new file mode 100644 index 0000000..53a1ae3 Binary files /dev/null and b/app/data/posters/Dimension_20.jpg differ diff --git a/app/data/posters/Dimension_20_A_Court_of_Fey__Flowers.jpg b/app/data/posters/Dimension_20_A_Court_of_Fey__Flowers.jpg new file mode 100644 index 0000000..8414186 Binary files /dev/null and b/app/data/posters/Dimension_20_A_Court_of_Fey__Flowers.jpg differ diff --git a/app/data/posters/Dimension_20_A_Crown_Of_Candy.jpg b/app/data/posters/Dimension_20_A_Crown_Of_Candy.jpg new file mode 100644 index 0000000..9489ff3 Binary files /dev/null and b/app/data/posters/Dimension_20_A_Crown_Of_Candy.jpg differ diff --git a/app/data/posters/Dimension_20_A_Starstruck_Odyssey.jpg b/app/data/posters/Dimension_20_A_Starstruck_Odyssey.jpg new file mode 100644 index 0000000..11c418f Binary files /dev/null and b/app/data/posters/Dimension_20_A_Starstruck_Odyssey.jpg differ diff --git a/app/data/posters/Dimension_20_Animated.png b/app/data/posters/Dimension_20_Animated.png new file mode 100644 index 0000000..cafa770 Binary files /dev/null and b/app/data/posters/Dimension_20_Animated.png differ diff --git a/app/data/posters/Dimension_20_Audio_Only.jpg b/app/data/posters/Dimension_20_Audio_Only.jpg new file mode 100644 index 0000000..ef44433 Binary files /dev/null and b/app/data/posters/Dimension_20_Audio_Only.jpg differ diff --git a/app/data/posters/Dimension_20_Burrows_End.jpg b/app/data/posters/Dimension_20_Burrows_End.jpg new file mode 100644 index 0000000..6a307f7 Binary files /dev/null and b/app/data/posters/Dimension_20_Burrows_End.jpg differ diff --git a/app/data/posters/Dimension_20_Cloudward_Ho.jpg b/app/data/posters/Dimension_20_Cloudward_Ho.jpg new file mode 100644 index 0000000..713b009 Binary files /dev/null and b/app/data/posters/Dimension_20_Cloudward_Ho.jpg differ diff --git a/app/data/posters/Dimension_20_Coffin_Run.jpg b/app/data/posters/Dimension_20_Coffin_Run.jpg new file mode 100644 index 0000000..75884e5 Binary files /dev/null and b/app/data/posters/Dimension_20_Coffin_Run.jpg differ diff --git a/app/data/posters/Dimension_20_Dungeons_and_Drag_Queens.jpg b/app/data/posters/Dimension_20_Dungeons_and_Drag_Queens.jpg new file mode 100644 index 0000000..057e13a Binary files /dev/null and b/app/data/posters/Dimension_20_Dungeons_and_Drag_Queens.jpg differ diff --git a/app/data/posters/Dimension_20_Escape_From_the_Bloodkeep.jpg b/app/data/posters/Dimension_20_Escape_From_the_Bloodkeep.jpg new file mode 100644 index 0000000..e86efae Binary files /dev/null and b/app/data/posters/Dimension_20_Escape_From_the_Bloodkeep.jpg differ diff --git a/app/data/posters/Dimension_20_Fantasy_High.jpg b/app/data/posters/Dimension_20_Fantasy_High.jpg new file mode 100644 index 0000000..ee36ec8 Binary files /dev/null and b/app/data/posters/Dimension_20_Fantasy_High.jpg differ diff --git a/app/data/posters/Dimension_20_Fantasy_High_Junior_Year.jpg b/app/data/posters/Dimension_20_Fantasy_High_Junior_Year.jpg new file mode 100644 index 0000000..dd7ecc6 Binary files /dev/null and b/app/data/posters/Dimension_20_Fantasy_High_Junior_Year.jpg differ diff --git a/app/data/posters/Dimension_20_Leviathan.jpg b/app/data/posters/Dimension_20_Leviathan.jpg new file mode 100644 index 0000000..aeff968 Binary files /dev/null and b/app/data/posters/Dimension_20_Leviathan.jpg differ diff --git a/app/data/posters/Dimension_20_Live.jpg b/app/data/posters/Dimension_20_Live.jpg new file mode 100644 index 0000000..57fd485 Binary files /dev/null and b/app/data/posters/Dimension_20_Live.jpg differ diff --git a/app/data/posters/Dimension_20_Live_Time_Quangle.jpg b/app/data/posters/Dimension_20_Live_Time_Quangle.jpg new file mode 100644 index 0000000..e0a9ed1 Binary files /dev/null and b/app/data/posters/Dimension_20_Live_Time_Quangle.jpg differ diff --git a/app/data/posters/Dimension_20_Mentopolis.jpg b/app/data/posters/Dimension_20_Mentopolis.jpg new file mode 100644 index 0000000..2dd9f23 Binary files /dev/null and b/app/data/posters/Dimension_20_Mentopolis.jpg differ diff --git a/app/data/posters/Dimension_20_Mice__Murder.jpg b/app/data/posters/Dimension_20_Mice__Murder.jpg new file mode 100644 index 0000000..2b8d6a1 Binary files /dev/null and b/app/data/posters/Dimension_20_Mice__Murder.jpg differ diff --git a/app/data/posters/Dimension_20_Misfits_and_Magic.jpg b/app/data/posters/Dimension_20_Misfits_and_Magic.jpg new file mode 100644 index 0000000..5bf7255 Binary files /dev/null and b/app/data/posters/Dimension_20_Misfits_and_Magic.jpg differ diff --git a/app/data/posters/Dimension_20_Never_Stop_Blowing_Up.jpg b/app/data/posters/Dimension_20_Never_Stop_Blowing_Up.jpg new file mode 100644 index 0000000..4198106 Binary files /dev/null and b/app/data/posters/Dimension_20_Never_Stop_Blowing_Up.jpg differ diff --git a/app/data/posters/Dimension_20_Neverafter.jpg b/app/data/posters/Dimension_20_Neverafter.jpg new file mode 100644 index 0000000..7850394 Binary files /dev/null and b/app/data/posters/Dimension_20_Neverafter.jpg differ diff --git a/app/data/posters/Dimension_20_Shriek_Week.jpg b/app/data/posters/Dimension_20_Shriek_Week.jpg new file mode 100644 index 0000000..7a7b5cb Binary files /dev/null and b/app/data/posters/Dimension_20_Shriek_Week.jpg differ diff --git a/app/data/posters/Dimension_20_The_Ravening_War.jpg b/app/data/posters/Dimension_20_The_Ravening_War.jpg new file mode 100644 index 0000000..9a51a3e Binary files /dev/null and b/app/data/posters/Dimension_20_The_Ravening_War.jpg differ diff --git a/app/data/posters/Dimension_20_The_Seven.jpg b/app/data/posters/Dimension_20_The_Seven.jpg new file mode 100644 index 0000000..a0ca49f Binary files /dev/null and b/app/data/posters/Dimension_20_The_Seven.jpg differ diff --git a/app/data/posters/Dimension_20_The_Unsleeping_City.jpg b/app/data/posters/Dimension_20_The_Unsleeping_City.jpg new file mode 100644 index 0000000..c0b0a7e Binary files /dev/null and b/app/data/posters/Dimension_20_The_Unsleeping_City.jpg differ diff --git a/app/data/posters/Dimension_20_Tiny_Heist.jpg b/app/data/posters/Dimension_20_Tiny_Heist.jpg new file mode 100644 index 0000000..e1362b5 Binary files /dev/null and b/app/data/posters/Dimension_20_Tiny_Heist.jpg differ diff --git a/app/data/posters/Dimension_20_Titan_Takedown.jpg b/app/data/posters/Dimension_20_Titan_Takedown.jpg new file mode 100644 index 0000000..484ecfa Binary files /dev/null and b/app/data/posters/Dimension_20_Titan_Takedown.jpg differ diff --git a/app/data/posters/Dimension_20s_Adventuring_Party.jpg b/app/data/posters/Dimension_20s_Adventuring_Party.jpg new file mode 100644 index 0000000..77c497a Binary files /dev/null and b/app/data/posters/Dimension_20s_Adventuring_Party.jpg differ diff --git a/app/data/posters/Dirty_Laundry.jpg b/app/data/posters/Dirty_Laundry.jpg new file mode 100644 index 0000000..3c1f789 Binary files /dev/null and b/app/data/posters/Dirty_Laundry.jpg differ diff --git a/app/data/posters/Erotic_Clubhouse.jpg b/app/data/posters/Erotic_Clubhouse.jpg new file mode 100644 index 0000000..ceeded2 Binary files /dev/null and b/app/data/posters/Erotic_Clubhouse.jpg differ diff --git a/app/data/posters/Fantasy_High_Extra_Credit.jpg b/app/data/posters/Fantasy_High_Extra_Credit.jpg new file mode 100644 index 0000000..6fbe1f4 Binary files /dev/null and b/app/data/posters/Fantasy_High_Extra_Credit.jpg differ diff --git a/app/data/posters/Fatal_Decision.jpg b/app/data/posters/Fatal_Decision.jpg new file mode 100644 index 0000000..be49691 Binary files /dev/null and b/app/data/posters/Fatal_Decision.jpg differ diff --git a/app/data/posters/Game_Changer.jpg b/app/data/posters/Game_Changer.jpg new file mode 100644 index 0000000..86d1028 Binary files /dev/null and b/app/data/posters/Game_Changer.jpg differ diff --git a/app/data/posters/Game_Changer_Animated.jpg b/app/data/posters/Game_Changer_Animated.jpg new file mode 100644 index 0000000..b658a3c Binary files /dev/null and b/app/data/posters/Game_Changer_Animated.jpg differ diff --git a/app/data/posters/Game_Changer_Battle_Royale.jpg b/app/data/posters/Game_Changer_Battle_Royale.jpg new file mode 100644 index 0000000..67e5d6e Binary files /dev/null and b/app/data/posters/Game_Changer_Battle_Royale.jpg differ diff --git a/app/data/posters/Gastronauts.png b/app/data/posters/Gastronauts.png new file mode 100644 index 0000000..eca6a61 Binary files /dev/null and b/app/data/posters/Gastronauts.png differ diff --git a/app/data/posters/Gods_of_Food.jpg b/app/data/posters/Gods_of_Food.jpg new file mode 100644 index 0000000..59b23b4 Binary files /dev/null and b/app/data/posters/Gods_of_Food.jpg differ diff --git a/app/data/posters/Kingpin_Katie.jpg b/app/data/posters/Kingpin_Katie.jpg new file mode 100644 index 0000000..7ee5803 Binary files /dev/null and b/app/data/posters/Kingpin_Katie.jpg differ diff --git a/app/data/posters/Make_Some_Noise.jpg b/app/data/posters/Make_Some_Noise.jpg new file mode 100644 index 0000000..d09b54e Binary files /dev/null and b/app/data/posters/Make_Some_Noise.jpg differ diff --git a/app/data/posters/Monts_Slumber_Party.jpg b/app/data/posters/Monts_Slumber_Party.jpg new file mode 100644 index 0000000..f1bac72 Binary files /dev/null and b/app/data/posters/Monts_Slumber_Party.jpg differ diff --git a/app/data/posters/Nobody_Asked.jpg b/app/data/posters/Nobody_Asked.jpg new file mode 100644 index 0000000..afed26f Binary files /dev/null and b/app/data/posters/Nobody_Asked.jpg differ diff --git a/app/data/posters/Paranoia.jpg b/app/data/posters/Paranoia.jpg new file mode 100644 index 0000000..13c6a82 Binary files /dev/null and b/app/data/posters/Paranoia.jpg differ diff --git a/app/data/posters/Parlor_Room.jpg b/app/data/posters/Parlor_Room.jpg new file mode 100644 index 0000000..18b71b2 Binary files /dev/null and b/app/data/posters/Parlor_Room.jpg differ diff --git a/app/data/posters/Play_It_By_Ear.jpg b/app/data/posters/Play_It_By_Ear.jpg new file mode 100644 index 0000000..2813885 Binary files /dev/null and b/app/data/posters/Play_It_By_Ear.jpg differ diff --git a/app/data/posters/Smartypants.jpg b/app/data/posters/Smartypants.jpg new file mode 100644 index 0000000..f21e344 Binary files /dev/null and b/app/data/posters/Smartypants.jpg differ diff --git a/app/data/posters/Thousandaires.jpg b/app/data/posters/Thousandaires.jpg new file mode 100644 index 0000000..e88987a Binary files /dev/null and b/app/data/posters/Thousandaires.jpg differ diff --git a/app/data/posters/Total_Forgiveness.jpg b/app/data/posters/Total_Forgiveness.jpg new file mode 100644 index 0000000..4771f46 Binary files /dev/null and b/app/data/posters/Total_Forgiveness.jpg differ diff --git a/app/data/posters/Total_Forgiveness_Early_Payoff.jpg b/app/data/posters/Total_Forgiveness_Early_Payoff.jpg new file mode 100644 index 0000000..5c0e9f0 Binary files /dev/null and b/app/data/posters/Total_Forgiveness_Early_Payoff.jpg differ diff --git a/app/data/posters/Troopers.jpg b/app/data/posters/Troopers.jpg new file mode 100644 index 0000000..098d924 Binary files /dev/null and b/app/data/posters/Troopers.jpg differ diff --git a/app/data/posters/Troopers_Animated.jpg b/app/data/posters/Troopers_Animated.jpg new file mode 100644 index 0000000..1805ad6 Binary files /dev/null and b/app/data/posters/Troopers_Animated.jpg differ diff --git a/app/data/posters/Ultramechatron_Team_Go.jpg b/app/data/posters/Ultramechatron_Team_Go.jpg new file mode 100644 index 0000000..99f6d2f Binary files /dev/null and b/app/data/posters/Ultramechatron_Team_Go.jpg differ diff --git a/app/data/posters/Um_Actually.jpg b/app/data/posters/Um_Actually.jpg new file mode 100644 index 0000000..7585b66 Binary files /dev/null and b/app/data/posters/Um_Actually.jpg differ diff --git a/app/data/posters/Very_Important_People.jpg b/app/data/posters/Very_Important_People.jpg new file mode 100644 index 0000000..eceff11 Binary files /dev/null and b/app/data/posters/Very_Important_People.jpg differ diff --git a/app/data/posters/WTF_101.jpg b/app/data/posters/WTF_101.jpg new file mode 100644 index 0000000..a3f63c8 Binary files /dev/null and b/app/data/posters/WTF_101.jpg differ diff --git a/app/data/posters/What_the_Facts_101.jpg b/app/data/posters/What_the_Facts_101.jpg new file mode 100644 index 0000000..4b8dd3e Binary files /dev/null and b/app/data/posters/What_the_Facts_101.jpg differ diff --git a/app/data/posters/Where_in_the_Eff_is_Sarah_Cincinnati.jpg b/app/data/posters/Where_in_the_Eff_is_Sarah_Cincinnati.jpg new file mode 100644 index 0000000..8ddb4dc Binary files /dev/null and b/app/data/posters/Where_in_the_Eff_is_Sarah_Cincinnati.jpg differ diff --git a/app/download.py b/app/download.py index 7e910ac..6a7e78b 100644 --- a/app/download.py +++ b/app/download.py @@ -7,6 +7,8 @@ logger = logging.getLogger("syllabus") # Global or outer-scope tracking dictionary last_logged_percent = {} +DATA_DIR = os.getenv("DATA_DIR", "/data") + def my_hook(d): #logging hook status = d.get('status') filename = d.get('filename') @@ -70,7 +72,7 @@ class grab(): seasons = [item.replace(url+'/season:', '') for item in option_values] return seasons - def poster(url, name, force_download, save_dir='/data/posters/'): + def poster(url, name, force_download, save_dir=f'{DATA_DIR}/posters/'): # Use alt for filename if available, fallback to a generic name alt_value = name path = urlsplit(url).path @@ -114,7 +116,7 @@ class ArchiveOnlyYDL(yt_dlp.YoutubeDL): class dropout(): def archive(show, season): - with open('/data/dropout.json', 'r') as json_file: + with open(f'{DATA_DIR}/dropout.json', 'r') as json_file: url_mapping = json.load(json_file) url = next((item['URL'] for item in url_mapping if item['SHOW'] == show), None) @@ -125,8 +127,8 @@ class dropout(): dl_opts = { 'quiet': True, - 'cookiefile': '/data/dropout.cookies.txt', - 'download_archive': '/data/logs/dropout.archive.log', + 'cookiefile': f'{DATA_DIR}/dropout.cookies.txt', + 'download_archive': f'{DATA_DIR}/logs/dropout.archive.log', 'skip_download': True, # Prevent actual downloads } @@ -138,14 +140,14 @@ class dropout(): dl_opts = { 'progress_hooks': [my_hook], - 'download_archive': '/data/logs/dropout.archive.log', + 'download_archive': f'{DATA_DIR}/logs/dropout.archive.log', 'format': 'bestvideo+bestaudio/best', 'audio_quality': '256K', 'paths': { 'temp': '/temp', 'home': directory, }, - 'cookiefile': '/data/dropout.cookies.txt', + 'cookiefile': f'{DATA_DIR}/dropout.cookies.txt', 'writesubtitles': True, 'subtitleslangs': ['en'], 'outtmpl': filename_template, @@ -160,7 +162,7 @@ class dropout(): directory = f"/tv/{show}/{'Specials' if specials else f'Season {season}'}" os.makedirs(directory, exist_ok=True) - with open('/data/dropout.json', 'r') as json_file: + with open(f'{DATA_DIR}/dropout.json', 'r') as json_file: url_mapping = json.load(json_file) url = next((item['URL'] for item in url_mapping if item['SHOW'] == show), None) @@ -183,7 +185,7 @@ class dropout(): ydl_opts = { 'quiet': True, 'skip_download': True, - 'cookiefile': '/data/dropout.cookies.txt', + 'cookiefile': f'{DATA_DIR}/dropout.cookies.txt', } # Extract playlist info @@ -201,14 +203,14 @@ class dropout(): dl_opts = { 'progress_hooks': [my_hook], - 'download_archive': '/data/logs/dropout.archive.log', + 'download_archive': f'{DATA_DIR}/logs/dropout.archive.log', 'format': 'bestvideo+bestaudio/best', 'audio_quality': '256K', 'paths': { 'temp': '/temp', 'home': directory }, - 'cookiefile': '/data/dropout.cookies.txt', + 'cookiefile': f'{DATA_DIR}/dropout.cookies.txt', 'writesubtitles': True, 'subtitleslangs': ['en'], 'outtmpl': filename_template, @@ -248,7 +250,7 @@ class dropout(): # Sort the json_data by the 'SHOW' key # sorted_json_data = sorted(json_data, key=lambda x: x['SHOW']) - with open('/data/dropout.json', 'w') as json_file: + with open(f'{DATA_DIR}/dropout.json', 'w') as json_file: json.dump(json_data, json_file, indent=4) class youtube(): @@ -256,7 +258,7 @@ class youtube(): logger.info(f'message=Received download request for {url}.') dl_ops = { 'progress_hooks': [my_hook], - 'download_archive': '/data/logs/youtube.archive.log', + 'download_archive': f'{DATA_DIR}/logs/youtube.archive.log', 'paths': { 'temp': '/temp', 'home': location @@ -285,7 +287,7 @@ class youtube(): }] elif dl_ops['paths']['home'] == '/youtube': dl_ops['format'] = 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best' - dl_ops['cookiefile'] = '/data/youtube.cookies.txt' + dl_ops['cookiefile'] = f'{DATA_DIR}/youtube.cookies.txt' else: dl_ops['format'] = 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best' diff --git a/app/main.py b/app/main.py index 2171b74..0bde324 100644 --- a/app/main.py +++ b/app/main.py @@ -8,25 +8,32 @@ from typing import Optional import logging, os from logging.handlers import TimedRotatingFileHandler -# Ensure log directory exists -os.makedirs("/data/logs", exist_ok=True) +# Setup paths +DATA_DIR = os.getenv("DATA_DIR", "/data") +LOGS_DIR = os.path.join(DATA_DIR, "logs") +LOG_FILE = os.path.join(LOGS_DIR, "syllabus.log") -# Setup timed rotating logger -# log_path = "/data/logs/syllabus.log" +# Ensure logs directory exists +os.makedirs(LOGS_DIR, exist_ok=True) + +# Ensure log file exists +if not os.path.exists(LOG_FILE): + with open(LOG_FILE, "w") as f: + f.write("") + +# Set up logger logger = logging.getLogger("syllabus") logger.setLevel(logging.DEBUG) +logger.handlers = [] # Remove default handlers -# Remove any default handlers -logger.handlers = [] - -# Set up TimedRotatingFileHandler +# Use correct path here: handler = TimedRotatingFileHandler( - filename="/data/logs/syllabus.log", - when="midnight", # Rotate at midnight - interval=30, # Every 30 day - backupCount=12, # Keep last 7 logs + filename=LOG_FILE, + when="midnight", + interval=30, + backupCount=12, encoding="utf-8", - utc=False # Use UTC for time reference + utc=False ) formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") @@ -35,15 +42,13 @@ logger.addHandler(handler) # App setup app = FastAPI() -app.mount("/data", StaticFiles(directory="/data"), name="data") +app.mount("/data", StaticFiles(directory=DATA_DIR), name="data") templates = Jinja2Templates(directory="templates") loop = asyncio.get_event_loop() # Optional cache cached_data = None - - # Middleware @app.middleware("http") async def log_requests(request: Request, call_next): @@ -87,21 +92,22 @@ async def dropoutUpdate(force: bool = False): global cached_data try: download.dropout.series(force) - with open('/data/dropout.json') as f: + with open(f'{DATA_DIR}/dropout.json') as f: cached_data = json.load(f) return JSONResponse(status_code=200, content={"status": "success", "message": "Series grab complete."}) except Exception as e: return JSONResponse(status_code=500, content={"status": "error", "message": str(e)}) @app.get("/dropout/series") -async def dropoutSeries(): +async def dropout_series(): global cached_data if cached_data is None: await dropoutUpdate() - try: - return JSONResponse(content=cached_data) - except: - return JSONResponse(content={"error": "File not found"}, status_code=404) + + if cached_data is None: + raise JSONResponse(status_code=404, detail="No data available") + + return cached_data # FastAPI auto-converts to JSON async def get_show_data(show: str, force: bool = False): global cached_data diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/frontend/.vscode/extensions.json b/frontend/.vscode/extensions.json new file mode 100644 index 0000000..bdef820 --- /dev/null +++ b/frontend/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["svelte.svelte-vscode"] +} diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..382941e --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,47 @@ +# Svelte + Vite + +This template should help get you started developing with Svelte in Vite. + +## Recommended IDE Setup + +[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). + +## Need an official Svelte framework? + +Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more. + +## Technical considerations + +**Why use this over SvelteKit?** + +- It brings its own routing solution which might not be preferable for some users. +- It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app. + +This template contains as little as possible to get started with Vite + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project. + +Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate. + +**Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?** + +Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace, while also adding `svelte` and `vite/client` type information. + +**Why include `.vscode/extensions.json`?** + +Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project. + +**Why enable `checkJs` in the JS template?** + +It is likely that most cases of changing variable types in runtime are likely to be accidental, rather than deliberate. This provides advanced typechecking out of the box. Should you like to take advantage of the dynamically-typed nature of JavaScript, it is trivial to change the configuration. + +**Why is HMR not preserving my local component state?** + +HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/sveltejs/svelte-hmr/tree/master/packages/svelte-hmr#preservation-of-local-state). + +If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR. + +```js +// store.js +// An extremely simple external store +import { writable } from 'svelte/store' +export default writable(0) +``` diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..ca2fa62 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + Syllabus + + +
+ + + diff --git a/frontend/jsconfig.json b/frontend/jsconfig.json new file mode 100644 index 0000000..5696a2d --- /dev/null +++ b/frontend/jsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + "moduleResolution": "bundler", + "target": "ESNext", + "module": "ESNext", + /** + * svelte-preprocess cannot figure out whether you have + * a value or a type, so tell TypeScript to enforce using + * `import type` instead of `import` for Types. + */ + "verbatimModuleSyntax": true, + "isolatedModules": true, + "resolveJsonModule": true, + /** + * To have warnings / errors of the Svelte compiler at the + * correct position, enable source maps by default. + */ + "sourceMap": true, + "esModuleInterop": true, + "skipLibCheck": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable this if you'd like to use dynamic types. + */ + "checkJs": true + }, + /** + * Use global.d.ts instead of compilerOptions.types + * to avoid limiting type declarations. + */ + "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"] +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..d7f3df2 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,1310 @@ +{ + "name": "frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.0.0", + "dependencies": { + "svelte-boxicons": "^1.0.4" + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^6.0.0", + "svelte": "^5.35.5", + "vite": "^7.0.4" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz", + "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz", + "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz", + "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz", + "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz", + "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz", + "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz", + "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz", + "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz", + "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz", + "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz", + "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz", + "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz", + "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz", + "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz", + "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz", + "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz", + "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz", + "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz", + "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz", + "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz", + "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz", + "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz", + "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz", + "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz", + "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz", + "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.45.1.tgz", + "integrity": "sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.45.1.tgz", + "integrity": "sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.45.1.tgz", + "integrity": "sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.45.1.tgz", + "integrity": "sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.45.1.tgz", + "integrity": "sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.45.1.tgz", + "integrity": "sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.45.1.tgz", + "integrity": "sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.45.1.tgz", + "integrity": "sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.45.1.tgz", + "integrity": "sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.45.1.tgz", + "integrity": "sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.45.1.tgz", + "integrity": "sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.45.1.tgz", + "integrity": "sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.45.1.tgz", + "integrity": "sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.45.1.tgz", + "integrity": "sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.45.1.tgz", + "integrity": "sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.45.1.tgz", + "integrity": "sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.45.1.tgz", + "integrity": "sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.45.1.tgz", + "integrity": "sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.45.1.tgz", + "integrity": "sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.45.1.tgz", + "integrity": "sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sveltejs/acorn-typescript": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz", + "integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8.9.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-6.1.0.tgz", + "integrity": "sha512-+U6lz1wvGEG/BvQyL4z/flyNdQ9xDNv5vrh+vWBWTHaebqT0c9RNggpZTo/XSPoHsSCWBlYaTlRX8pZ9GATXCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0-next.1", + "debug": "^4.4.1", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.17", + "vitefu": "^1.1.1" + }, + "engines": { + "node": "^20.19 || ^22.12 || >=24" + }, + "peerDependencies": { + "svelte": "^5.0.0", + "vite": "^6.3.0 || ^7.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-5.0.0.tgz", + "integrity": "sha512-iwQ8Z4ET6ZFSt/gC+tVfcsSBHwsqc6RumSaiLUkAurW3BCpJam65cmHw0oOlDMTO0u+PZi9hilBRYN+LZNHTUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.1" + }, + "engines": { + "node": "^20.19 || ^22.12 || >=24" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^6.0.0-next.0", + "svelte": "^5.0.0", + "vite": "^6.3.0 || ^7.0.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esbuild": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz", + "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.8", + "@esbuild/android-arm": "0.25.8", + "@esbuild/android-arm64": "0.25.8", + "@esbuild/android-x64": "0.25.8", + "@esbuild/darwin-arm64": "0.25.8", + "@esbuild/darwin-x64": "0.25.8", + "@esbuild/freebsd-arm64": "0.25.8", + "@esbuild/freebsd-x64": "0.25.8", + "@esbuild/linux-arm": "0.25.8", + "@esbuild/linux-arm64": "0.25.8", + "@esbuild/linux-ia32": "0.25.8", + "@esbuild/linux-loong64": "0.25.8", + "@esbuild/linux-mips64el": "0.25.8", + "@esbuild/linux-ppc64": "0.25.8", + "@esbuild/linux-riscv64": "0.25.8", + "@esbuild/linux-s390x": "0.25.8", + "@esbuild/linux-x64": "0.25.8", + "@esbuild/netbsd-arm64": "0.25.8", + "@esbuild/netbsd-x64": "0.25.8", + "@esbuild/openbsd-arm64": "0.25.8", + "@esbuild/openbsd-x64": "0.25.8", + "@esbuild/openharmony-arm64": "0.25.8", + "@esbuild/sunos-x64": "0.25.8", + "@esbuild/win32-arm64": "0.25.8", + "@esbuild/win32-ia32": "0.25.8", + "@esbuild/win32-x64": "0.25.8" + } + }, + "node_modules/esm-env": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", + "license": "MIT" + }, + "node_modules/esrap": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.1.0.tgz", + "integrity": "sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/is-reference": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.6" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.45.1.tgz", + "integrity": "sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.45.1", + "@rollup/rollup-android-arm64": "4.45.1", + "@rollup/rollup-darwin-arm64": "4.45.1", + "@rollup/rollup-darwin-x64": "4.45.1", + "@rollup/rollup-freebsd-arm64": "4.45.1", + "@rollup/rollup-freebsd-x64": "4.45.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.45.1", + "@rollup/rollup-linux-arm-musleabihf": "4.45.1", + "@rollup/rollup-linux-arm64-gnu": "4.45.1", + "@rollup/rollup-linux-arm64-musl": "4.45.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.45.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.45.1", + "@rollup/rollup-linux-riscv64-gnu": "4.45.1", + "@rollup/rollup-linux-riscv64-musl": "4.45.1", + "@rollup/rollup-linux-s390x-gnu": "4.45.1", + "@rollup/rollup-linux-x64-gnu": "4.45.1", + "@rollup/rollup-linux-x64-musl": "4.45.1", + "@rollup/rollup-win32-arm64-msvc": "4.45.1", + "@rollup/rollup-win32-ia32-msvc": "4.45.1", + "@rollup/rollup-win32-x64-msvc": "4.45.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/svelte": { + "version": "5.36.17", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.36.17.tgz", + "integrity": "sha512-yxJVoHo3Km6+BlQLO3MXrhpZ8eeBuy/UOvEKLkmyQ8QmMFIkL0Hxs+DdmHBgAJazkc9o91TkTPgP6CvGenU1Ig==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/estree": "^1.0.5", + "acorn": "^8.12.1", + "aria-query": "^5.3.1", + "axobject-query": "^4.1.0", + "clsx": "^2.1.1", + "esm-env": "^1.2.1", + "esrap": "^2.1.0", + "is-reference": "^3.0.3", + "locate-character": "^3.0.0", + "magic-string": "^0.30.11", + "zimmerframe": "^1.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/svelte-boxicons": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/svelte-boxicons/-/svelte-boxicons-1.0.4.tgz", + "integrity": "sha512-6JZI6+WgDkDrj5TQbiFermPBadFi01VPU4HDHALR3GGt07j7cqA8or38gGzizJ09Q49VXh+fh703ed6o03a25A==", + "license": "MIT", + "peerDependencies": { + "svelte": "^3.55.1 || ^4.0.0 || ^5.0.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/vite": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.6.tgz", + "integrity": "sha512-MHFiOENNBd+Bd9uvc8GEsIzdkn1JxMmEeYX35tI3fv0sJBUTfW5tQsoaOwuY4KhBI09A3dUJ/DXf2yxPVPUceg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.6", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.40.0", + "tinyglobby": "^0.2.14" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz", + "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", + "dev": true, + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/zimmerframe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", + "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", + "license": "MIT" + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..0530f47 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,19 @@ +{ + "name": "frontend", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^6.0.0", + "svelte": "^5.35.5", + "vite": "^7.0.4" + }, + "dependencies": { + "svelte-boxicons": "^1.0.4" + } +} diff --git a/frontend/public/vite.svg b/frontend/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/frontend/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte new file mode 100644 index 0000000..e865d9e --- /dev/null +++ b/frontend/src/App.svelte @@ -0,0 +1,41 @@ + + + + +{#if loading} +

Loading...

+{:else if error} +

{error}

+{:else} +
+ {#each items as item (item.ID)} + + {/each} +
+{/if} diff --git a/frontend/src/app.css b/frontend/src/app.css new file mode 100644 index 0000000..61ba367 --- /dev/null +++ b/frontend/src/app.css @@ -0,0 +1,79 @@ +:root { + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +.card { + padding: 2em; +} + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/frontend/src/assets/svelte.svg b/frontend/src/assets/svelte.svg new file mode 100644 index 0000000..c5e0848 --- /dev/null +++ b/frontend/src/assets/svelte.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/lib/Counter.svelte b/frontend/src/lib/Counter.svelte new file mode 100644 index 0000000..770c922 --- /dev/null +++ b/frontend/src/lib/Counter.svelte @@ -0,0 +1,10 @@ + + + diff --git a/frontend/src/lib/Navbar.svelte b/frontend/src/lib/Navbar.svelte new file mode 100644 index 0000000..f61ddea --- /dev/null +++ b/frontend/src/lib/Navbar.svelte @@ -0,0 +1,109 @@ + + + + + + +{#if isOpen} +
+ (isOpen = false)}> Home + (isOpen = false)}> About + (isOpen = false)}> Contact +
+{/if} diff --git a/frontend/src/lib/Tile.svelte b/frontend/src/lib/Tile.svelte new file mode 100644 index 0000000..1c4a594 --- /dev/null +++ b/frontend/src/lib/Tile.svelte @@ -0,0 +1,82 @@ + + + + +
+ + + +
{show}
+
diff --git a/frontend/src/main.js b/frontend/src/main.js new file mode 100644 index 0000000..458c7a8 --- /dev/null +++ b/frontend/src/main.js @@ -0,0 +1,9 @@ +import { mount } from 'svelte' +import './app.css' +import App from './App.svelte' + +const app = mount(App, { + target: document.getElementById('app'), +}) + +export default app diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts new file mode 100644 index 0000000..4078e74 --- /dev/null +++ b/frontend/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/frontend/svelte.config.js b/frontend/svelte.config.js new file mode 100644 index 0000000..b0683fd --- /dev/null +++ b/frontend/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/frontend/vite.config.js b/frontend/vite.config.js new file mode 100644 index 0000000..b24ee98 --- /dev/null +++ b/frontend/vite.config.js @@ -0,0 +1,15 @@ +import { defineConfig } from 'vite'; +import { svelte } from '@sveltejs/vite-plugin-svelte'; + +export default defineConfig({ + plugins: [svelte()], +server: { + proxy: { + '/dropout': { + target: 'http://localhost:8000', + changeOrigin: true, + rewrite: path => path.replace(/^\/dropout/, '/dropout') + } + } +} +});