feat: fallback to unsplash cover when article contains no image
This commit is contained in:
@@ -21,7 +21,7 @@ const KMenuEntry = (
|
||||
: "text-gray-400"
|
||||
}`}
|
||||
>
|
||||
{entry?.icon && icons[entry.icon]({ class: "w-4 h-4 mr-1" })}
|
||||
{entry?.icon && icons[entry.icon]({ class: "min-w-4 h-4 mr-1" })}
|
||||
{entry.title}
|
||||
</div>
|
||||
);
|
||||
@@ -168,13 +168,15 @@ export const KMenu = (
|
||||
style={{ background: "#2B2930", color: "#818181" }}
|
||||
>
|
||||
<div
|
||||
class={`grid h-12 text-gray-400 ${
|
||||
activeState.value !== "loading" && "border-b"
|
||||
class={`grid min-h-12 text-gray-400 ${
|
||||
(activeState.value === "normal" || activeState.value === "input") &&
|
||||
"border-b"
|
||||
} border-gray-500 `}
|
||||
style={{
|
||||
gridTemplateColumns: activeState.value !== "loading"
|
||||
? "auto 1fr"
|
||||
: "1fr",
|
||||
gridTemplateColumns:
|
||||
(activeState.value === "normal" || activeState.value === "input")
|
||||
? "auto 1fr"
|
||||
: "1fr",
|
||||
}}
|
||||
>
|
||||
{(activeState.value === "normal" || activeState.value === "input") &&
|
||||
@@ -198,12 +200,18 @@ export const KMenu = (
|
||||
)}
|
||||
{activeState.value === "loading" && (
|
||||
<div class="py-3 px-4 flex items-center gap-2">
|
||||
<icons.IconLoader2 class="animate-spin w-4 h-4" />
|
||||
<icons.IconLoader2 class="animate-spin min-w-4 h-4" />
|
||||
{loadingText.value || "Loading..."}
|
||||
</div>
|
||||
)}
|
||||
{activeState.value === "error" && (
|
||||
<div class="py-3 px-4 flex items-center gap-2 text-red-400">
|
||||
<icons.IconAlertCircle class="min-w-4 h-4" />
|
||||
{loadingText.value || "An error occurred"}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{activeState.value === "normal" &&
|
||||
{(activeState.value === "normal" || activeState.value === "input") &&
|
||||
(
|
||||
<div
|
||||
class=""
|
||||
|
||||
@@ -7,6 +7,7 @@ import { addSeriesInfo } from "@islands/KMenu/commands/add_series_infos.ts";
|
||||
import { createNewSeries } from "@islands/KMenu/commands/create_series.ts";
|
||||
import { updateAllRecommendations } from "@islands/KMenu/commands/create_recommendations.ts";
|
||||
import { createNewRecipe } from "@islands/KMenu/commands/create_recipe.ts";
|
||||
import { enhanceArticleInfo } from "@islands/KMenu/commands/enhance_article_infos.ts";
|
||||
|
||||
export const menus: Record<string, Menu> = {
|
||||
main: {
|
||||
@@ -77,6 +78,7 @@ export const menus: Record<string, Menu> = {
|
||||
createNewSeries,
|
||||
createNewRecipe,
|
||||
addMovieInfos,
|
||||
enhanceArticleInfo,
|
||||
// updateAllRecommendations,
|
||||
],
|
||||
},
|
||||
|
||||
@@ -8,39 +8,53 @@ export const addMovieInfos: MenuEntry = {
|
||||
meta: "",
|
||||
icon: "IconReportSearch",
|
||||
cb: async (state, context) => {
|
||||
state.activeState.value = "loading";
|
||||
const movie = context as ReviewResource;
|
||||
try {
|
||||
state.activeState.value = "loading";
|
||||
const movie = context as ReviewResource;
|
||||
|
||||
const query = movie.name;
|
||||
const query = movie.name;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/tmdb/query?q=${encodeURIComponent(query)}`,
|
||||
);
|
||||
const response = await fetch(
|
||||
`/api/tmdb/query?q=${encodeURIComponent(query)}`,
|
||||
);
|
||||
|
||||
const json = await response.json() as TMDBMovie[];
|
||||
if (!response.ok) {
|
||||
throw new Error(await response.text());
|
||||
}
|
||||
|
||||
const menuID = `result/${movie.name}`;
|
||||
const json = await response.json() as TMDBMovie[];
|
||||
|
||||
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";
|
||||
globalThis.location.reload();
|
||||
},
|
||||
})),
|
||||
};
|
||||
const menuID = `result/${movie.name}`;
|
||||
|
||||
state.activeMenu.value = menuID;
|
||||
state.commandInput.value = "";
|
||||
state.activeState.value = "normal";
|
||||
state.menus[menuID] = {
|
||||
title: "Select",
|
||||
entries: json.map((m) => ({
|
||||
title: `${m.title} released ${m.release_date}`,
|
||||
cb: async () => {
|
||||
try {
|
||||
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";
|
||||
globalThis.location.reload();
|
||||
} catch (e) {
|
||||
state.activeState.value = "error";
|
||||
state.loadingText.value = e.message;
|
||||
}
|
||||
},
|
||||
})),
|
||||
};
|
||||
|
||||
state.activeMenu.value = menuID;
|
||||
state.commandInput.value = "";
|
||||
state.activeState.value = "normal";
|
||||
} catch (e) {
|
||||
state.activeState.value = "error";
|
||||
state.loadingText.value = e.message;
|
||||
}
|
||||
},
|
||||
visible: () => {
|
||||
const loc = globalThis["location"];
|
||||
|
||||
@@ -8,39 +8,53 @@ export const addSeriesInfo: MenuEntry = {
|
||||
meta: "",
|
||||
icon: "IconReportSearch",
|
||||
cb: async (state, context) => {
|
||||
state.activeState.value = "loading";
|
||||
const series = context as ReviewResource;
|
||||
try {
|
||||
state.activeState.value = "loading";
|
||||
const series = context as ReviewResource;
|
||||
|
||||
const query = series.name;
|
||||
const query = series.name;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/tmdb/query?q=${encodeURIComponent(query)}&type=serie`,
|
||||
);
|
||||
const response = await fetch(
|
||||
`/api/tmdb/query?q=${encodeURIComponent(query)}&type=serie`,
|
||||
);
|
||||
|
||||
const json = await response.json() as TMDBSeries[];
|
||||
if (!response.ok) {
|
||||
throw new Error(await response.text());
|
||||
}
|
||||
|
||||
const menuID = `result/${series.name}`;
|
||||
const json = await response.json() as TMDBSeries[];
|
||||
|
||||
state.menus[menuID] = {
|
||||
title: "Select",
|
||||
entries: json.map((m) => ({
|
||||
title: `${m.name || m.original_name} released ${m.first_air_date}`,
|
||||
cb: async () => {
|
||||
state.activeState.value = "loading";
|
||||
await fetch(`/api/series/enhance/${series.name}/`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ tmdbId: m.id }),
|
||||
});
|
||||
state.visible.value = false;
|
||||
state.activeState.value = "normal";
|
||||
//window.location.reload();
|
||||
},
|
||||
})),
|
||||
};
|
||||
const menuID = `result/${series.name}`;
|
||||
|
||||
state.commandInput.value = "";
|
||||
state.activeMenu.value = menuID;
|
||||
state.activeState.value = "normal";
|
||||
state.menus[menuID] = {
|
||||
title: "Select",
|
||||
entries: json.map((m) => ({
|
||||
title: `${m.name || m.original_name} released ${m.first_air_date}`,
|
||||
cb: async () => {
|
||||
try {
|
||||
state.activeState.value = "loading";
|
||||
await fetch(`/api/series/enhance/${series.name}/`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ tmdbId: m.id }),
|
||||
});
|
||||
state.visible.value = false;
|
||||
state.activeState.value = "normal";
|
||||
//window.location.reload();
|
||||
} catch (e) {
|
||||
state.activeState.value = "error";
|
||||
state.loadingText.value = e.message;
|
||||
}
|
||||
},
|
||||
})),
|
||||
};
|
||||
|
||||
state.commandInput.value = "";
|
||||
state.activeMenu.value = menuID;
|
||||
state.activeState.value = "normal";
|
||||
} catch (e) {
|
||||
state.activeState.value = "error";
|
||||
state.loadingText.value = e.message;
|
||||
}
|
||||
},
|
||||
visible: () => {
|
||||
const loc = globalThis["location"];
|
||||
|
||||
@@ -22,14 +22,16 @@ export const createNewArticle: MenuEntry = {
|
||||
state.activeState.value = "loading";
|
||||
|
||||
fetchStream("/api/articles/create?url=" + value, (chunk) => {
|
||||
if (chunk.startsWith("id:")) {
|
||||
if (chunk.type === "error") {
|
||||
state.activeState.value = "error";
|
||||
state.loadingText.value = chunk.message;
|
||||
} else if (chunk.type === "finished") {
|
||||
state.loadingText.value = "Finished";
|
||||
setTimeout(() => {
|
||||
window.location.href = "/articles/" +
|
||||
chunk.replace("id:", "").trim();
|
||||
globalThis.location.href = "/articles/" + chunk.url;
|
||||
}, 500);
|
||||
} else {
|
||||
state.loadingText.value = chunk;
|
||||
state.loadingText.value = chunk.message;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -31,35 +31,52 @@ export const createNewMovie: MenuEntry = {
|
||||
|
||||
let currentQuery: string;
|
||||
const search = debounce(async function search(query: string) {
|
||||
currentQuery = query;
|
||||
if (query.length < 2) {
|
||||
return;
|
||||
try {
|
||||
currentQuery = query;
|
||||
if (query.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetch("/api/tmdb/query?q=" + query);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(await response.text());
|
||||
}
|
||||
|
||||
const movies = await response.json() as TMDBMovie[];
|
||||
|
||||
if (query !== currentQuery) return;
|
||||
|
||||
state.menus["input_link"] = {
|
||||
title: "Search",
|
||||
entries: movies.map((r) => {
|
||||
return {
|
||||
title: `${r.title} - ${r.release_date}`,
|
||||
cb: async () => {
|
||||
try {
|
||||
state.activeState.value = "loading";
|
||||
const response = await fetch("/api/movies/" + r.id, {
|
||||
method: "POST",
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(await response.text());
|
||||
}
|
||||
const movie = await response.json() as ReviewResource;
|
||||
unsub();
|
||||
globalThis.location.href = "/movies/" + movie.name;
|
||||
} catch (e) {
|
||||
state.activeState.value = "error";
|
||||
state.loadingText.value = e.message;
|
||||
}
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
state.activeMenu.value = "input_link";
|
||||
} catch (e) {
|
||||
state.activeState.value = "error";
|
||||
state.loadingText.value = e.message;
|
||||
}
|
||||
|
||||
const response = await fetch("/api/tmdb/query?q=" + query);
|
||||
|
||||
const movies = await response.json() as TMDBMovie[];
|
||||
|
||||
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 ReviewResource;
|
||||
unsub();
|
||||
globalThis.location.href = "/movies/" + movie.name;
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
state.activeMenu.value = "input_link";
|
||||
}, 500);
|
||||
|
||||
const unsub = state.commandInput.subscribe((value) => {
|
||||
|
||||
@@ -21,15 +21,17 @@ export const createNewRecipe: MenuEntry = {
|
||||
|
||||
state.activeState.value = "loading";
|
||||
|
||||
fetchStream("/api/recipes/create?url=" + value, (chunk) => {
|
||||
if (chunk.startsWith("id:")) {
|
||||
fetchStream("/api/recipes/create?url=" + value, (msg) => {
|
||||
if (msg.type === "error") {
|
||||
state.activeState.value = "error";
|
||||
state.loadingText.value = msg.message;
|
||||
} else if (msg.type === "finished") {
|
||||
state.loadingText.value = "Finished";
|
||||
setTimeout(() => {
|
||||
globalThis.location.href = "/recipes/" +
|
||||
chunk.replace("id:", "").trim();
|
||||
globalThis.location.href = "/recipes/" + msg.url;
|
||||
}, 500);
|
||||
} else {
|
||||
state.loadingText.value = chunk;
|
||||
state.loadingText.value = msg.message;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,12 +10,15 @@ export const updateAllRecommendations: MenuEntry = {
|
||||
state.activeState.value = "loading";
|
||||
|
||||
fetchStream("/api/recommendation/all", (chunk) => {
|
||||
if (chunk.toLowerCase().includes("finish")) {
|
||||
if (chunk.type === "error") {
|
||||
state.activeState.value = "error";
|
||||
state.loadingText.value = chunk.message;
|
||||
} else if (chunk.type === "finished") {
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
globalThis.location.reload();
|
||||
}, 500);
|
||||
} else {
|
||||
state.loadingText.value = chunk;
|
||||
state.loadingText.value = chunk.message;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -31,42 +31,55 @@ export const createNewSeries: MenuEntry = {
|
||||
|
||||
let currentQuery: string;
|
||||
const search = debounce(async function search(query: string) {
|
||||
currentQuery = query;
|
||||
if (query.length < 2) {
|
||||
return;
|
||||
try {
|
||||
currentQuery = query;
|
||||
if (query.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetch(
|
||||
"/api/tmdb/query?q=" + query + "&type=series",
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(await response.text());
|
||||
}
|
||||
|
||||
const series = await response.json() as TMDBSeries[];
|
||||
|
||||
if (query !== currentQuery) return;
|
||||
|
||||
state.menus["input_link"] = {
|
||||
title: "Search",
|
||||
entries: series.map((r) => {
|
||||
return {
|
||||
title: `${r.name} - ${r.first_air_date}`,
|
||||
cb: async () => {
|
||||
try {
|
||||
state.activeState.value = "loading";
|
||||
const response = await fetch("/api/series/" + r.id, {
|
||||
method: "POST",
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(await response.text());
|
||||
}
|
||||
const series = await response.json() as ReviewResource;
|
||||
unsub();
|
||||
globalThis.location.href = "/series/" + series.name;
|
||||
} catch (e) {
|
||||
state.activeState.value = "error";
|
||||
state.loadingText.value = e.message;
|
||||
}
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
state.commandInput.value = "";
|
||||
state.activeMenu.value = "input_link";
|
||||
} catch (e) {
|
||||
state.activeState.value = "error";
|
||||
state.loadingText.value = e.message;
|
||||
}
|
||||
|
||||
const response = await fetch(
|
||||
"/api/tmdb/query?q=" + query + "&type=series",
|
||||
);
|
||||
|
||||
const series = await response.json() as TMDBSeries[];
|
||||
|
||||
if (query !== currentQuery) return;
|
||||
|
||||
state.menus["input_link"] = {
|
||||
title: "Search",
|
||||
entries: series.map((r) => {
|
||||
return {
|
||||
title: `${r.name} - ${r.first_air_date}`,
|
||||
cb: async () => {
|
||||
try {
|
||||
state.activeState.value = "loading";
|
||||
const response = await fetch("/api/series/" + r.id, {
|
||||
method: "POST",
|
||||
});
|
||||
const series = await response.json() as ReviewResource;
|
||||
unsub();
|
||||
globalThis.location.href = "/series/" + series.name;
|
||||
} catch (_e) {
|
||||
state.activeState.value = "normal";
|
||||
}
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
state.commandInput.value = "";
|
||||
state.activeMenu.value = "input_link";
|
||||
}, 500);
|
||||
|
||||
const unsub = state.commandInput.subscribe((value) => {
|
||||
|
||||
41
islands/KMenu/commands/enhance_article_infos.ts
Normal file
41
islands/KMenu/commands/enhance_article_infos.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { getCookie } from "@lib/string.ts";
|
||||
import { MenuEntry } from "../types.ts";
|
||||
import { ArticleResource } from "@lib/marka/schema.ts";
|
||||
import { fetchStream } from "@lib/helpers.ts";
|
||||
|
||||
export const enhanceArticleInfo: MenuEntry = {
|
||||
title: "Enhance Article Info",
|
||||
meta: "Update metadata and content from source url",
|
||||
icon: "IconReportSearch",
|
||||
cb: (state, context) => {
|
||||
state.activeState.value = "loading";
|
||||
const article = context as ArticleResource;
|
||||
|
||||
fetchStream(
|
||||
`/api/articles/enhance/${article.name}/`,
|
||||
(chunk) => {
|
||||
if (chunk.type === "error") {
|
||||
state.activeState.value = "error";
|
||||
state.loadingText.value = chunk.message;
|
||||
} else if (chunk.type == "finished") {
|
||||
state.loadingText.value = "Finished";
|
||||
setTimeout(() => {
|
||||
state.visible.value = false;
|
||||
state.activeState.value = "normal";
|
||||
globalThis.location.reload();
|
||||
}, 500);
|
||||
} else {
|
||||
state.loadingText.value = chunk.message;
|
||||
}
|
||||
},
|
||||
{ method: "POST" },
|
||||
);
|
||||
},
|
||||
visible: () => {
|
||||
const loc = globalThis["location"];
|
||||
if (!getCookie("session_cookie")) return false;
|
||||
|
||||
return (loc?.pathname?.includes("article") &&
|
||||
!loc.pathname.endsWith("articles"));
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user