🏗 Refactoring AirDCPPSocket init and download handling

This commit is contained in:
2022-06-09 00:55:39 -07:00
parent 2943000db3
commit a73250d99c
12 changed files with 155 additions and 126 deletions

View File

@@ -265,7 +265,6 @@ export const getTransfers =
true,
);
}
console.log(ADCPPSocket);
const foo = await ADCPPSocket.get("queue/bundles/1/50", {});
console.log(foo);
} catch (err) {

View File

@@ -58,6 +58,11 @@ pre {
.navbar {
border-bottom: 1px solid #f2f1f9;
.download-progress-meter {
margin-left: -300px;
min-width: 500px;
}
}
.navbar-item.is-mega {

View File

@@ -1,5 +1,5 @@
import React, { ReactElement, useState } from "react";
import { useSelector } from "react-redux";
import React, { ReactElement, useContext, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import Dashboard from "./Dashboard/Dashboard";
import Import from "./Import";
@@ -18,7 +18,11 @@ import { Routes, Route } from "react-router-dom";
import Navbar from "./Navbar";
import "../assets/scss/App.scss";
import Notifications from "react-notification-system-redux";
import { AirDCPPSocketContext } from "../context/AirDCPPSocket";
import {
AirDCPPSocketContextProvider,
AirDCPPSocketContext,
} from "../context/AirDCPPSocket";
import { isNil } from "lodash";
//Optional styling
const style = {
@@ -66,10 +70,26 @@ const style = {
export const App = (): ReactElement => {
const notifications = useSelector((state: RootState) => state.notifications);
const [ADCPPSocket, setADCPPSocket] = useState({});
const airDCPPConfiguration = useContext(AirDCPPSocketContext);
const { AirDCPPSocket } = airDCPPConfiguration;
useEffect(() => {
const addQueueListener = async () => {
if (!isNil(AirDCPPSocket)) {
await AirDCPPSocket.addListener(
"queue",
"queue_bundle_added",
async (data) => console.log("JEMEN:", data),
);
console.log(
"[AirDCPP]: Listener registered - listening to queue bundle changes",
);
}
};
addQueueListener();
}, [AirDCPPSocket]);
return (
<AirDCPPSocketContext.Provider value={{ ADCPPSocket, setADCPPSocket }}>
<AirDCPPSocketContextProvider>
<div>
<Navbar />
<Notifications
@@ -83,7 +103,7 @@ export const App = (): ReactElement => {
<Route path="/import" element={<Import path={"./comics"} />} />
<Route path="/library" element={<LibraryContainer />} />
<Route path="/library-grid" element={<LibraryGrid />} />
<Route path="/downloads" element={<Downloads />} />
<Route path="/downloads" element={<Downloads data={{}} />} />
<Route path="/search" element={<Search />} />
<Route
path={"/comic/details/:comicObjectId"}
@@ -99,7 +119,7 @@ export const App = (): ReactElement => {
<Route path="/volumes/all" element={<Volumes />} />
</Routes>
</div>
</AirDCPPSocketContext.Provider>
</AirDCPPSocketContextProvider>
);
};

View File

@@ -20,14 +20,14 @@ interface IAcquisitionPanelProps {
query: any;
comicObjectid: any;
comicObject: any;
userSettings: any;
settings: any;
}
export const AcquisitionPanel = (
props: IAcquisitionPanelProps,
): ReactElement => {
const issueName = props.query.issue.name || "";
const { userSettings } = props;
// const { settings } = props;
const sanitizedIssueName = issueName.replace(/[^a-zA-Z0-9 ]/g, " ");
// Selectors for picking state
@@ -44,23 +44,21 @@ export const AcquisitionPanel = (
(state: RootState) => state.airdcpp.searchInstance,
);
// const userSettings = useSelector((state: RootState) => state.settings.data);
const { ADCPPSocket } = useContext(AirDCPPSocketContext);
// const settings = useSelector((state: RootState) => state.settings.data);
const airDCPPConfiguration = useContext(AirDCPPSocketContext);
const { AirDCPPSocket, settings } = airDCPPConfiguration;
const dispatch = useDispatch();
const [dcppQuery, setDcppQuery] = useState({});
console.log(ADCPPSocket);
console.log(airDCPPConfiguration)
useEffect(() => {
if (!isNil(userSettings.directConnect)) {
if (!isNil(settings)) {
// AirDC++ search query
const dcppSearchQuery = {
query: {
pattern: `${sanitizedIssueName.replace(/#/g, "")}`,
extensions: ["cbz", "cbr", "cb7"],
},
hub_urls: map(
userSettings.directConnect.client.hubs,
(item) => item.value,
),
hub_urls: map(settings.directConnect.client.hubs, (item) => item.value),
priority: 5,
};
setDcppQuery(dcppSearchQuery);
@@ -74,20 +72,17 @@ export const AcquisitionPanel = (
pattern: `${searchQuery.issueName}`,
extensions: ["cbz", "cbr", "cb7"],
},
hub_urls: map(
userSettings.directConnect.client.hubs,
(item) => item.value,
),
hub_urls: map(settings.directConnect.client.hubs, (item) => item.value),
priority: 5,
};
dispatch(
search(manualQuery, ADCPPSocket, {
username: `${userSettings.directConnect.client.host.username}`,
password: `${userSettings.directConnect.client.host.password}`,
search(manualQuery, AirDCPPSocket, {
username: `${settings.directConnect.client.host.username}`,
password: `${settings.directConnect.client.host.password}`,
}),
);
},
[dispatch, ADCPPSocket],
[dispatch, AirDCPPSocket],
);
// download via AirDC++
@@ -99,18 +94,18 @@ export const AcquisitionPanel = (
resultId,
comicBookObjectId,
comicObject,
ADCPPSocket,
AirDCPPSocket,
{
username: `${userSettings.directConnect.client.host.username}`,
password: `${userSettings.directConnect.client.host.password}`,
username: `${settings.directConnect.client.host.username}`,
password: `${settings.directConnect.client.host.password}`,
},
),
);
// this is to update the download count badge on the downloads tab
dispatch(
getBundlesForComic(comicBookObjectId, ADCPPSocket, {
username: `${userSettings.directConnect.client.host.username}`,
password: `${userSettings.directConnect.client.host.password}`,
getBundlesForComic(comicBookObjectId, AirDCPPSocket, {
username: `${settings.directConnect.client.host.username}`,
password: `${settings.directConnect.client.host.password}`,
}),
);
},
@@ -119,7 +114,7 @@ export const AcquisitionPanel = (
return (
<>
<div className="comic-detail columns">
{!isEmpty(ADCPPSocket) ? (
{!isEmpty(AirDCPPSocket) ? (
<Form
onSubmit={getDCPPSearchResults}
initialValues={{
@@ -190,13 +185,11 @@ export const AcquisitionPanel = (
<dl>
<dt>
<div className="tags mb-1">
{userSettings.directConnect.client.hubs.map(
({ value }) => (
<span className="tag is-warning" key={value}>
{value}
</span>
),
)}
{settings.directConnect.client.hubs.map(({ value }) => (
<span className="tag is-warning" key={value}>
{value}
</span>
))}
</div>
</dt>
<dt>

View File

@@ -5,38 +5,18 @@ import { useParams } from "react-router-dom";
import { getComicBookDetailById } from "../../actions/comicinfo.actions";
import { ComicDetail } from "../ComicDetail/ComicDetail";
import { getSettings } from "../../actions/settings.actions";
import { AirDCPPSocketContext } from "../../context/AirDCPPSocket";
import AirDCPPSocket from "../../services/DcppSearchService";
export const ComicDetailContainer = (): ReactElement | null => {
const comicBookDetailData = useSelector(
(state: RootState) => state.comicInfo.comicBookDetail,
);
const dispatch = useDispatch();
useEffect(() => {
dispatch(getSettings());
}, [dispatch]);
const userSettings = useSelector((state: RootState) => state.settings.data);
const { ADCPPSocket, setADCPPSocket } = useContext(AirDCPPSocketContext);
useEffect(() => {
if (isEmpty(ADCPPSocket) && !isNil(userSettings.directConnect)) {
setADCPPSocket(
new AirDCPPSocket({
protocol: `${userSettings.directConnect.client.host.protocol}`,
hostname: `${userSettings.directConnect.client.host.hostname}`,
}),
);
}
}, [userSettings]);
const { comicObjectId } = useParams<{ comicObjectId: string }>();
useEffect(() => {
dispatch(getComicBookDetailById(comicObjectId));
// dispatch(getSettings());
}, [dispatch]);
return !isEmpty(comicBookDetailData) ? (
<ComicDetail data={comicBookDetailData} userSettings={userSettings} />
<ComicDetail data={comicBookDetailData} />
) : null;
};

View File

@@ -0,0 +1,35 @@
import prettyBytes from "pretty-bytes";
import React, { ReactElement } from "react";
export const DownloadProgressTick = (props): ReactElement => {
return (
<div className="box">
<h4 className="is-size-6">{props.data.name}</h4>
<div>
<span className="is-size-3 has-text-weight-semibold">
{prettyBytes(props.data.downloaded_bytes)} of{" "}
{prettyBytes(props.data.size)}{" "}
</span>
<progress
className="progress is-small is-success"
value={props.data.downloaded_bytes}
max={props.data.size}
>
{(parseInt(props.data.downloaded_bytes) / parseInt(props.data.size)) *
100}
%
</progress>
</div>
<div className="is-size-5">
{prettyBytes(props.data.speed)} per second.
</div>
<div className="is-size-5">
Time left:
{Math.round(parseInt(props.data.seconds_left) / 60)}
</div>
<div>{props.data.target}</div>
</div>
);
};
export default DownloadProgressTick;

View File

@@ -19,9 +19,6 @@ interface IDownloadsPanelProps {
export const DownloadsPanel = (
props: IDownloadsPanelProps,
): ReactElement | null => {
const downloadProgressTick = useSelector(
(state: RootState) => state.airdcpp.downloadProgressData,
);
const bundles = useSelector((state: RootState) => {
return state.airdcpp.bundles;
});
@@ -41,58 +38,12 @@ export const DownloadsPanel = (
password: `${userSettings.directConnect.client.host.password}`,
}),
);
dispatch(
getDownloadProgress(props.comicObjectId, ADCPPSocket, {
username: `${userSettings.directConnect.client.host.username}`,
password: `${userSettings.directConnect.client.host.password}`,
}),
);
}
} catch (error) {
throw new Error(error);
}
}, [dispatch]);
const ProgressTick = (props) => {
return (
<div className="column is-half">
{JSON.stringify(props.data.downloadProgressTick)}
<div className="card">
<div className="card-content is-size-7">
<dl>
<dt className="is-size-6">{props.data.name}</dt>
<dd>
<span className="is-size-3 has-text-weight-semibold">
{prettyBytes(props.data.downloaded_bytes)} of{" "}
{prettyBytes(props.data.size)}{" "}
</span>
<progress
className="progress is-small is-success"
value={props.data.downloaded_bytes}
max={props.data.size}
>
{(parseInt(props.data.downloaded_bytes) /
parseInt(props.data.size)) *
100}
%
</progress>
</dd>
<dd className="is-size-5">
{prettyBytes(props.data.speed)} per second.
</dd>
<dd className="is-size-5">
Time left:
{Math.round(parseInt(props.data.seconds_left) / 60)}
</dd>
<dd>{props.data.target}</dd>
</dl>
</div>
</div>
</div>
);
};
const Bundles = (props) => {
return !isEmpty(props.data) ? (
<div className="column is-full">
@@ -130,9 +81,6 @@ export const DownloadsPanel = (
return !isNil(props.data) ? (
<>
<div className="columns is-multiline">
{!isNil(downloadProgressTick) ? (
<ProgressTick data={downloadProgressTick} />
) : null}
{!isEmpty(ADCPPSocket) ? (
<Bundles data={bundles} />
) : (

View File

@@ -9,7 +9,7 @@ export const LibraryStatistics = (
return (
<div className="mt-5">
<h4 className="title is-4">
<i className="fa-solid fa-chart-simple"></i> Statistics
<i className="fa-solid fa-chart-simple"></i> Your Library In Numbers
</h4>
<p className="subtitle is-7">A brief snapshot of your library.</p>
<div className="columns is-multiline">

View File

@@ -1,5 +1,6 @@
import React from "react";
import { SearchBar } from "./GlobalSearchBar/SearchBar";
import { DownloadProgressTick } from "./ComicDetail/DownloadProgressTick";
import { Link } from "react-router-dom";
const Navbar: React.FunctionComponent = (props) => {
@@ -62,15 +63,23 @@ const Navbar: React.FunctionComponent = (props) => {
<div className="navbar-end">
<a className="navbar-item is-hidden-desktop-only"></a>
<div className="navbar-item has-dropdown is-hoverable">
<a
className="navbar-link is-active"
href="/documentation/overview/start/"
>
{/* <div className="navbar-item has-dropdown is-hoverable">
<a className="navbar-link is-arrowless">
<i className="fa-solid fa-download"></i>
{!isUndefined(downloadProgressTick) ? (
<>
<i className="fa-solid fa-circle-dashed"></i>
</>
) : null}
</a>
<div className="navbar-dropdown">asdas</div>
</div>
{!isUndefined(downloadProgressTick) ? (
<div className="navbar-dropdown download-progress-meter">
<a className="navbar-item">
<DownloadProgressTick data={downloadProgressTick} />
</a>
</div>
) : null}
</div> */}
<div className="navbar-item has-dropdown is-hoverable is-mega">
<div className="navbar-link flex">Blog</div>
<div id="blogDropdown" className="navbar-dropdown">

View File

@@ -1,5 +0,0 @@
import React from "react";
const AirDCPPSocketContext = React.createContext(null);
export { AirDCPPSocketContext };

View File

@@ -0,0 +1,45 @@
import axios from "axios";
import React, { createContext, useEffect, useState } from "react";
import { SETTINGS_SERVICE_BASE_URI } from "../constants/endpoints";
import AirDCPPSocket from "../services/DcppSearchService";
const AirDCPPSocketContext = createContext({});
const AirDCPPSocketContextProvider = ({ children }) => {
const [airDCPPConfiguration, setValue] = useState({});
useEffect(() => {
const initializeAirDCPPSocket = () => {
axios({
url: `${SETTINGS_SERVICE_BASE_URI}/getSettings`,
method: "POST",
data: "",
}).then(async (data) => {
const { directConnect } = data.data;
const initializedAirDCPPSocket = new AirDCPPSocket({
protocol: `${directConnect.client.host.protocol}`,
hostname: `${directConnect.client.host.hostname}`,
});
await initializedAirDCPPSocket.connect(
`${directConnect.client.host.username}`,
`${directConnect.client.host.password}`,
true,
);
setValue({
AirDCPPSocket: initializedAirDCPPSocket,
settings: data.data,
});
});
};
initializeAirDCPPSocket();
}, []);
// the Provider gives access to the context to its children
console.log(airDCPPConfiguration);
return (
<AirDCPPSocketContext.Provider value={airDCPPConfiguration}>
{children}
</AirDCPPSocketContext.Provider>
);
};
export { AirDCPPSocketContext, AirDCPPSocketContextProvider };

View File