refactor: commands from menu
This commit is contained in:
parent
b95cfcc5b4
commit
f9638c35fc
@ -15,7 +15,7 @@
|
|||||||
},
|
},
|
||||||
"imports": {
|
"imports": {
|
||||||
"$fresh/": "https://deno.land/x/fresh@1.3.1/",
|
"$fresh/": "https://deno.land/x/fresh@1.3.1/",
|
||||||
"yaml": "https://deno.land/std@0.196.0/yaml/parse.ts",
|
"yaml": "https://deno.land/std@0.194.0/yaml/mod.ts",
|
||||||
"preact": "https://esm.sh/preact@10.15.1",
|
"preact": "https://esm.sh/preact@10.15.1",
|
||||||
"preact/": "https://esm.sh/preact@10.15.1/",
|
"preact/": "https://esm.sh/preact@10.15.1/",
|
||||||
"preact-render-to-string": "https://esm.sh/*preact-render-to-string@6.2.0",
|
"preact-render-to-string": "https://esm.sh/*preact-render-to-string@6.2.0",
|
||||||
|
10
fresh.gen.ts
10
fresh.gen.ts
@ -31,7 +31,10 @@ import * as $$0 from "./islands/Counter.tsx";
|
|||||||
import * as $$1 from "./islands/IngredientsList.tsx";
|
import * as $$1 from "./islands/IngredientsList.tsx";
|
||||||
import * as $$2 from "./islands/KMenu.tsx";
|
import * as $$2 from "./islands/KMenu.tsx";
|
||||||
import * as $$3 from "./islands/KMenu/commands.ts";
|
import * as $$3 from "./islands/KMenu/commands.ts";
|
||||||
import * as $$4 from "./islands/KMenu/types.ts";
|
import * as $$4 from "./islands/KMenu/commands/add_movie_infos.ts";
|
||||||
|
import * as $$5 from "./islands/KMenu/commands/create_article.ts";
|
||||||
|
import * as $$6 from "./islands/KMenu/commands/create_movie.ts";
|
||||||
|
import * as $$7 from "./islands/KMenu/types.ts";
|
||||||
|
|
||||||
const manifest = {
|
const manifest = {
|
||||||
routes: {
|
routes: {
|
||||||
@ -66,7 +69,10 @@ const manifest = {
|
|||||||
"./islands/IngredientsList.tsx": $$1,
|
"./islands/IngredientsList.tsx": $$1,
|
||||||
"./islands/KMenu.tsx": $$2,
|
"./islands/KMenu.tsx": $$2,
|
||||||
"./islands/KMenu/commands.ts": $$3,
|
"./islands/KMenu/commands.ts": $$3,
|
||||||
"./islands/KMenu/types.ts": $$4,
|
"./islands/KMenu/commands/add_movie_infos.ts": $$4,
|
||||||
|
"./islands/KMenu/commands/create_article.ts": $$5,
|
||||||
|
"./islands/KMenu/commands/create_movie.ts": $$6,
|
||||||
|
"./islands/KMenu/types.ts": $$7,
|
||||||
},
|
},
|
||||||
baseUrl: import.meta.url,
|
baseUrl: import.meta.url,
|
||||||
};
|
};
|
||||||
|
@ -37,6 +37,7 @@ export const KMenu = (
|
|||||||
const loadingText = useSignal("");
|
const loadingText = useSignal("");
|
||||||
const activeIndex = useSignal(-1);
|
const activeIndex = useSignal(-1);
|
||||||
|
|
||||||
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const input = useRef<HTMLInputElement>(null);
|
const input = useRef<HTMLInputElement>(null);
|
||||||
const commandInput = useSignal("");
|
const commandInput = useSignal("");
|
||||||
|
|
||||||
@ -83,6 +84,23 @@ export const KMenu = (
|
|||||||
}, context);
|
}, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const container = containerRef.current;
|
||||||
|
if (container) {
|
||||||
|
const selectedItem = container.children[activeIndex.value];
|
||||||
|
if (selectedItem) {
|
||||||
|
const itemPosition = selectedItem.getBoundingClientRect();
|
||||||
|
const containerPosition = container.getBoundingClientRect();
|
||||||
|
|
||||||
|
// Check if the selected item is above the visible area
|
||||||
|
if (itemPosition.top < containerPosition.top) {
|
||||||
|
container.scrollTop -= containerPosition.top - itemPosition.top;
|
||||||
|
} // Check if the selected item is below the visible area
|
||||||
|
else if (itemPosition.bottom > containerPosition.bottom) {
|
||||||
|
container.scrollTop += itemPosition.bottom - containerPosition.bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
useEventListener("keydown", (ev: KeyboardEvent) => {
|
useEventListener("keydown", (ev: KeyboardEvent) => {
|
||||||
if (ev.key === "/" && ev.ctrlKey) {
|
if (ev.key === "/" && ev.ctrlKey) {
|
||||||
visible.value = !visible.value;
|
visible.value = !visible.value;
|
||||||
@ -140,7 +158,7 @@ export const KMenu = (
|
|||||||
} border-gray-500 `}
|
} border-gray-500 `}
|
||||||
style={{
|
style={{
|
||||||
gridTemplateColumns: activeState.value !== "loading"
|
gridTemplateColumns: activeState.value !== "loading"
|
||||||
? "4em 1fr"
|
? "auto 1fr"
|
||||||
: "1fr",
|
: "1fr",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -148,7 +166,7 @@ export const KMenu = (
|
|||||||
(
|
(
|
||||||
<>
|
<>
|
||||||
<div class="grid place-items-center border-r border-gray-500">
|
<div class="grid place-items-center border-r border-gray-500">
|
||||||
<span class="text-white">
|
<span class="text-white mx-4">
|
||||||
{activeMenu.title}
|
{activeMenu.title}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -172,7 +190,11 @@ export const KMenu = (
|
|||||||
</div>
|
</div>
|
||||||
{activeState.value === "normal" &&
|
{activeState.value === "normal" &&
|
||||||
(
|
(
|
||||||
<div class="" style={{ maxHeight: "12rem", overflowY: "auto" }}>
|
<div
|
||||||
|
class=""
|
||||||
|
style={{ maxHeight: "12rem", overflowY: "auto" }}
|
||||||
|
ref={containerRef}
|
||||||
|
>
|
||||||
{entries?.length === 0 && (
|
{entries?.length === 0 && (
|
||||||
<div class="text-gray-400 px-4 py-2">
|
<div class="text-gray-400 px-4 py-2">
|
||||||
No Entries
|
No Entries
|
||||||
|
@ -1,56 +1,12 @@
|
|||||||
import { Menu } from "@islands/KMenu/types.ts";
|
import { Menu } from "@islands/KMenu/types.ts";
|
||||||
import { Movie } from "@lib/resource/movies.ts";
|
import { addMovieInfos } from "@islands/KMenu/commands/add_movie_infos.ts";
|
||||||
import { TMDBMovie } from "@lib/types.ts";
|
import { createNewMovie } from "@islands/KMenu/commands/create_movie.ts";
|
||||||
import { fetchStream, isValidUrl } from "@lib/helpers.ts";
|
import { createNewArticle } from "@islands/KMenu/commands/create_article.ts";
|
||||||
|
|
||||||
export const menus: Record<string, Menu> = {
|
export const menus: Record<string, Menu> = {
|
||||||
main: {
|
main: {
|
||||||
title: "Run",
|
title: "Run",
|
||||||
entries: [
|
entries: [
|
||||||
{
|
|
||||||
title: "Close menu",
|
|
||||||
meta: "",
|
|
||||||
cb: (state) => {
|
|
||||||
state.visible.value = false;
|
|
||||||
},
|
|
||||||
visible: () => false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Create new article",
|
|
||||||
meta: "",
|
|
||||||
icon: "IconSquareRoundedPlus",
|
|
||||||
cb: (state) => {
|
|
||||||
state.menus["input_link"] = {
|
|
||||||
title: "Link:",
|
|
||||||
entries: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
state.activeMenu.value = "input_link";
|
|
||||||
state.activeState.value = "input";
|
|
||||||
|
|
||||||
const unsub = state.commandInput.subscribe((value) => {
|
|
||||||
if (isValidUrl(value)) {
|
|
||||||
unsub();
|
|
||||||
|
|
||||||
state.activeState.value = "loading";
|
|
||||||
|
|
||||||
fetchStream("/api/articles/create?url=" + value, (chunk) => {
|
|
||||||
console.log({ chunk: chunk.split("\n") });
|
|
||||||
if (chunk.startsWith("id:")) {
|
|
||||||
state.loadingText.value = "Finished";
|
|
||||||
setTimeout(() => {
|
|
||||||
window.location.href = "/articles/" +
|
|
||||||
chunk.replace("id:", "").trim();
|
|
||||||
}, 500);
|
|
||||||
} else {
|
|
||||||
state.loadingText.value = chunk;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
visible: () => true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: "Clear Cache",
|
title: "Clear Cache",
|
||||||
icon: "IconRefresh",
|
icon: "IconRefresh",
|
||||||
@ -63,58 +19,9 @@ export const menus: Record<string, Menu> = {
|
|||||||
state.visible.value = false;
|
state.visible.value = false;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
createNewArticle,
|
||||||
title: "Add Movie infos",
|
createNewMovie,
|
||||||
meta: "",
|
addMovieInfos,
|
||||||
icon: "IconReportSearch",
|
|
||||||
cb: async (state, context) => {
|
|
||||||
state.activeState.value = "loading";
|
|
||||||
const movie = context as Movie;
|
|
||||||
|
|
||||||
const query = movie.name;
|
|
||||||
|
|
||||||
const response = await fetch(
|
|
||||||
`/api/tmdb/query?q=${encodeURIComponent(query)}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const json = await response.json() as TMDBMovie[];
|
|
||||||
|
|
||||||
const menuID = `result/${movie.name}`;
|
|
||||||
|
|
||||||
state.menus[menuID] = {
|
|
||||||
title: "Select",
|
|
||||||
entries: json.map((m) => ({
|
|
||||||
title: `${m.title} released ${m.release_date}`,
|
|
||||||
cb: async () => {
|
|
||||||
state.activeState.value = "loading";
|
|
||||||
await fetch(`/api/movies/enhance/${movie.name}/`, {
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify({ tmdbId: m.id }),
|
|
||||||
});
|
|
||||||
state.visible.value = false;
|
|
||||||
state.activeState.value = "normal";
|
|
||||||
window.location.reload();
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
};
|
|
||||||
|
|
||||||
state.activeMenu.value = menuID;
|
|
||||||
|
|
||||||
state.activeState.value = "normal";
|
|
||||||
},
|
|
||||||
visible: () => {
|
|
||||||
const loc = globalThis["location"];
|
|
||||||
return loc?.pathname?.includes("movie");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Reload Page",
|
|
||||||
meta: "",
|
|
||||||
cb: () => {
|
|
||||||
window.location.reload();
|
|
||||||
},
|
|
||||||
visible: () => false,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
48
islands/KMenu/commands/add_movie_infos.ts
Normal file
48
islands/KMenu/commands/add_movie_infos.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { MenuEntry } from "@islands/KMenu/types.ts";
|
||||||
|
import { Movie } from "@lib/resource/movies.ts";
|
||||||
|
import { TMDBMovie } from "@lib/types.ts";
|
||||||
|
|
||||||
|
export const addMovieInfos: MenuEntry = {
|
||||||
|
title: "Add Movie infos",
|
||||||
|
meta: "",
|
||||||
|
icon: "IconReportSearch",
|
||||||
|
cb: async (state, context) => {
|
||||||
|
state.activeState.value = "loading";
|
||||||
|
const movie = context as Movie;
|
||||||
|
|
||||||
|
const query = movie.name;
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
`/api/tmdb/query?q=${encodeURIComponent(query)}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const json = await response.json() as TMDBMovie[];
|
||||||
|
|
||||||
|
const menuID = `result/${movie.name}`;
|
||||||
|
|
||||||
|
state.menus[menuID] = {
|
||||||
|
title: "Select",
|
||||||
|
entries: json.map((m) => ({
|
||||||
|
title: `${m.title} released ${m.release_date}`,
|
||||||
|
cb: async () => {
|
||||||
|
state.activeState.value = "loading";
|
||||||
|
await fetch(`/api/movies/enhance/${movie.name}/`, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ tmdbId: m.id }),
|
||||||
|
});
|
||||||
|
state.visible.value = false;
|
||||||
|
state.activeState.value = "normal";
|
||||||
|
window.location.reload();
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
state.activeMenu.value = menuID;
|
||||||
|
|
||||||
|
state.activeState.value = "normal";
|
||||||
|
},
|
||||||
|
visible: () => {
|
||||||
|
const loc = globalThis["location"];
|
||||||
|
return loc?.pathname?.includes("movie");
|
||||||
|
},
|
||||||
|
};
|
39
islands/KMenu/commands/create_article.ts
Normal file
39
islands/KMenu/commands/create_article.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { MenuEntry } from "@islands/KMenu/types.ts";
|
||||||
|
import { fetchStream, isValidUrl } from "@lib/helpers.ts";
|
||||||
|
|
||||||
|
export const createNewArticle: MenuEntry = {
|
||||||
|
title: "Create new article",
|
||||||
|
meta: "",
|
||||||
|
icon: "IconSquareRoundedPlus",
|
||||||
|
cb: (state) => {
|
||||||
|
state.menus["input_link"] = {
|
||||||
|
title: "Link:",
|
||||||
|
entries: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
state.activeMenu.value = "input_link";
|
||||||
|
state.activeState.value = "input";
|
||||||
|
|
||||||
|
const unsub = state.commandInput.subscribe((value) => {
|
||||||
|
if (isValidUrl(value)) {
|
||||||
|
unsub();
|
||||||
|
|
||||||
|
state.activeState.value = "loading";
|
||||||
|
|
||||||
|
fetchStream("/api/articles/create?url=" + value, (chunk) => {
|
||||||
|
console.log({ chunk: chunk.split("\n") });
|
||||||
|
if (chunk.startsWith("id:")) {
|
||||||
|
state.loadingText.value = "Finished";
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = "/articles/" +
|
||||||
|
chunk.replace("id:", "").trim();
|
||||||
|
}, 500);
|
||||||
|
} else {
|
||||||
|
state.loadingText.value = chunk;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
visible: () => true,
|
||||||
|
};
|
72
islands/KMenu/commands/create_movie.ts
Normal file
72
islands/KMenu/commands/create_movie.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { MenuEntry } from "@islands/KMenu/types.ts";
|
||||||
|
import { TMDBMovie } from "@lib/types.ts";
|
||||||
|
import { debounce } from "@lib/helpers.ts";
|
||||||
|
import { Movie } from "@lib/resource/movies.ts";
|
||||||
|
|
||||||
|
export const createNewMovie: MenuEntry = {
|
||||||
|
title: "Create new movie",
|
||||||
|
meta: "",
|
||||||
|
icon: "IconSquareRoundedPlus",
|
||||||
|
cb: (state) => {
|
||||||
|
state.menus["input_link"] = {
|
||||||
|
title: "Search",
|
||||||
|
entries: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
state.menus["loading"] = {
|
||||||
|
title: "Search",
|
||||||
|
entries: [
|
||||||
|
{
|
||||||
|
title: "Loading",
|
||||||
|
icon: "IconLoader2",
|
||||||
|
cb() {
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
state.activeMenu.value = "input_link";
|
||||||
|
state.activeState.value = "normal";
|
||||||
|
|
||||||
|
let currentQuery: string;
|
||||||
|
const search = debounce(async function search(query: string) {
|
||||||
|
currentQuery = query;
|
||||||
|
console.log({ query });
|
||||||
|
if (query.length < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch("/api/tmdb/query?q=" + query);
|
||||||
|
|
||||||
|
const movies = await response.json() as TMDBMovie[];
|
||||||
|
|
||||||
|
console.log({ query, currentQuery, movies });
|
||||||
|
|
||||||
|
if (query !== currentQuery) return;
|
||||||
|
|
||||||
|
state.menus["input_link"] = {
|
||||||
|
title: "Search",
|
||||||
|
entries: movies.map((r) => {
|
||||||
|
return {
|
||||||
|
title: `${r.title} - ${r.release_date}`,
|
||||||
|
cb: async () => {
|
||||||
|
state.activeState.value = "loading";
|
||||||
|
const response = await fetch("/api/movies/" + r.id, {
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
|
const movie = await response.json() as Movie;
|
||||||
|
window.location.href = "/movies/" + movie.name;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
state.activeMenu.value = "input_link";
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
const unsub = state.commandInput.subscribe((value) => {
|
||||||
|
state.activeMenu.value = "loading";
|
||||||
|
search(value);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
visible: () => true,
|
||||||
|
};
|
24
lib/cache/cache.ts
vendored
24
lib/cache/cache.ts
vendored
@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
Bulk,
|
||||||
connect,
|
connect,
|
||||||
Redis,
|
Redis,
|
||||||
RedisConnectOptions,
|
RedisConnectOptions,
|
||||||
@ -14,16 +15,31 @@ async function createCache<T>(): Promise<Map<string, T> | Redis> {
|
|||||||
const conf: RedisConnectOptions = {
|
const conf: RedisConnectOptions = {
|
||||||
hostname: REDIS_HOST,
|
hostname: REDIS_HOST,
|
||||||
port: REDIS_PORT || 6379,
|
port: REDIS_PORT || 6379,
|
||||||
|
maxRetryCount: 2,
|
||||||
};
|
};
|
||||||
if (REDIS_PASS) {
|
if (REDIS_PASS) {
|
||||||
conf.password = REDIS_PASS;
|
conf.password = REDIS_PASS;
|
||||||
}
|
}
|
||||||
const client = await connect(conf);
|
try {
|
||||||
console.log("[redis] connected");
|
const client = await connect(conf);
|
||||||
return client;
|
console.log("[redis] connected");
|
||||||
|
return client;
|
||||||
|
} catch (_err) {
|
||||||
|
console.log("[cache] cant connect to redis, falling back to mock");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Map<string, T>();
|
const mockRedis = new Map<string, RedisValue>();
|
||||||
|
|
||||||
|
return {
|
||||||
|
async set(key: string, value: RedisValue) {
|
||||||
|
mockRedis.set(key, value);
|
||||||
|
return value.toString();
|
||||||
|
},
|
||||||
|
async get(key: string) {
|
||||||
|
return mockRedis.get(key) as Bulk;
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const cache = await createCache();
|
const cache = await createCache();
|
||||||
|
@ -76,3 +76,15 @@ export const createStreamResponse = () => {
|
|||||||
enqueue,
|
enqueue,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function debounce<T extends (...args: Parameters<T>) => void>(
|
||||||
|
this: ThisParameterType<T>,
|
||||||
|
fn: T,
|
||||||
|
delay = 300,
|
||||||
|
) {
|
||||||
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
||||||
|
return (...args: Parameters<T>) => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
timer = setTimeout(() => fn.apply(this, args), delay);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { parseDocument, renderMarkdown } from "@lib/documents.ts";
|
import { parseDocument, renderMarkdown } from "@lib/documents.ts";
|
||||||
import { parse } from "yaml";
|
import { parse, stringify } from "yaml";
|
||||||
import { createCrud } from "@lib/crud.ts";
|
import { createCrud } from "@lib/crud.ts";
|
||||||
import { extractHashTags } from "@lib/string.ts";
|
import { extractHashTags, formatDate } from "@lib/string.ts";
|
||||||
|
import { fixRenderedMarkdown } from "@lib/helpers.ts";
|
||||||
|
|
||||||
export type Movie = {
|
export type Movie = {
|
||||||
id: string;
|
id: string;
|
||||||
@ -18,6 +19,27 @@ export type Movie = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function renderMovie(movie: Movie) {
|
||||||
|
const meta = movie.meta;
|
||||||
|
if ("date" in meta) {
|
||||||
|
meta.date = formatDate(meta.date);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fixRenderedMarkdown(`${
|
||||||
|
meta
|
||||||
|
? `---
|
||||||
|
${stringify(meta)}
|
||||||
|
---`
|
||||||
|
: `---
|
||||||
|
---`
|
||||||
|
}
|
||||||
|
# ${movie.name}
|
||||||
|
${movie.meta.image ? `` : ""}
|
||||||
|
${movie.tags.map((t) => `#${t}`).join(" ")}
|
||||||
|
${movie.description}
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
export function parseMovie(original: string, id: string): Movie {
|
export function parseMovie(original: string, id: string): Movie {
|
||||||
const doc = parseDocument(original);
|
const doc = parseDocument(original);
|
||||||
|
|
||||||
@ -80,3 +102,8 @@ const crud = createCrud<Movie>({
|
|||||||
|
|
||||||
export const getMovie = crud.read;
|
export const getMovie = crud.read;
|
||||||
export const getAllMovies = crud.readAll;
|
export const getAllMovies = crud.readAll;
|
||||||
|
export const createMovie = (movie: Movie) => {
|
||||||
|
console.log("creating movie", { movie });
|
||||||
|
const content = renderMovie(movie);
|
||||||
|
return crud.create(movie.id, content);
|
||||||
|
};
|
||||||
|
@ -1,10 +1,62 @@
|
|||||||
import { Handlers } from "$fresh/server.ts";
|
import { Handlers } from "$fresh/server.ts";
|
||||||
import { getMovie } from "@lib/resource/movies.ts";
|
import { createMovie, getMovie, Movie } from "@lib/resource/movies.ts";
|
||||||
import { json } from "@lib/helpers.ts";
|
import { json } from "@lib/helpers.ts";
|
||||||
|
import * as tmdb from "@lib/tmdb.ts";
|
||||||
|
import { fileExtension } from "https://deno.land/x/file_extension@v2.1.0/mod.ts";
|
||||||
|
import { safeFileName } from "@lib/string.ts";
|
||||||
|
import { createDocument } from "@lib/documents.ts";
|
||||||
|
|
||||||
export const handler: Handlers = {
|
export const handler: Handlers = {
|
||||||
async GET(_, ctx) {
|
async GET(_, ctx) {
|
||||||
const movie = await getMovie(ctx.params.name);
|
const movie = await getMovie(ctx.params.name);
|
||||||
return json(movie);
|
return json(movie);
|
||||||
},
|
},
|
||||||
|
async POST(_, ctx) {
|
||||||
|
const tmdbId = parseInt(ctx.params.name);
|
||||||
|
|
||||||
|
const movieDetails = await tmdb.getMovie(tmdbId);
|
||||||
|
const movieCredits = await tmdb.getMovieCredits(tmdbId);
|
||||||
|
|
||||||
|
const releaseDate = movieDetails.release_date;
|
||||||
|
const posterPath = movieDetails.poster_path;
|
||||||
|
const director =
|
||||||
|
movieCredits?.crew?.filter?.((person) => person.job === "Director")[0];
|
||||||
|
|
||||||
|
let finalPath = "";
|
||||||
|
const name = movieDetails.title || movieDetails.original_title ||
|
||||||
|
ctx.params.name;
|
||||||
|
if (posterPath) {
|
||||||
|
const poster = await tmdb.getMoviePoster(posterPath);
|
||||||
|
const extension = fileExtension(posterPath);
|
||||||
|
|
||||||
|
finalPath = `Media/movies/images/${
|
||||||
|
safeFileName(name)
|
||||||
|
}_cover.${extension}`;
|
||||||
|
await createDocument(finalPath, poster);
|
||||||
|
}
|
||||||
|
|
||||||
|
const metadata = {} as Movie["meta"];
|
||||||
|
if (releaseDate) {
|
||||||
|
metadata.date = new Date(releaseDate);
|
||||||
|
}
|
||||||
|
if (finalPath) {
|
||||||
|
metadata.image = finalPath;
|
||||||
|
}
|
||||||
|
if (director) {
|
||||||
|
metadata.author = director.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const movie: Movie = {
|
||||||
|
id: name,
|
||||||
|
name: name,
|
||||||
|
type: "movie",
|
||||||
|
description: "",
|
||||||
|
tags: [],
|
||||||
|
meta: metadata,
|
||||||
|
};
|
||||||
|
|
||||||
|
await createMovie(movie);
|
||||||
|
|
||||||
|
return json(movie);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@ export default function Greet(props: PageProps<Movie>) {
|
|||||||
|
|
||||||
const { author = "", date = "" } = movie.meta;
|
const { author = "", date = "" } = movie.meta;
|
||||||
|
|
||||||
console.log(movie.description)
|
console.log(movie.description);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainLayout url={props.url}>
|
<MainLayout url={props.url}>
|
||||||
@ -35,7 +35,9 @@ export default function Greet(props: PageProps<Movie>) {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div class="px-8 text-white mt-10">
|
<div class="px-8 text-white mt-10">
|
||||||
{movie?.description?.length > 80 ? <h2 class="text-4xl font-bold mb-4">Review</h2>:<></>}
|
{movie?.description?.length > 80
|
||||||
|
? <h2 class="text-4xl font-bold mb-4">Review</h2>
|
||||||
|
: <></>}
|
||||||
<pre
|
<pre
|
||||||
class="whitespace-break-spaces"
|
class="whitespace-break-spaces"
|
||||||
dangerouslySetInnerHTML={{ __html: movie.description || "" }}
|
dangerouslySetInnerHTML={{ __html: movie.description || "" }}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user