Fix audible provider & add more YT channel (#618)

* add more youtube channel

* fix audible provider

* fix youtube video card style
This commit is contained in:
an-lee
2024-05-17 11:36:35 +08:00
committed by GitHub
parent 47fe3f430d
commit 2d58c9ac63
7 changed files with 49 additions and 46 deletions

View File

@@ -16,20 +16,18 @@ export class AudibleProvider {
return new Promise<string>((resolve, _reject) => {
const view = new WebContentsView();
view.webContents.loadURL(this.baseURL + path);
view.webContents.on("did-finish-load", () => {
logger.debug(`Scraped ${this.baseURL + path}`);
view.webContents.on("did-stop-loading", () => {
logger.debug(`Finish loading ${this.baseURL + path}`);
view.webContents
.executeJavaScript(`document.documentElement.innerHTML`)
.then((html) => {
resolve(html as string);
})
.catch((err) => {
resolve("");
})
.finally(() => view.webContents.close());
});
view.webContents.on("did-fail-load", () => {
logger.warn(`Failed to scrape ${this.baseURL + path}`);
view.webContents.close();
resolve("");
});
});
};

View File

@@ -11,23 +11,19 @@ export class TedProvider {
view.webContents.loadURL(url);
logger.debug("started scraping", url);
view.webContents.on("did-finish-load", () => {
logger.debug("finished scraping", url);
view.webContents.on("did-stop-loading", () => {
logger.debug("finished loading", url);
view.webContents
.executeJavaScript(`document.documentElement.innerHTML`)
.then((html) => resolve(html as string))
.catch((error) => {
logger.warn("Failed to scrape", url, error);
resolve("");
})
.finally(() => {
view.webContents.close();
});
});
view.webContents.on(
"did-fail-load",
(_event, _errorCode, error, validatedURL) => {
logger.warn("Failed to scrape", url, error, validatedURL);
view.webContents.close();
resolve("");
}
);
});
};

View File

@@ -11,11 +11,15 @@ export class YoutubeProvider {
view.webContents.loadURL(url);
logger.debug("started scraping", url);
view.webContents.on("did-finish-load", () => {
logger.debug("finished scraping", url);
view.webContents.on("did-stop-loading", () => {
logger.debug("finished loading", url);
view.webContents
.executeJavaScript(`document.documentElement.innerHTML`)
.then((html) => resolve(html as string))
.catch((error) => {
logger.warn("Failed to scrape", url, error);
resolve("");
})
.finally(() => {
view.webContents.close();
});
@@ -45,12 +49,13 @@ export class YoutubeProvider {
const videoList = videoContents
.filter((i: any) => i.richItemRenderer)
.map((video: any) => {
const thumbnails =
video.richItemRenderer.content.videoRenderer.thumbnail.thumbnails;
return {
title:
video.richItemRenderer.content.videoRenderer.title.runs[0].text,
thumbnail:
video.richItemRenderer.content.videoRenderer.thumbnail
.thumbnails[0].url,
thumbnail: thumbnails[thumbnails.length - 1].url,
videoId: video.richItemRenderer.content.videoRenderer.videoId,
duration:
video.richItemRenderer.content.videoRenderer.lengthText
@@ -65,18 +70,21 @@ export class YoutubeProvider {
}
};
videos = async () => {
const html = await this.scrape("https://www.youtube.com/@CNN/videos");
videos = async (channel: string) => {
const html = await this.scrape(`https://www.youtube.com/${channel}/videos`);
return this.extractVideos(html);
};
registerIpcHandlers = () => {
ipcMain.handle("youtube-provider-videos", async () => {
try {
return await this.videos();
} catch (error) {
logger.error(error);
ipcMain.handle(
"youtube-provider-videos",
async (_event, channel: string) => {
try {
return await this.videos(channel);
} catch (error) {
logger.error(error);
}
}
});
);
};
}

View File

@@ -85,8 +85,8 @@ contextBridge.exposeInMainWorld("__ENJOY_APP__", {
},
},
youtube: {
videos: () => {
return ipcRenderer.invoke("youtube-provider-videos");
videos: (channel: string) => {
return ipcRenderer.invoke("youtube-provider-videos", channel);
},
},
},

View File

@@ -15,7 +15,8 @@ import {
import { useNavigate } from "react-router-dom";
import { LoaderIcon } from "lucide-react";
export const YoutubeVideosSegment = () => {
export const YoutubeVideosSegment = (props: { channel: string }) => {
const { channel } = props;
const navigate = useNavigate();
const { EnjoyApp } = useContext(AppSettingsProviderContext);
const [videos, setvideos] = useState<YoutubeVideoType[]>([]);
@@ -46,18 +47,20 @@ export const YoutubeVideosSegment = () => {
};
const fetchYoutubeVideos = async () => {
const cachedVideos = await EnjoyApp.cacheObjects.get("youtube-videos");
const cachedVideos = await EnjoyApp.cacheObjects.get(
`youtube-videos-${channel}`
);
if (cachedVideos) {
setvideos(cachedVideos);
return;
}
EnjoyApp.providers.youtube
.videos()
.videos(channel)
.then((videos) => {
if (!videos) return;
EnjoyApp.cacheObjects.set("youtube-videos", videos, 60 * 10);
EnjoyApp.cacheObjects.set(`youtube-videos-${channel}`, videos, 60 * 10);
setvideos(videos);
})
.catch((err) => {
@@ -90,7 +93,7 @@ export const YoutubeVideosSegment = () => {
<div className="flex items-start justify-between mb-4">
<div className="space-y-1">
<h2 className="text-2xl font-semibold tracking-tight capitalize">
{t("from")} Youtube CNN
{t("from")} Youtube {channel}
</h2>
</div>
<div className="ml-auto mr-4"></div>
@@ -183,18 +186,18 @@ const YoutubeVideoCard = (props: {
return (
<div onClick={onClick} className="w-64 cursor-pointer">
<div className="aspect-[4/2.5] border rounded-lg overflow-hidden relative">
<div className="aspect-[16/9] border rounded-lg overflow-hidden relative mb-4">
<img
src={video.thumbnail}
alt={video.title}
className="hover:scale-105 object-cover w-screen"
className="hover:scale-105 object-cover w-full h-full"
/>
<div className="absolute bottom-0 left-0 right-0 p-2 bg-black bg-opacity-50">
<div className="text-xs text-white text-right">{video.duration}</div>
</div>
</div>
<div className="text-sm font-semibold mt-4 max-w-full h-5 mb-10">
<div className="text-sm font-semibold h-10 max-w-full line-clamp-2">
{video.title}
</div>
</div>

View File

@@ -2,9 +2,7 @@ import {
AudiosSegment,
AudibleBooksSegment,
StoriesSegment,
TedIdeasSegment,
VideosSegment,
TedTalksSegment,
YoutubeVideosSegment,
} from "@renderer/components";
@@ -16,9 +14,9 @@ export default () => {
<VideosSegment />
<StoriesSegment />
<AudibleBooksSegment />
<TedTalksSegment />
<TedIdeasSegment />
<YoutubeVideosSegment />
<YoutubeVideosSegment channel="@TED" />
<YoutubeVideosSegment channel="@CNN" />
<YoutubeVideosSegment channel="@nytimes" />
</div>
</div>
);

View File

@@ -42,7 +42,7 @@ type EnjoyAppType = {
downloadTalk: (url: string) => Promise<{ audio: string; video: string }>;
};
youtube: {
videos: () => Promise<YoutubeVideoType[]>;
videos: (channel: string) => Promise<YoutubeVideoType[]>;
};
};
view: {