Skip to content

Commit

Permalink
add: daiog option
Browse files Browse the repository at this point in the history
  • Loading branch information
puemos committed Apr 22, 2020
1 parent feb8f87 commit b369f9f
Show file tree
Hide file tree
Showing 21 changed files with 158 additions and 93 deletions.
12 changes: 6 additions & 6 deletions src/core/src/adapters/redux/slices/config-slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
export interface ISetConcurrencyPayload {
concurrency: number;
}
export interface ISetAutoSavePayload {
autoSave: boolean;
export interface ISetSaveDialogPayload {
saveDialog: boolean;
}

export interface IConfigState {
concurrency: number;
autoSave: boolean;
saveDialog: boolean;
}
const initialConfigState: IConfigState = {
concurrency: 2,
autoSave: false,
saveDialog: false,
};

export const configSlice = createSlice({
Expand All @@ -23,8 +23,8 @@ export const configSlice = createSlice({
setConcurrency(state, action: PayloadAction<ISetConcurrencyPayload>) {
state.concurrency = action.payload.concurrency;
},
setAutosave(state, action: PayloadAction<ISetAutoSavePayload>) {
state.autoSave = action.payload.autoSave;
setSaveDialog(state, action: PayloadAction<ISetSaveDialogPayload>) {
state.saveDialog = action.payload.saveDialog;
},
},
});
13 changes: 3 additions & 10 deletions src/core/src/controllers/inc-download-status-epic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,12 @@ export const incDownloadStatusEpic: Epic<
filter(({ status }) => Boolean(status)),
filter(({ status }) => status!.done === status!.total),
mergeMap(({ id }) => {
if (store$.value.config.autoSave) {
return of(
levelsSlice.actions.finishLevelDownload({
levelID: id,
}),
levelsSlice.actions.saveLevelToFile({
levelID: id,
})
);
}
return of(
levelsSlice.actions.finishLevelDownload({
levelID: id,
}),
levelsSlice.actions.saveLevelToFile({
levelID: id,
})
);
})
Expand Down
37 changes: 30 additions & 7 deletions src/core/src/controllers/save-level-to-file-epic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,50 @@ import { filter, map, mergeMap } from "rxjs/operators";
import { RootState, RootAction } from "../adapters/redux/root-reducer";
import { levelsSlice } from "../adapters/redux/slices/levels-slice";
import { Dependencies } from "../services";
import { mergeBucketFactory, writeToFileFactory } from "../use-cases";
import {
mergeBucketFactory,
writeToFileFactory,
generateFileName,
} from "../use-cases";

export const saveLevelToFileEpic: Epic<
RootAction,
RootAction,
RootState,
Dependencies
> = (action$, _store$, { fs }) =>
> = (action$, store$, { fs }) =>
action$.pipe(
filter(levelsSlice.actions.saveLevelToFile.match),
map((action) => action.payload.levelID),
mergeMap(
(levelID) => from(mergeBucketFactory(fs)(levelID)),
(levelID, data) => ({ levelID, data })
),
map(({ levelID, data }) => ({
level: store$.value.levels.levels[levelID]!,
data,
})),
map(({ level, data }) => ({
level,
playlist: store$.value.playlists.playlists[level.playlistID]!,
data,
})),
map(({ level, data, playlist }) => ({
level,
filename: generateFileName()(playlist, level),
dialog: store$.value.config.saveDialog,
data,
})),
mergeMap(
({ levelID, data }) =>
from(writeToFileFactory(fs)(`${levelID}.mp4`, data)),
({ levelID }) => ({ levelID })
({ dialog, filename, data }) =>
from(
writeToFileFactory(fs)(filename, data, {
dialog,
})
),
({ level }) => ({ level })
),
mergeMap(({ levelID }) =>
of(levelsSlice.actions.saveLevelToFileSuccess({ levelID: levelID }))
mergeMap(({ level }) =>
of(levelsSlice.actions.saveLevelToFileSuccess({ levelID: level.id }))
)
);
8 changes: 7 additions & 1 deletion src/core/src/services/fs.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
export interface IFS {
getBucket(id: string): Bucket;
createBucket(id: string, length: number): void;
write(path: string, data: ArrayBuffer): Promise<void>;
write(
path: string,
data: ArrayBuffer,
options: {
dialog: boolean;
}
): Promise<void>;
}

export interface Bucket {
Expand Down
16 changes: 16 additions & 0 deletions src/core/src/use-cases/generate-file-name.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Playlist, Level } from "../entities";

export const generateFileName = () => {
const run = (playlist: Playlist, level: Level): string => {
const path = playlist.uri.split("?")[0];
const chunks = path.split("/");
const playlistFilename = chunks[chunks.length - 1];
const playlistFilenameWithoutExt = playlistFilename.split(".m3u8")[0];

if (playlist.pageTitle) {
return `${playlist.pageTitle}-${playlistFilenameWithoutExt}.ts`;
}
return `${playlistFilenameWithoutExt}.ts`;
};
return run;
};
1 change: 1 addition & 0 deletions src/core/src/use-cases/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from "./get-levels";
export * from "./merge-bucket";
export * from "./write-to-bucket";
export * from "./write-to-file";
export * from "./generate-file-name";
8 changes: 6 additions & 2 deletions src/core/src/use-cases/write-to-file.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { IFS } from "../services";

export const writeToFileFactory = (fs: IFS) => {
const run = async (path: string, data: ArrayBuffer): Promise<void> => {
await fs.write(path, data);
const run = async (
path: string,
data: ArrayBuffer,
options: { dialog: boolean }
): Promise<void> => {
await fs.write(path, data, options);
};
return run;
};
1 change: 1 addition & 0 deletions src/extension/extension-background/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@types/uuid": "^7.0.2",
"@videojs/vhs-utils": "^1.3.0",
"m3u8-parser": "^4.4.0",
"sanitize-filename": "^1.6.3",
"ts-loader": "^7.0.0",
"url-toolkit": "^2.1.6",
"uuid": "^7.0.3",
Expand Down
15 changes: 11 additions & 4 deletions src/extension/extension-background/src/services/in-memory-fs.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Bucket, IFS } from "@hls-downloader/core/lib/services";
import { browser } from "webextension-polyfill-ts";

import sanitize from "sanitize-filename";
const buckets: Record<string, Bucket> = {};

export class InMemoryBucket implements Bucket {
Expand Down Expand Up @@ -39,17 +39,24 @@ const getBucket: IFS["getBucket"] = function (id: string) {
return buckets[id];
};

const write: IFS["write"] = async function (path: string, data: Uint8Array) {
const write: IFS["write"] = async function (
path: string,
data: Uint8Array,
{ dialog }
) {
window.URL = window.URL || window.webkitURL;
const blob = new Blob([data], {
type: "video/MP2T",
});
const url = URL.createObjectURL(blob);
const filename = sanitize(path ?? "steam.mp4");
console.log({ filename });

await browser.downloads.download({
url,
saveAs: true,
saveAs: dialog,
conflictAction: "uniquify",
filename: "steam.mp4",
filename,
});
URL.revokeObjectURL(url);
return Promise.resolve();
Expand Down
19 changes: 19 additions & 0 deletions src/extension/extension-background/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2489,6 +2489,13 @@ safe-regex@^1.1.0:
dependencies:
ret "~0.1.10"

sanitize-filename@^1.6.3:
version "1.6.3"
resolved "https://registry.yarnpkg.com/sanitize-filename/-/sanitize-filename-1.6.3.tgz#755ebd752045931977e30b2025d340d7c9090378"
integrity sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==
dependencies:
truncate-utf8-bytes "^1.0.0"

schema-utils@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770"
Expand Down Expand Up @@ -2854,6 +2861,13 @@ to-regex@^3.0.1, to-regex@^3.0.2:
regex-not "^1.0.2"
safe-regex "^1.1.0"

truncate-utf8-bytes@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b"
integrity sha1-QFkjkJWS1W94pYGENLC3hInKXys=
dependencies:
utf8-byte-length "^1.0.1"

ts-loader@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-7.0.0.tgz#7c74dfa8956e3e33b91d98d4ed7b6f7575c35c25"
Expand Down Expand Up @@ -2957,6 +2971,11 @@ use@^3.1.0:
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==

utf8-byte-length@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61"
integrity sha1-9F8VDExm7uloGGUFq5P8u4rWv2E=

util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
Expand Down
8 changes: 7 additions & 1 deletion src/extension/extension-popup/src/view/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { Box, Flex } from "@chakra-ui/core";
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import {
BrowserRouter as Router,
Route,
Switch,
Redirect,
} from "react-router-dom";
import { Navbar } from "./NavbarView";
import PlaylistsView from "./PlaylistsView";
import SettingsView from "./SettingsView";
Expand Down Expand Up @@ -37,6 +42,7 @@ function App() {
</style>
<Box overflowY="scroll" className="Main" height={500 - 72} pt="1rem">
<Switch>
<Redirect from="/index.html" to="/" />
<Route path="/settings">
<SettingsView />
</Route>
Expand Down
33 changes: 16 additions & 17 deletions src/extension/extension-popup/src/view/LevelView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { levelsSlice } from "@hls-downloader/core/lib/adapters/redux/slices";
import { Level, LevelStatus } from "@hls-downloader/core/lib/entities";
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { LevelProgressView } from "./LevelProgressView";

export const LevelView = (props: { level: Level }) => {
const status = useSelector<RootState, LevelStatus | null>(
Expand All @@ -27,30 +26,30 @@ export const LevelView = (props: { level: Level }) => {
bg="gray.800"
>
<Stack>
<Stack isInline spacing="1rem">
<Stack isInline spacing="0.2rem" width="24rem">
<Grid gridTemplateColumns="1.3fr 1fr 1fr" gridTemplateRows="1fr">
<Stack isInline spacing="0.4rem">
<Text color="#99a3ff">Resolution</Text>
{props.level.width && (
<Text color="gray.400">
{props.level.width}×{props.level.height}
</Text>
)}
</Stack>
<Stack isInline spacing="0.2rem">
<Stack isInline spacing="0.4rem">
<Text color="#99a3ff">Bitrate</Text>
<Text color="gray.400">{props.level.bitrate}</Text>
</Stack>
<Box width="100%">
{["ready", "done", "saving", "downloading"].includes(
status?.status!
) && (
<LevelProgressView
status={status!}
levelID={props.level.id}
></LevelProgressView>
)}
</Box>
</Stack>
{["ready", "done", "saving", "downloading"].includes(
status?.status!
) && (
<Stack isInline spacing="0.4rem">
<Text color="#99a3ff">Progress</Text>
<Text textAlign="right" color="gray.400">{`${Number(
(100 * status!.done) / status!.total
).toFixed(0)}%`}</Text>
</Stack>
)}
</Grid>
<Box>
<Input
size="sm"
Expand All @@ -69,16 +68,16 @@ export const LevelView = (props: { level: Level }) => {
onClick={onSaveLevelClick}
/>
)}

{["init", "downloading"].includes(status?.status!) && (
<IconButton
icon="arrow-forward"
icon="download"
aria-label="download"
isDisabled={status?.status === "downloading"}
isLoading={status?.status === "downloading"}
onClick={onDownloadLevelClick}
/>
)}
)}
</Stack>
</Grid>
);
Expand Down
23 changes: 23 additions & 0 deletions src/extension/extension-popup/src/view/NavLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Box, Heading, Link, Stack } from "@chakra-ui/core";
import React from "react";
import { useHistory, useLocation } from "react-router-dom";

export function NavLink(props: { path: string; label: string, width: string }) {
const { pathname } = useLocation();
const { push } = useHistory();
return (
<Stack width={props.width} spacing="2px">
<Box w="100%">
<Link
_hover={{
textDecoration: "none",
}}
onClick={() => push(props.path)}
>
<Heading size="sm">{props.label}</Heading>
</Link>
</Box>
{pathname === props.path && <Box w="100%" bg="burlywood" h="2px"></Box>}
</Stack>
);
}
Loading

0 comments on commit b369f9f

Please sign in to comment.