🔧 AirDCPP metadata and download first draft

This commit is contained in:
2021-08-23 14:34:55 -07:00
parent e5870fa1a8
commit 8a1e6fb98a
5 changed files with 162 additions and 84 deletions

View File

@@ -6,10 +6,9 @@ import {
SearchResponse, SearchResponse,
} from "threetwo-ui-typings"; } from "threetwo-ui-typings";
import { import {
AIRDCPP_SEARCH_INSTANCE_CREATED,
AIRDCPP_SEARCH_RESULTS_RECEIVED, AIRDCPP_SEARCH_RESULTS_RECEIVED,
AIRDCPP_HUB_SEARCHES_SENT, AIRDCPP_HUB_SEARCHES_SENT,
AIRDCPP_HUB_USER_CONNECTED, AIRDCPP_RESULT_DOWNLOAD_INITIATED,
} from "../constants/action-types"; } from "../constants/action-types";
interface SearchData { interface SearchData {
@@ -30,10 +29,10 @@ export const search = (data: SearchData) => async (dispatch) => {
`search/${instance.id}`, `search/${instance.id}`,
"search_hub_searches_sent", "search_hub_searches_sent",
async (searchInfo) => { async (searchInfo) => {
console.log("As", searchInfo)
// Collect the results for 5 seconds before fetching them
dispatch({ dispatch({
type: AIRDCPP_HUB_SEARCHES_SENT, type: AIRDCPP_HUB_SEARCHES_SENT,
searchInfo,
instance,
}); });
}, },
); );
@@ -52,3 +51,17 @@ export const search = (data: SearchData) => async (dispatch) => {
SocketService.disconnect(); SocketService.disconnect();
return results; return results;
}; };
export const downloadAirDCPPItem =
(instanceId: string, resultId: string): void =>
async (dispatch) => {
await SocketService.connect("admin", "password", true);
const downloadResult = await SocketService.post(
`search/${instanceId}/results/${resultId}/download`,
);
dispatch({
type: AIRDCPP_RESULT_DOWNLOAD_INITIATED,
downloadResult: downloadResult,
});
SocketService.disconnect();
};

View File

