Delete old components from a month ago? & Update draggable window to be using the native svgs by lucide icons & updated the news page to activate the tab changing animation when changing tabs & added caching into the [slug].ts file in publishers/lt & added a basic endpoint for searching for sources.

This commit is contained in:
yuanhau 2025-06-04 22:30:02 +08:00
parent 231a7ce251
commit 8032c3faae
12 changed files with 124 additions and 117 deletions

View file

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { useThrottleFn } from "@vueuse/core"; import { useThrottleFn } from "@vueuse/core";
import { XIcon, MinusIcon } from "lucide-vue-next";
const props = defineProps<{ const props = defineProps<{
title: string; title: string;
@ -78,19 +79,23 @@ const stopDrag = () => {
@mousedown="startDrag" @mousedown="startDrag"
class="bg-gray-700 p-2 cursor-move flex justify-between items-center flex-shrink-0 text-white z-[50] selection:opacity-0" class="bg-gray-700 p-2 cursor-move flex justify-between items-center flex-shrink-0 text-white z-[50] selection:opacity-0"
> >
<h3 class="font-semibold text-white">{{ title }}</h3> <h3
class="font-semibold text-white selection:opactiy-0 selection:bg-gray-700"
>
{{ title }}
</h3>
<div class="flex flex-row gap-1"> <div class="flex flex-row gap-1">
<button <button
@click="emit('min')" @click="emit('min')"
class="p-1 hover:bg-gray-300 dark:hover:bg-gray-600 rounded transition duration-200" class="p-1 hover:bg-gray-300 dark:hover:bg-gray-600 rounded transition duration-200"
> >
<MinusIcon />
</button> </button>
<button <button
@click="emit('close')" @click="emit('close')"
class="p-1 rounded bg-red-500 text-white hover:bg-red-600 transition duration-200" class="p-1 rounded bg-red-500 text-white hover:bg-red-600 transition duration-200"
> >
<XIcon />
</button> </button>
</div> </div>
</div> </div>

View file

@ -51,6 +51,7 @@ const pullTabsData = async () => {
}; };
const updateContent = async (url: string, tabAction: boolean) => { const updateContent = async (url: string, tabAction: boolean) => {
contentArray.value = [];
if (tabAction === true) { if (tabAction === true) {
primary.value = url; primary.value = url;
switchTabs.value = true; switchTabs.value = true;

View file

@ -19,7 +19,7 @@ const {
data: source, data: source,
pending, pending,
error, error,
} = await useFetch("/api/cached/getData/fetchSources", { } = await useFetch("/api/publishers/lt_all", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",

View file

@ -23,21 +23,6 @@ const usersList = await sql`
) )
`; `;
const createNewsProviders = await sql`
create table if not exists newsProviders (
uuid text primary key,
title text not null,
slug text unique,
website text not null,
description text not null,
facebookUrl text,
twitterUrl text,
threadsUrl text,
logoUrl text not null,
lean text not null
)
`;
const createUserAiChatHistory = await sql` const createUserAiChatHistory = await sql`
CREATE TABLE IF NOT EXISTS chat_history ( CREATE TABLE IF NOT EXISTS chat_history (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
@ -47,38 +32,7 @@ CREATE TABLE IF NOT EXISTS chat_history (
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)`; )`;
const newsArticles = await sql` const createSources = await sql``;
create table if not exists news_articles (
uuid text primary key,
title text not null,
content text not null,
news_org text not null,
origin_link text not null,
author text,
related_uuid text not null
)
`;
const hotNews = await sql`
create table if not exists hot_news (
uuid text primary key,
title text not null,
news_org text not null,
link text not null,
related_uuid text not null,
created_at timestamptz default current_timestamp
)
`;
const articlesLt = await sql`
create table if not exists articles_lt (
uuid text primary key,
title text not null,
content text not null,
origin text not null,
author text
)
`;
console.log("Creation Complete"); console.log("Creation Complete");

View file

@ -1,14 +0,0 @@
export default defineEventHandler(async (event) => {
const slug = getRouterParam(event, "slug");
const body = await readBody(event);
return {
body: body,
title: "News Org 1",
slug: "taisounds",
website: "https://yuanhau.com",
description: "wah wah wah wah wah wah I dont fucking care",
facebook: "https://www.facebook.csdkc",
logoUrl:
"https://cdn.discordapp.com/avatars/918723093646684180/4eecc27ac05ee8a701fa167808610c7a.jpg",
};
});

View file

@ -1,27 +0,0 @@
import sql from "~/server/components/postgres";
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const query = getQuery(event);
/*const sources = await sql`SELECT * FROM sources`;
return sources;*/
// Fake data
return {
status: "ok",
data: [
{
id: 1,
title: "Source 1",
logo: "#",
url: "https://source1.com",
description: "Description for Source 1",
},
{
id: 2,
title: "Source 2",
logo: "#",
url: "https://source2.com",
description: "Description for Source 2",
},
],
};
});

View file

@ -0,0 +1,44 @@
import sql from "~/server/components/postgres";
const createUsers = await sql`
create table if not exists users (
uuid text primary key,
created_at timestamptz default current_timestamp,
username text not null unique,
avatarurl text,
firstname text,
passwordhash text not null,
email text
);
`;
const usersList = await sql`
create table if not exists usertokens (
token text not null primary key,
created_at timestamptz default current_timestamp,
username text not null,
email text,
avatarurl text,
firstname text
)
`;
const createUserAiChatHistory = await sql`
CREATE TABLE IF NOT EXISTS chat_history (
id SERIAL PRIMARY KEY,
uuid VARCHAR(255) NOT NULL,
role VARCHAR(50) NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)`;
const createSources = await sql``;
export default defineEventHandler(async (event) => {
return {
createUsers: createUsers,
usersList: usersList,
createUserAiChatHistory: createUserAiChatHistory,
createSources: createSources,
};
});

View file

@ -1,10 +0,0 @@
import s3 from "~/server/components/s3";
export default defineEventHandler(async (event) => {
const slug = getRouterParam(event, "slug");
return sendRedirect(
event,
`${process.env.S3_ENDPOINT}/${process.env.S3_BUCKETNAME}/${slug}`,
302,
);
});

View file

@ -1,8 +1,43 @@
// TODO Add caching import sql from "~/server/components/postgres";
import * as cheerio from "cheerio"; import * as cheerio from "cheerio";
// Caching
interface CacheItems {
slug: string;
title: string;
description: string;
articles: any[];
timestamp: number;
}
const CACHE_DURATION = 1000 * 60 * 30;
const cache: Record<string, CacheItems> = {};
function cleanupCache() {
const now = Date.now();
Object.keys(cache).forEach((key) => {
if (now - cache[key].timestamp > CACHE_DURATION) {
delete cache[key];
}
});
}
setInterval(cleanupCache, CACHE_DURATION);
export default defineEventHandler(async (event) => { export default defineEventHandler(async (event) => {
const slug = getRouterParam(event, "slug"); const slug = getRouterParam(event, "slug");
if (!slug) {
return {
error: "NO_SLUG_PROVIDED",
};
}
if (cache[slug] && Date.now() - cache[slug].timestamp < CACHE_DURATION) {
return {
...cache[slug],
cached: true,
};
}
const buildUrl = "https://today.line.me/tw/v3/publisher/" + slug; const buildUrl = "https://today.line.me/tw/v3/publisher/" + slug;
try { try {
const req = await fetch(buildUrl, { const req = await fetch(buildUrl, {
@ -25,37 +60,42 @@ export default defineEventHandler(async (event) => {
.text() .text()
.replace(/.css-.*\}/, ""); .replace(/.css-.*\}/, "");
const description = html("p.description").text(); const description = html("p.description").text();
const logoClue = html("div.editor").contents();
const logo =
logoClue.find("img").attr("srcset") ||
html("div.editor div figure img").attr("src") ||
"";
const bgImage = html("figure.keyVisual img").attr("srcset") || "";
const articles = [];
const regexArticleLinks = /[a-zA-Z0-9]{7}/g; const regexArticleLinks = /[a-zA-Z0-9]{7}/g;
const otherArticles = <any[]>[]; const otherArticles = <any[]>[];
html("a.ltcp-link").each((i, element) => { html("a.ltcp-link").each((i, element) => {
const articleLink = html(element).attr("href"); const articleLink = html(element).attr("href");
const articleTitle = html(element).find("h3.header").text(); const articleTitle = html(element).find("h3.header").text();
//const image = html(element).find("figure").attr("src");
console.log(html(element).find("img"));
console.log("----------");
const date = html(element) const date = html(element)
.find("div._articleCard div.css-wqleh6 span") .find("div._articleCard div.css-wqleh6 span")
.text(); .text();
if (articleLink && articleTitle) { if (articleLink && articleTitle) {
const articleSlug = articleLink.matchAll(regexArticleLinks); const articleSlug = articleLink
.replaceAll("article", "")
.match(regexArticleLinks);
otherArticles.push({ otherArticles.push({
index: i, index: i,
title: articleTitle, title: articleTitle,
link: articleSlug, link: articleSlug[0],
date: date, date: date,
//image: image || "/geterrorassets/noImageLogo.svg",
}); });
} }
}); });
cache[slug] = {
slug: slug,
title: newsOrgName,
description: description,
articles: otherArticles,
timestamp: Date.now(),
};
return { return {
title: newsOrgName, title: newsOrgName,
description: description, description: description,
logo: logo,
articles: otherArticles, articles: otherArticles,
logoClue: String(logoClue), cached: false,
}; };
} catch (e) { } catch (e) {
console.log(e); console.log(e);

View file

@ -0,0 +1,17 @@
import sql from "~/server/components/postgres";
export default defineEventHandler(async (event) => {
try {
const fetchDataInSQL = await sql`
SELECT * FROM lt_news_org;
`;
return {
data: fetchDataInSQL,
};
} catch (e) {
console.log(e);
return {
error: "SERVER_SIDE_ERR",
elogs: e.message,
};
}
});

View file

@ -1,3 +0,0 @@
export default defineEventHandler(async (event) => {
return {};
});