добавлено полное апи sonarr
This commit is contained in:
@@ -12,7 +12,7 @@ const CardCompact = ({item}) => {
|
||||
<Card.Title>{item.title}</Card.Title>
|
||||
<Card.Body>
|
||||
<div>Год: {item.year} <br/></div>
|
||||
<div>Рейтинг: {cc.rating} <br/></div>
|
||||
{cc.rating || cc.rating !== 0 ? <div>Рейтинг: {cc.rating} <br/></div> : null}
|
||||
{cc.status ? <div>{cc.status}<br/></div> : null}
|
||||
{cc.size ? <div>Размер: {cc.size} Gb</div> : null}
|
||||
{(item?.statistics?.seasonCount ? <div>Сезоны: {item.statistics.seasonCount}</div> : null)}
|
||||
|
||||
@@ -23,7 +23,7 @@ const CardExtended = ({item, selectHandle}) => {
|
||||
</Row>
|
||||
<Row>
|
||||
<Col style={{justifyContent: 'end'}}>
|
||||
<Button variant={'outline-primary'} title={"Download"}>Загрузить</Button>
|
||||
<Button variant={'outline-primary'} disabled title={"Download"}>{item.serial ? "Сериал" : "Фильм"}</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
@@ -1,18 +1,9 @@
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {Button, Col, Container, FormCheck, FormSelect, Modal, Row} from 'react-bootstrap';
|
||||
import {useToast} from "../hooks/useToast";
|
||||
import {radarr} from "../contexts/client";
|
||||
|
||||
const movieMonitor = [
|
||||
{
|
||||
id: "movieAndCollection",
|
||||
name: "Все части"
|
||||
},
|
||||
{
|
||||
id: "movieOnly",
|
||||
name: "Только этот фильм"
|
||||
}
|
||||
]
|
||||
import {radarr, sonarr} from "../contexts/client";
|
||||
import {movieMonitor, tvMonitor} from "./monitors";
|
||||
import {createRequest} from "./saveRequest";
|
||||
|
||||
const RecommendationModal = ({show, handleClose, item, serial, handleSave}) => {
|
||||
const [movieQuality, setMovieQuality] = useState([])
|
||||
@@ -21,9 +12,11 @@ const RecommendationModal = ({show, handleClose, item, serial, handleSave}) => {
|
||||
const [film, setFilm] = useState(false)
|
||||
const {addToast} = useToast();
|
||||
const rating = item?.ratings?.imdb?.value ?? null;
|
||||
const client = serial ? sonarr() : radarr();
|
||||
const monitorArray = serial ? tvMonitor : movieMonitor;
|
||||
|
||||
useEffect(() => {
|
||||
radarr().get("api/v3/qualityprofile")
|
||||
client.get("api/v3/qualityprofile")
|
||||
.then((r) => {
|
||||
setMovieQuality(r.data)
|
||||
})
|
||||
@@ -32,43 +25,15 @@ const RecommendationModal = ({show, handleClose, item, serial, handleSave}) => {
|
||||
}, []);
|
||||
|
||||
const handleSubmit = () => {
|
||||
const request = !serial ? createMovieRequest : null;
|
||||
request()
|
||||
createRequest(monitor, quality, item, serial, film)
|
||||
.then(res => {
|
||||
radarr().post("api/v3/movie", res)
|
||||
client.post(`api/v3/${serial ? "series" : "movie"}`, res)
|
||||
.then(() => handleSave(item, serial))
|
||||
.catch((err) => addToast(err, 'danger'));
|
||||
.catch((err) => addToast(err.message, 'danger'));
|
||||
})
|
||||
.catch((err) => addToast(err, 'danger'));
|
||||
}
|
||||
|
||||
const createMovieRequest = async () => {
|
||||
if (!monitor) {
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw 'Проверьте пункт отслеживания';
|
||||
}
|
||||
if (!quality) {
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw 'Необходимо указать качество';
|
||||
}
|
||||
let request = item;
|
||||
request.id = 0;
|
||||
request.monitored = true;
|
||||
request.qualityProfileId = quality;
|
||||
request.minimumAvailability = "released"
|
||||
request.addOptions = {
|
||||
monitor: monitor,
|
||||
searchForMovie: true
|
||||
}
|
||||
const folders = await radarr().get("api/v3/rootFolder");
|
||||
request.rootFolderPath = folders.data.find((d) => d.path.includes(film ? "film" : "mult")).path;
|
||||
|
||||
const tags = await radarr().get("api/v3/tag");
|
||||
request.tags = tags.data.filter((t) => t.label === (film ? "film" : "mult")).map((t) => t.id)
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
if (!item) {
|
||||
return null;
|
||||
}
|
||||
@@ -82,7 +47,7 @@ const RecommendationModal = ({show, handleClose, item, serial, handleSave}) => {
|
||||
<Container fluid>
|
||||
<Row className="align-items-start">
|
||||
<Col md={3} className="mb-3">
|
||||
<img width="100%" className='mb-3' src={item.remotePoster} alt={item.title} />
|
||||
<img width="100%" className='mb-3' src={item.remotePoster} alt={item.title}/>
|
||||
</Col>
|
||||
<Col md={9} className="d-flex flex-column">
|
||||
<div>
|
||||
@@ -101,7 +66,7 @@ const RecommendationModal = ({show, handleClose, item, serial, handleSave}) => {
|
||||
<FormCheck type='switch' disabled={serial} style={{marginBottom: '1rem'}}
|
||||
onChange={() => setFilm(!film)}/>
|
||||
<p>Фильм</p>
|
||||
<FormCheck type='checkbox' disabled={!serial}
|
||||
<FormCheck type='checkbox' disabled checked={serial}
|
||||
style={{marginBottom: '1rem', marginLeft: '1rem'}}
|
||||
label="Сериал"/>
|
||||
</Col>
|
||||
@@ -111,7 +76,7 @@ const RecommendationModal = ({show, handleClose, item, serial, handleSave}) => {
|
||||
<p style={{width: '50%', paddingTop: '1rem'}}>Что отслеживать</p>
|
||||
<FormSelect onChange={(e) => setMonitor(e.target.value)}>
|
||||
<option selected value={null}>Выберите пункт из меню</option>
|
||||
{movieMonitor.map((m) => <option value={m.id} key={m.id}>{m.name}</option>)}
|
||||
{monitorArray.map((m) => <option value={m.id} key={m.id}>{m.name}</option>)}
|
||||
</FormSelect>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
export const getCardContent = (item) => {
|
||||
let result = {
|
||||
image: item?.images?.length > 0 ? item.images[0]?.remoteUrl : null,
|
||||
rating: item.ratings?.imdb?.value ?? null,
|
||||
rating: item.ratings?.imdb?.value ?? item.ratings.value ?? null,
|
||||
status: null,
|
||||
size: null,
|
||||
series: null,
|
||||
};
|
||||
|
||||
if(item.images?.length > 0) {
|
||||
result.image = item.images.find(image => image.coverType === "poster").remoteUrl;
|
||||
}
|
||||
|
||||
if (item.sizeOnDisk) {
|
||||
result.size = item.sizeOnDisk / 1000000000;
|
||||
}
|
||||
|
||||
33
src/components/monitors.js
Normal file
33
src/components/monitors.js
Normal file
@@ -0,0 +1,33 @@
|
||||
export const movieMonitor = [
|
||||
{
|
||||
id: "movieAndCollection",
|
||||
name: "Все части"
|
||||
},
|
||||
{
|
||||
id: "movieOnly",
|
||||
name: "Только этот фильм"
|
||||
}
|
||||
]
|
||||
|
||||
export const tvMonitor = [
|
||||
{
|
||||
id: "all",
|
||||
name: "Все серии"
|
||||
},
|
||||
{
|
||||
id: "future",
|
||||
name: "Новые серии"
|
||||
},
|
||||
{
|
||||
id: "firstSeason",
|
||||
name: "Первый сезон"
|
||||
},
|
||||
{
|
||||
id: "lastSeason",
|
||||
name: "Последний сезон"
|
||||
},
|
||||
{
|
||||
id: "latestSeason",
|
||||
name: "Последние сезоны"
|
||||
},
|
||||
]
|
||||
49
src/components/saveRequest.js
Normal file
49
src/components/saveRequest.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import {sonarr} from "../contexts/client";
|
||||
|
||||
export const createRequest = async (monitor, quality, item, serial, film) => {
|
||||
if (!monitor) {
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw 'Проверьте пункт отслеживания';
|
||||
}
|
||||
if (!quality) {
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw 'Необходимо указать качество';
|
||||
}
|
||||
let request = item;
|
||||
request.monitored = true;
|
||||
request.qualityProfileId = quality;
|
||||
|
||||
var addOptions = {
|
||||
monitor: monitor,
|
||||
}
|
||||
|
||||
const folders = await sonarr().get("api/v3/rootFolder");
|
||||
request.rootFolderPath = !serial ? folders.data.find((d) => d.path.includes(film ? "film" : "mult")).path : folders.data[0].path;
|
||||
|
||||
if (!serial) {
|
||||
request.id = 0;
|
||||
request.minimumAvailability = "released"
|
||||
addOptions = {
|
||||
...addOptions,
|
||||
searchForMovie: true
|
||||
}
|
||||
const tags = await sonarr().get("api/v3/tag");
|
||||
request.tags = tags.data.filter((t) => t.label === (film ? "film" : "mult")).map((t) => t.id)
|
||||
} else {
|
||||
request.seasonFolder = true;
|
||||
addOptions = {
|
||||
...addOptions,
|
||||
searchForMissingEpisodes: true,
|
||||
searchForCutoffUnmetEpisodes: false
|
||||
}
|
||||
|
||||
delete request.minimumAvailability;
|
||||
delete request.monitorNewItems;
|
||||
delete request.id;
|
||||
}
|
||||
|
||||
delete request.serial;
|
||||
request.addOptions = addOptions;
|
||||
|
||||
return request;
|
||||
}
|
||||
@@ -12,6 +12,8 @@ const Home = () => {
|
||||
const [tv, setTv] = useState([]);
|
||||
const {addToast} = useToast();
|
||||
|
||||
// На будущую реализацию удаления
|
||||
// api/v3/movie/68?deleteFiles=true&addImportExclusion=false
|
||||
useEffect(() => {
|
||||
setLoadingMovies(true);
|
||||
setLoadingTv(true);
|
||||
|
||||
@@ -3,15 +3,14 @@ import CardExtend from "../components/CardExtend";
|
||||
import {Alert, Container, InputGroup, Row} from "react-bootstrap";
|
||||
import RecommendationModal from "../components/RecommendationModal";
|
||||
import {useToast} from "../hooks/useToast";
|
||||
import {radarr} from "../contexts/client";
|
||||
import {radarr, sonarr} from "../contexts/client";
|
||||
|
||||
export function Search() {
|
||||
const [query, setQuery] = useState('');
|
||||
const [serial, setSerial] = useState(false);
|
||||
const [loadMovies, setLoadMovies] = useState(false);
|
||||
// const [loadTv, setLoadTv] = useState(false);
|
||||
const [errorMovies, setErrorMovies] = useState(false);
|
||||
// const [errorTv, setErrorTv] = useState(false);
|
||||
// const [resultTv, setResultTv] = useState([]);
|
||||
const [loadTv, setLoadTv] = useState(false);
|
||||
const [resultTv, setResultTv] = useState([]);
|
||||
const [resultMovies, setResultMovies] = useState([]);
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [selectItem, setSelectItem] = useState({});
|
||||
@@ -23,22 +22,43 @@ export function Search() {
|
||||
}
|
||||
setLoadMovies(true);
|
||||
radarr().get(`api/v3/movie/lookup?term=${query}}`)
|
||||
.then((r) => setResultMovies(r.data))
|
||||
.catch((err) => setErrorMovies(err))
|
||||
.then((r) => {
|
||||
const movies = r.data.map((m) => {
|
||||
return {
|
||||
...m,
|
||||
serial: false
|
||||
}
|
||||
})
|
||||
setResultMovies(movies);
|
||||
})
|
||||
.catch((err) => addToast(err, 'alert'))
|
||||
.finally(() => setLoadMovies(false));
|
||||
|
||||
setLoadTv(true);
|
||||
sonarr().get(`api/v3/series/lookup?term=${query}}`)
|
||||
.then((r) => {
|
||||
const series = r.data.map((s) => {
|
||||
return {
|
||||
...s,
|
||||
serial: true
|
||||
}
|
||||
})
|
||||
setResultTv(series)
|
||||
}).catch((err) => addToast(err, 'alert'))
|
||||
.finally(() => setLoadTv(false));
|
||||
// eslint-disable-next-lin
|
||||
}, [query]);
|
||||
|
||||
const handleChange = (item) => {
|
||||
setSelectItem(item);
|
||||
setShowModal(true);
|
||||
setSerial(item.serial);
|
||||
}
|
||||
|
||||
const result = useMemo(() => {
|
||||
let array = resultMovies;
|
||||
// array.concat(resultTv);
|
||||
let array = resultMovies.concat(resultTv);
|
||||
return array.sort((a, b) => a.title.localeCompare(b.title));
|
||||
}, [resultMovies]);
|
||||
}, [resultMovies, resultTv]);
|
||||
|
||||
const handleCloseModal = () => {
|
||||
setShowModal(false);
|
||||
@@ -49,15 +69,12 @@ export function Search() {
|
||||
let nState = resultMovies;
|
||||
nState = nState.filter(i => i.title !== item.title && i.year !== item.year);
|
||||
|
||||
const func = setResultMovies;
|
||||
const func = serial ? setResultTv : setResultMovies;
|
||||
func(nState);
|
||||
addToast(`${item.title} добавлен в список загрузок`, 'success');
|
||||
handleCloseModal();
|
||||
}
|
||||
|
||||
// Используем хук useAxios для обработки запросов
|
||||
// const {response, loading, errorTv} = useAxios('/api/search', 'get', {query});
|
||||
|
||||
return (
|
||||
<Container style={{marginTop: 5}}>
|
||||
<h2>Поиск</h2>
|
||||
@@ -73,28 +90,24 @@ export function Search() {
|
||||
</InputGroup>
|
||||
</form>
|
||||
|
||||
{loadMovies && <div className="text-center">Загрузка...</div>}
|
||||
|
||||
{errorMovies && (
|
||||
<Alert variant="danger">{errorMovies}</Alert>
|
||||
)}
|
||||
{(loadMovies || loadTv) && <div className="text-center">Загрузка...</div>}
|
||||
|
||||
{result && result.length > 0 && (
|
||||
<div>
|
||||
<h3>Результаты поиска</h3>
|
||||
<Row>
|
||||
{resultMovies.map(result => <CardExtend item={result} key={result.id}
|
||||
{result.map(result => <CardExtend item={result} key={result.id}
|
||||
selectHandle={handleChange}/>)}
|
||||
</Row>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(!loadMovies && !errorMovies && (!resultMovies || !result.length)) && (
|
||||
{((!loadMovies && (!resultMovies || !result.length) && (!loadTv && (!resultTv || !result.length))) &&
|
||||
<Alert variant='info'>
|
||||
Ничего не найдено
|
||||
</Alert>
|
||||
)}
|
||||
<RecommendationModal item={selectItem} handleClose={handleCloseModal} show={showModal} serial={false}
|
||||
<RecommendationModal item={selectItem} handleClose={handleCloseModal} show={showModal} serial={serial}
|
||||
handleSave={handleSave}/>
|
||||
</Container>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user