@@ -1,7 +1,7 @@
import React, { useState, useEffect, useCallback, ReactElement } from "react"; import React, { useState, useEffect, useCallback, ReactElement } from "react";
import { search } from "../actions/airdcpp.actions"; import { search, downloadAirDCPPItem } from "../actions/airdcpp.actions";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { RootState } from "threetwo-ui-typings"; import { RootState, SearchInstance } from "threetwo-ui-typings";
import { each, isNil, map } from "lodash"; import { each, isNil, map } from "lodash";
interface IAcquisitionPanelProps { interface IAcquisitionPanelProps {
@@ -17,8 +17,14 @@ export const AcquisitionPanel = (
const airDCPPSearchResults = useSelector( const airDCPPSearchResults = useSelector(
(state: RootState) => state.airdcpp.results, (state: RootState) => state.airdcpp.results,
); );
const searchStatus = useSelector( const isAirDCPPSearchInProgress = useSelector(
(state: RootState) => state.airdcpp.searchStatus, (state: RootState) => state.airdcpp.isAirDCPPSearchInProgress,
);
const searchInfo = useSelector(
(state: RootState) => state.airdcpp.searchInfo,
);
const searchInstance: SearchInstance = useSelector(
(state: RootState) => state.airdcpp.searchInstance,
); );
const dispatch = useDispatch(); const dispatch = useDispatch();
const getDCPPSearchResults = useCallback( const getDCPPSearchResults = useCallback(
@@ -30,22 +36,67 @@ export const AcquisitionPanel = (
const dcppQuery = { const dcppQuery = {
query: { query: {
pattern: `${volumeName}`, pattern: `${volumeName}`,
// file_type: "compressed",
extensions: ["cbz", "cbr"], extensions: ["cbz", "cbr"],
}, },
hub_urls: ["perfection.crabdance.com:777"], hub_urls: ["perfection.crabdance.com:777"],
priority: 1, priority: 1,
}; };
const downloadDCPPResult = useCallback(
(searchInstanceId, resultId) =>
dispatch(downloadAirDCPPItem(searchInstanceId, resultId)),
[dispatch],
);
return ( return (
<div className="comic-detail"> <>
<div className="comic-detail columns">
<div className="column is-one-fifth">
<button <button
className="button" className={
isAirDCPPSearchInProgress
? "button is-loading is-warning"
: "button"
}
onClick={() => getDCPPSearchResults(dcppQuery)} onClick={() => getDCPPSearchResults(dcppQuery)}
> >
Search on AirDC++ Search on AirDC++
</button> </button>
<p>{searchStatus}</p> </div>
{!isNil(searchInfo) && !isNil(searchInstance) && (
<>
<div className="column is-one-quarter is-size-7">
<div className="card">
<div className="card-content">
<div className="content">
<dl>
<dt>Query: {searchInfo.query.pattern}</dt>
<dd>
Extensions: {searchInfo.query.extensions.join(", ")}
</dd>
<dd>File type: {searchInfo.query.file_type}</dd>
</dl>
</div>
</div>
</div>
</div>
<div className="column is-one-quarter is-size-7">
<div className="card">
<div className="card-content">
<div className="content">
<dl>
<dt>Search Instance: {searchInstance.id}</dt>
<dt>Owned by {searchInstance.owner}</dt>
<dd>Expires in: {searchInstance.expires_in}</dd>
</dl>
</div>
</div>
</div>
</div>
</>
)}
</div>
{/* results */} {/* results */}
<div>
{!isNil(airDCPPSearchResults) && ( {!isNil(airDCPPSearchResults) && (
<table className="table is-striped"> <table className="table is-striped">
<thead> <thead>
@@ -53,10 +104,11 @@ export const AcquisitionPanel = (
<th>Name</th> <th>Name</th>
<th>Type</th> <th>Type</th>
<th>Slots</th> <th>Slots</th>
<th>Actions</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{map(airDCPPSearchResults, ({ name, type, slots, users }) => { {map(airDCPPSearchResults, ({ name, type, slots, users, id }) => {
return ( return (
<tr> <tr>
<td> <td>
@@ -88,10 +140,21 @@ export const AcquisitionPanel = (
</td> </td>
<td> <td>
<div className="tags has-addons"> <div className="tags has-addons">
<span className="tag is-success">{slots.free} free</span> <span className="tag is-success">
{slots.free} free
</span>
<span className="tag is-light">{slots.total}</span> <span className="tag is-light">{slots.total}</span>
</div> </div>
</td> </td>
<td>
<a
onClick={() =>
downloadDCPPResult(searchInstance.id, id)
}
>
<i className="fas fa-file-download"></i>
</a>
</td>
</tr> </tr>
); );
})} })}
@@ -99,6 +162,7 @@ export const AcquisitionPanel = (
</table> </table>
)} )}
</div> </div>
</>
); );
}; };

View File

@@ -151,6 +151,12 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
name: "Acquisition", name: "Acquisition",
content: <AcquisitionPanel comicBookMetadata={comicBookDetailData} />, content: <AcquisitionPanel comicBookMetadata={comicBookDetailData} />,
}, },
{
id: 4,
icon: <i className="fas fa-cloud-download-alt"></i>,
name: "Downloads",
content: <div>Downloads</div>,
},
]; ];
const MetadataTabGroup = () => { const MetadataTabGroup = () => {
return ( return (

View File

@@ -31,11 +31,9 @@ export const IMS_COMIC_BOOK_DB_OBJECT_CALL_IN_PROGRESS =
export const IMS_COMIC_BOOK_DB_OBJECT_CALL_FAILED = export const IMS_COMIC_BOOK_DB_OBJECT_CALL_FAILED =
"IMS_COMIC_BOOK_DB_OBJECT_CALL_FAILED"; "IMS_COMIC_BOOK_DB_OBJECT_CALL_FAILED";
export const AIRDCPP_SEARCH_INSTANCE_CREATED =
"AIRDCPP_SEARCH_INSTANCE_CREATED";
export const AIRDCPP_SEARCH_IN_PROGRESS = "AIRDCPP_SEARCH_IN_PROGRESS"; export const AIRDCPP_SEARCH_IN_PROGRESS = "AIRDCPP_SEARCH_IN_PROGRESS";
export const AIRDCPP_SEARCH_RESULTS_RECEIVED = export const AIRDCPP_SEARCH_RESULTS_RECEIVED =
"AIRDCPP_SEARCH_RESULTS_RECEIVED"; "AIRDCPP_SEARCH_RESULTS_RECEIVED";
export const AIRDCPP_HUB_SEARCHES_SENT = "AIRDCPP_HUB_SEARCHES_SENT"; export const AIRDCPP_HUB_SEARCHES_SENT = "AIRDCPP_HUB_SEARCHES_SENT";
export const AIRDCPP_HUB_USER_CONNECTED = "AIRDCPP_HUB_USER_CONNECTED"; export const AIRDCPP_RESULT_DOWNLOAD_INITIATED = "AIRDCPP_RESULT_DOWNLOAD_INITIATED";

View File

@@ -1,30 +1,19 @@
import { import {
AIRDCPP_SEARCH_INSTANCE_CREATED,
AIRDCPP_SEARCH_IN_PROGRESS, AIRDCPP_SEARCH_IN_PROGRESS,
AIRDCPP_SEARCH_RESULTS_RECEIVED, AIRDCPP_SEARCH_RESULTS_RECEIVED,
AIRDCPP_HUB_SEARCHES_SENT, AIRDCPP_HUB_SEARCHES_SENT,
AIRDCPP_HUB_USER_CONNECTED, AIRDCPP_RESULT_DOWNLOAD_INITIATED,
} from "../constants/action-types"; } from "../constants/action-types";
const initialState = { const initialState = {
isAirDCPPSearchInProgress: false, isAirDCPPSearchInProgress: false,
searchStatus: "", searchStatus: "",
searchInfo: null,
searchInstance: null,
}; };
function airdcppReducer(state = initialState, action) { function airdcppReducer(state = initialState, action) {
switch (action.type) { switch (action.type) {
case AIRDCPP_HUB_USER_CONNECTED:
return {
...state,
searchStatus: "Hub user connected",
}
case AIRDCPP_SEARCH_INSTANCE_CREATED:
return {
...state,
searchInstance: action.searchInstance,
searchStatus: "Search Instance created",
};
case AIRDCPP_SEARCH_IN_PROGRESS: case AIRDCPP_SEARCH_IN_PROGRESS:
return { return {
...state, ...state,
@@ -35,6 +24,7 @@ function airdcppReducer(state = initialState, action) {
return { return {
...state, ...state,
isAirDCPPSearchInProgress: false, isAirDCPPSearchInProgress: false,
searchStatus: "Search complete",
results: action.results, results: action.results,
}; };
case AIRDCPP_HUB_SEARCHES_SENT: case AIRDCPP_HUB_SEARCHES_SENT:
@@ -42,6 +32,13 @@ function airdcppReducer(state = initialState, action) {
...state, ...state,
searchStatus: "Hub searches sent", searchStatus: "Hub searches sent",
isAirDCPPSearchInProgress: true, isAirDCPPSearchInProgress: true,
searchInfo: action.searchInfo,
searchInstance: action.instance,
};
case AIRDCPP_RESULT_DOWNLOAD_INITIATED:
return {
...state,
downloadResult: action.downloadResult,
}; };
default: default: