diff --git a/lib/routes/newswav/latest.ts b/lib/routes/newswav/latest.ts
new file mode 100644
index 000000000..954024ce4
--- /dev/null
+++ b/lib/routes/newswav/latest.ts
@@ -0,0 +1,100 @@
+import { Route } from '@/types';
+import cache from '@/utils/cache';
+import ofetch from '@/utils/ofetch';
+import { load } from 'cheerio';
+import { parseDate } from '@/utils/parse-date';
+
+export const route: Route = {
+ path: '/',
+ categories: ['new-media'],
+ example: '/newswav',
+ features: {
+ requireConfig: false,
+ requirePuppeteer: false,
+ antiCrawler: false,
+ supportBT: false,
+ supportPodcast: false,
+ supportScihub: false,
+ },
+ radar: [
+ {
+ source: ['newswav.com/latest', 'newswav.com'],
+ },
+ ],
+ name: 'Latest',
+ maintainers: ['TonyRL'],
+ handler,
+};
+
+async function handler() {
+ const baseUrl = 'https://newswav.com';
+
+ const response = await ofetch(`https://feed-api.newswav.com/api/web/feeds/latest`, {
+ query: {
+ languages: 'en,ms,zh',
+ },
+ });
+
+ const list = response.data.content
+ .filter((i) => i.contentId !== 'AD')
+ .map((i) => ({
+ title: i.title,
+ description: i.description,
+ category: i.topics.map((topic) => topic.en),
+ link: `${baseUrl}/article/${i.permalink}`,
+ permalink: i.permalink,
+ pubDate: parseDate(i.publishedAt),
+ author: i.publisher.name,
+ image: i.thumbnailUrl,
+ }));
+
+ const items = await Promise.all(
+ list.map((item) =>
+ cache.tryGet(item.link, async () => {
+ const response = await ofetch(`https://api.newswav.com/v4/api/v1/web/contents/${item.permalink}`);
+
+ if (response.contentType === 'video') {
+ const video = response.meta.video;
+ item.description = `
${video.content}`;
+
+ return item;
+ } else if (response.contentType === 'podcast') {
+ const podcast = response.meta.podcast;
+ item.description = `
${podcast.content}`;
+ item.enclosure_type = 'audio/mpeg';
+
+ return item;
+ }
+
+ const article = response.meta.article;
+ const $ = load(article.content);
+
+ $('*')
+ .contents()
+ .filter((_, element) => element.type === 'comment' && element.data.trim() === 'AD')
+ .remove();
+
+ $('iframe').each((_, element) => {
+ const $element = $(element);
+ if ($element.attr('src')?.includes('ga4-track.html') || $element.attr('src')?.includes('ga4-v2-track.html')) {
+ $element.remove();
+ }
+ });
+
+ item.description = $.html();
+
+ const image = new URL(article.originalUrl);
+ item.image = image.pathname.startsWith('/1000x0,q50=/') ? image.pathname.replace('/1000x0,q50=/', '') : image.pathname;
+
+ return item;
+ })
+ )
+ );
+
+ return {
+ title: 'Newswav - Malaysia’s #1 Content Aggregator | Malaysia Breaking News, World News, and Latest News',
+ description: 'Latest news, videos and podcasts on Politics, Lifestyle, Sports, Current Affairs, Business & Finance, Entertainment and more from Malaysia & around the world.',
+ link: `${baseUrl}/latest`,
+ item: items,
+ };
+}
diff --git a/lib/routes/newswav/namespace.ts b/lib/routes/newswav/namespace.ts
new file mode 100644
index 000000000..1ee0e5cf8
--- /dev/null
+++ b/lib/routes/newswav/namespace.ts
@@ -0,0 +1,7 @@
+import type { Namespace } from '@/types';
+
+export const namespace: Namespace = {
+ name: 'Newswav',
+ url: 'newswav.com',
+ lang: 'en',
+};