Skip to content

Commit

Permalink
Direct downloads
Browse files Browse the repository at this point in the history
  • Loading branch information
puemos committed May 9, 2024
1 parent 54ff6bc commit 268e7b4
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 6 deletions.
4 changes: 2 additions & 2 deletions src/core/src/use-cases/generate-file-name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ export const generateFileName = () => {
const playlistFilenameWithoutExt = playlistFilename.split(".m3u8")[0];

if (playlist.pageTitle) {
return `${playlist.pageTitle}-${playlistFilenameWithoutExt}.ts`;
return `${playlist.pageTitle}-${playlistFilenameWithoutExt}.mp4`;
}
return `${playlistFilenameWithoutExt}.ts`;
return `${playlistFilenameWithoutExt}.mp4`;
};
return run;
};
63 changes: 63 additions & 0 deletions src/popup/src/modules/Direct/DirectController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Playlist, PlaylistStatus } from "@hls-downloader/core/lib/entities";
import { RootState } from "@hls-downloader/core/lib/store/root-reducer";
import {
levelsSlice,
playlistsSlice,
} from "@hls-downloader/core/lib/store/slices";
import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";

function isPlaylist(playlist: Playlist | null): playlist is Playlist {
return playlist !== null;
}

const useSnifferController = () => {
const [currentPlaylistId, setCurrentPlaylistId] = useState<
string | undefined
>(undefined);
const [filter, setFilter] = useState("");
const [directURI, setDirectURI] = useState("");
const [currentDirectURI, setCurrentDirectURI] = useState("");
const dispatch = useDispatch();
const playlistsRecord = useSelector<
RootState,
Record<string, Playlist | null>
>((state) => state.playlists.playlists);

function clearPlaylists() {
dispatch(levelsSlice.actions.clear());
dispatch(playlistsSlice.actions.clearPlaylists());
}

function addDirectPlaylist() {
setCurrentDirectURI(directURI);
dispatch(
playlistsSlice.actions.addPlaylist({
id: directURI,
uri: directURI,
createdAt: Date.now(),
initiator: "Direct",
}),
);
}

const playlists = Object.values(playlistsRecord)
.filter(isPlaylist)
.filter(({ uri }) => uri === currentDirectURI);

playlists.sort((a, b) => b.createdAt - a.createdAt);

return {
filter,
clearPlaylists,
setFilter,
setCurrentPlaylistId,
playlists,
currentPlaylistId,
addDirectPlaylist,
directURI,
setDirectURI,
};
};

export default useSnifferController;
33 changes: 33 additions & 0 deletions src/popup/src/modules/Direct/DirectModule.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from "react";
import DirectView from "./DirectView";
import useDirectController from "./DirectController";

const DirectModule = () => {
const {
clearPlaylists,
setFilter,
filter,
setCurrentPlaylistId,
playlists,
currentPlaylistId,
addDirectPlaylist,
directURI,
setDirectURI,
} = useDirectController();

return (
<DirectView
filter={filter}
clearPlaylists={clearPlaylists}
setFilter={setFilter}
setCurrentPlaylistId={setCurrentPlaylistId}
playlists={playlists}
currentPlaylistId={currentPlaylistId}
addDirectPlaylist={addDirectPlaylist}
directURI={directURI}
setDirectURI={setDirectURI}
></DirectView>
);
};

export default DirectModule;
114 changes: 114 additions & 0 deletions src/popup/src/modules/Direct/DirectView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { Playlist } from "@hls-downloader/core/lib/entities";
import { Button, Input, ScrollArea, cn } from "@hls-downloader/design-system";
import { Banana } from "lucide-react";
import React from "react";
import PlaylistModule from "../Playlist/PlaylistModule";

interface Props {
playlists: Playlist[];
currentPlaylistId: string | undefined;
filter: string;
directURI: string;
clearPlaylists: () => void;
addDirectPlaylist: () => void;
setCurrentPlaylistId: (playlistId?: string) => void;
setFilter: (filter: string) => void;
setDirectURI: (filter: string) => void;
}

const DirectView = ({
clearPlaylists,
setFilter,
filter,
playlists,
currentPlaylistId,
setCurrentPlaylistId,
addDirectPlaylist,
directURI,
setDirectURI,
}: Props) => {
const showFilterInput = playlists.length !== 0;

return (
<div className="flex flex-col p-1 mt-4 space-y-3">
{currentPlaylistId && (
<>
<Button
onClick={() => setCurrentPlaylistId()}
size="sm"
variant="outline"
>
Back
</Button>
<PlaylistModule id={currentPlaylistId}></PlaylistModule>
</>
)}
{!currentPlaylistId && (
<div className="flex flex-row items-center justify-between gap-2">
<Input
type="text"
className="p-2 border rounded-md"
placeholder="https://.../playlist.m3u8"
value={directURI}
onChange={(e) => setDirectURI(e.target.value)}
/>
<Button
size={"default"}
variant={"outline"}
onClick={addDirectPlaylist}
>
Add
</Button>
</div>
)}
{!currentPlaylistId && playlists.length === 0 && (
<div className="flex flex-col items-center justify-center pt-36">
<Banana></Banana>

<h3 className="mt-4 text-lg font-semibold">No videos</h3>
<p className="mt-2 mb-4 text-sm text-muted-foreground">
Enter an URI and hit the Add button
</p>
</div>
)}
{!currentPlaylistId && playlists.length > 0 && (
<ScrollArea className="h-[calc(100vh-10rem)] w-full">
{playlists.map((item) => (
<div
key={item.id}
className={cn(
"flex flex-col mb-2 items-start gap-2 rounded-lg border p-3 text-left text-sm",
)}
>
<div className="flex flex-col w-full gap-1">
<div className="flex items-center">
<div className="flex items-center gap-2">
<div className="font-semibold">{item.pageTitle}</div>
</div>
<div className={cn("ml-auto text-xs")}>
{new Date(item.createdAt!).toLocaleString()}
</div>
</div>
<div className="text-xs font-medium">{item.initiator}</div>
</div>
<div className="text-xs break-all text-muted-foreground">
{item.uri}
</div>
<div className="flex flex-row-reverse w-full">
<Button
onClick={() => setCurrentPlaylistId(item.id)}
size="sm"
variant="outline"
>
Select
</Button>
</div>
</div>
))}
</ScrollArea>
)}
</div>
);
};

export default DirectView;
1 change: 1 addition & 0 deletions src/popup/src/modules/Navbar/RouterController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const useRouterController = (): ReturnType => {
TabOptions.DOWNLOADS,
TabOptions.SETTINGS,
TabOptions.SNIFTER,
TabOptions.DIRECT,
].includes(tab as Tab)
) {
setTab(tab as Tab);
Expand Down
5 changes: 5 additions & 0 deletions src/popup/src/modules/Navbar/RouterView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import SettingsModule from "../Settings/SettingsModule";
import SnifferModule from "../Sniffer/SnifferModule";
import { RouterContext } from "./RouterContext";
import { TabOptions } from "./types";
import DirectModule from "../Direct/DirectModule";

const RouterView = () => {
const { tab, setTab } = useContext(RouterContext);
Expand All @@ -20,6 +21,7 @@ const RouterView = () => {
<div className="flex justify-center">
<TabsList>
<TabsTrigger value={TabOptions.SNIFTER}>Sniffer</TabsTrigger>
<TabsTrigger value={TabOptions.DIRECT}>Direct</TabsTrigger>
<TabsTrigger value={TabOptions.DOWNLOADS}>Downloads</TabsTrigger>
<TabsTrigger value={TabOptions.SETTINGS}>Settings</TabsTrigger>
<TabsTrigger value={TabOptions.ABOUT}>About</TabsTrigger>
Expand All @@ -28,6 +30,9 @@ const RouterView = () => {
<TabsContent value={TabOptions.SNIFTER}>
<SnifferModule />
</TabsContent>
<TabsContent value={TabOptions.DIRECT}>
<DirectModule />
</TabsContent>
<TabsContent value={TabOptions.DOWNLOADS}>
<DownloadsModule />
</TabsContent>
Expand Down
4 changes: 3 additions & 1 deletion src/popup/src/modules/Navbar/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ export type Tab =
| TabOptions.ABOUT
| TabOptions.DOWNLOADS
| TabOptions.SETTINGS
| TabOptions.SNIFTER;
| TabOptions.SNIFTER
| TabOptions.DIRECT;

export enum TabOptions {
SNIFTER = "sniffer",
DIRECT = "direct",
DOWNLOADS = "downloads",
SETTINGS = "settings",
ABOUT = "about",
Expand Down
8 changes: 5 additions & 3 deletions src/popup/src/modules/Sniffer/SnifferController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ const playlistFilter =
return false;
};

function isPlaylist(playlist: Playlist | null): playlist is Playlist {
return playlist !== null;
}

const useSnifferController = (): ReturnType => {
const [currentPlaylistId, setCurrentPlaylistId] = useState<
string | undefined
Expand All @@ -54,9 +58,7 @@ const useSnifferController = (): ReturnType => {
dispatch(levelsSlice.actions.clear());
dispatch(playlistsSlice.actions.clearPlaylists());
}
function isPlaylist(playlist: Playlist | null): playlist is Playlist {
return playlist !== null;
}

const playlists = Object.values(playlistsRecord)
.filter(isPlaylist)
.filter(
Expand Down

0 comments on commit 268e7b4

Please sign in to comment.