Compare commits
3 Commits
69115c7318
...
a147766118
Author | SHA1 | Date | |
---|---|---|---|
a147766118 | |||
86acc89215 | |||
224eec48c0 |
@ -5,10 +5,10 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
<meta name="Description" content="Canapé">
|
<meta name="Description" content="Canapé">
|
||||||
<link rel="icon" type="image/png" href="<%= require("./img/favicon-32x32.png") %>" sizes="32x32">
|
<link rel="icon" type="image/png" href="<%= require("./img/favicon-16x16.png").default %>" sizes="16x16">
|
||||||
<link rel="icon" type="image/png" href="<%= require("./img/favicon-16x16.png") %>" sizes="16x16">
|
<link rel="icon" type="image/png" href="<%= require("./img/favicon-32x32.png").default %>" sizes="32x32">
|
||||||
<meta name="msapplication-navbutton-color" content="#4E5D6C">
|
<meta name="msapplication-navbutton-color" content="#4E5D6C">
|
||||||
<link rel="mask-icon" href="<%= require("./img/safari-pinned-tab.svg") %>" color="#5bbad5">
|
<link rel="mask-icon" href="<%= require("./img/safari-pinned-tab.svg").default %>" color="#5bbad5">
|
||||||
<title>Canapé</title>
|
<title>Canapé</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -27,7 +27,7 @@ export const ShowMore = ({ children, id, inLibrary }) => {
|
|||||||
ShowMore.propTypes = {
|
ShowMore.propTypes = {
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
inLibrary: PropTypes.bool.isRequired,
|
inLibrary: PropTypes.bool.isRequired,
|
||||||
children: PropTypes.oneOf(PropTypes.object, PropTypes.array)
|
children: PropTypes.oneOfType([PropTypes.object, PropTypes.array])
|
||||||
};
|
};
|
||||||
ShowMore.defaultProps = {
|
ShowMore.defaultProps = {
|
||||||
id: "",
|
id: "",
|
||||||
|
@ -48,5 +48,5 @@ FormModal.propTypes = {
|
|||||||
icon: PropTypes.string,
|
icon: PropTypes.string,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
handleSubmit: PropTypes.func,
|
handleSubmit: PropTypes.func,
|
||||||
children: PropTypes.oneOf(PropTypes.object, PropTypes.array)
|
children: PropTypes.oneOfType([PropTypes.object, PropTypes.array])
|
||||||
};
|
};
|
||||||
|
@ -85,82 +85,96 @@ ListPosters.propTypes = {
|
|||||||
|
|
||||||
export default ListPosters;
|
export default ListPosters;
|
||||||
|
|
||||||
const Posters = props => {
|
const Posters = ({
|
||||||
|
elmts,
|
||||||
|
onKeyEnter,
|
||||||
|
selectedImdbId,
|
||||||
|
selectPoster,
|
||||||
|
onDoubleClick
|
||||||
|
}) => {
|
||||||
const addMoreCount = 20;
|
const addMoreCount = 20;
|
||||||
const [size, setSize] = useState(0);
|
const [size, setSize] = useState(0);
|
||||||
const [postersPerRow, setPostersPerRow] = useState(0);
|
const [postersPerRow, setPostersPerRow] = useState(0);
|
||||||
const [posterHeight, setPosterHeight] = useState(0);
|
const [posterHeight, setPosterHeight] = useState(0);
|
||||||
|
|
||||||
const loadMore = () => {
|
const loadMore = useCallback(() => {
|
||||||
if (size === props.elmts.size) {
|
if (size === elmts.size) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newSize =
|
const newSize =
|
||||||
size + addMoreCount >= props.elmts.size
|
size + addMoreCount >= elmts.size ? elmts.size : size + addMoreCount;
|
||||||
? props.elmts.size
|
|
||||||
: size + addMoreCount;
|
|
||||||
|
|
||||||
setSize(newSize);
|
setSize(newSize);
|
||||||
};
|
}, [size, elmts.size]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadMore();
|
loadMore();
|
||||||
}, [props.elmts.size]);
|
}, [elmts.size, loadMore]);
|
||||||
|
|
||||||
const move = event => {
|
const move = useCallback(
|
||||||
// Only run the function if nothing else if actively focused
|
event => {
|
||||||
if (document.activeElement.tagName.toLowerCase() !== "body") {
|
// Only run the function if nothing else if actively focused
|
||||||
return;
|
if (document.activeElement.tagName.toLowerCase() !== "body") {
|
||||||
}
|
|
||||||
|
|
||||||
let diff = 0;
|
|
||||||
let moveFocus = 0;
|
|
||||||
switch (event.key) {
|
|
||||||
case "Enter":
|
|
||||||
props.onKeyEnter(props.selectedImdbId);
|
|
||||||
return;
|
return;
|
||||||
case "l":
|
}
|
||||||
diff = 1;
|
|
||||||
break;
|
|
||||||
case "h":
|
|
||||||
diff = -1;
|
|
||||||
break;
|
|
||||||
case "k":
|
|
||||||
diff = -1 * postersPerRow;
|
|
||||||
moveFocus = -1 * posterHeight;
|
|
||||||
break;
|
|
||||||
case "j":
|
|
||||||
diff = postersPerRow;
|
|
||||||
moveFocus = posterHeight;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the index of the currently selected item
|
let diff = 0;
|
||||||
const idx = props.elmts.keySeq().findIndex(k => k === props.selectedImdbId);
|
let moveFocus = 0;
|
||||||
|
switch (event.key) {
|
||||||
|
case "Enter":
|
||||||
|
onKeyEnter(selectedImdbId);
|
||||||
|
return;
|
||||||
|
case "l":
|
||||||
|
diff = 1;
|
||||||
|
break;
|
||||||
|
case "h":
|
||||||
|
diff = -1;
|
||||||
|
break;
|
||||||
|
case "k":
|
||||||
|
diff = -1 * postersPerRow;
|
||||||
|
moveFocus = -1 * posterHeight;
|
||||||
|
break;
|
||||||
|
case "j":
|
||||||
|
diff = postersPerRow;
|
||||||
|
moveFocus = posterHeight;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var newIdx = idx + diff;
|
// Get the index of the currently selected item
|
||||||
|
const idx = elmts.keySeq().findIndex(k => k === selectedImdbId);
|
||||||
|
|
||||||
// Handle edge cases
|
var newIdx = idx + diff;
|
||||||
if (newIdx > props.elmts.size - 1) {
|
|
||||||
newIdx = props.elmts.size - 1;
|
|
||||||
} else if (newIdx < 0) {
|
|
||||||
newIdx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the imdbID of the newly selected item
|
// Handle edge cases
|
||||||
var selectedImdb = Object.keys(props.elmts.toJS())[newIdx];
|
if (newIdx > elmts.size - 1) {
|
||||||
|
newIdx = elmts.size - 1;
|
||||||
|
} else if (newIdx < 0) {
|
||||||
|
newIdx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Select the movie
|
// Get the imdbID of the newly selected item
|
||||||
props.selectPoster(selectedImdb);
|
var selectedImdb = Object.keys(elmts.toJS())[newIdx];
|
||||||
if (moveFocus !== 0) {
|
|
||||||
window.scrollBy(0, moveFocus);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const posterCount = useCallback(node => {
|
// Select the movie
|
||||||
|
selectPoster(selectedImdb);
|
||||||
|
if (moveFocus !== 0) {
|
||||||
|
window.scrollBy(0, moveFocus);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[
|
||||||
|
elmts,
|
||||||
|
onKeyEnter,
|
||||||
|
posterHeight,
|
||||||
|
postersPerRow,
|
||||||
|
selectPoster,
|
||||||
|
selectedImdbId
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
const posterCount = node => {
|
||||||
if (node === null) {
|
if (node === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -180,7 +194,7 @@ const Posters = props => {
|
|||||||
childWidth >= parentWidth ? 1 : Math.floor(parentWidth / childWidth);
|
childWidth >= parentWidth ? 1 : Math.floor(parentWidth / childWidth);
|
||||||
setPostersPerRow(numberPerRow);
|
setPostersPerRow(numberPerRow);
|
||||||
setPosterHeight(posterHeight);
|
setPosterHeight(posterHeight);
|
||||||
});
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.onkeypress = move;
|
document.onkeypress = move;
|
||||||
@ -189,7 +203,7 @@ const Posters = props => {
|
|||||||
};
|
};
|
||||||
}, [move]);
|
}, [move]);
|
||||||
|
|
||||||
if (props.elmts.size === 0) {
|
if (elmts.size === 0) {
|
||||||
return (
|
return (
|
||||||
<div className="jumbotron">
|
<div className="jumbotron">
|
||||||
<h2>No result</h2>
|
<h2>No result</h2>
|
||||||
@ -203,23 +217,23 @@ const Posters = props => {
|
|||||||
className="poster-list d-flex flex-column flex-sm-row flex-sm-wrap justify-content-around"
|
className="poster-list d-flex flex-column flex-sm-row flex-sm-wrap justify-content-around"
|
||||||
dataLength={size}
|
dataLength={size}
|
||||||
next={loadMore}
|
next={loadMore}
|
||||||
hasMore={size !== props.elmts.size}
|
hasMore={size !== elmts.size}
|
||||||
loader={<Loader />}
|
loader={<Loader />}
|
||||||
>
|
>
|
||||||
{props.elmts
|
{elmts
|
||||||
.slice(0, size)
|
.slice(0, size)
|
||||||
.toIndexedSeq()
|
.toIndexedSeq()
|
||||||
.map(function(el, index) {
|
.map(function(el, index) {
|
||||||
const imdbId = el.get("imdb_id");
|
const imdbId = el.get("imdb_id");
|
||||||
const selected = imdbId === props.selectedImdbId ? true : false;
|
const selected = imdbId === selectedImdbId ? true : false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Poster
|
<Poster
|
||||||
url={el.get("poster_url")}
|
url={el.get("poster_url")}
|
||||||
key={index}
|
key={index}
|
||||||
selected={selected}
|
selected={selected}
|
||||||
onClick={() => props.selectPoster(imdbId)}
|
onClick={() => selectPoster(imdbId)}
|
||||||
onDoubleClick={() => props.onDoubleClick(imdbId)}
|
onDoubleClick={() => onDoubleClick(imdbId)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}, this)}
|
}, this)}
|
||||||
|
@ -55,7 +55,7 @@ const MoviesRoute = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
MoviesRoute.propTypes = {
|
MoviesRoute.propTypes = {
|
||||||
component: PropTypes.func,
|
component: PropTypes.object,
|
||||||
match: PropTypes.object,
|
match: PropTypes.object,
|
||||||
isExplorerFetched: PropTypes.bool.isRequired,
|
isExplorerFetched: PropTypes.bool.isRequired,
|
||||||
fetchMovies: PropTypes.func.isRequired,
|
fetchMovies: PropTypes.func.isRequired,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect, useCallback } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { addTorrent, searchTorrents } from "../../actions/torrents";
|
import { addTorrent, searchTorrents } from "../../actions/torrents";
|
||||||
@ -15,12 +15,21 @@ const mapStateToProps = state => ({
|
|||||||
});
|
});
|
||||||
const mapDispatchToProps = { addTorrent, searchTorrents };
|
const mapDispatchToProps = { addTorrent, searchTorrents };
|
||||||
|
|
||||||
const TorrentSearch = props => {
|
const TorrentSearch = ({
|
||||||
const [search, setSearch] = useState(props.match.params.search || "");
|
searching,
|
||||||
const [type, setType] = useState(props.match.params.type || "");
|
searchTorrents,
|
||||||
|
results,
|
||||||
|
addTorrent,
|
||||||
|
history,
|
||||||
|
match
|
||||||
|
}) => {
|
||||||
|
const [search, setSearch] = useState(match.params.search || "");
|
||||||
|
const [type, setType] = useState(match.params.type || "");
|
||||||
const [url, setUrl] = useState("");
|
const [url, setUrl] = useState("");
|
||||||
|
|
||||||
const getUrl = () => `/torrents/search/${type}/${encodeURI(search)}`;
|
const getUrl = useCallback(() => {
|
||||||
|
return `/torrents/search/${type}/${encodeURI(search)}`;
|
||||||
|
}, [type, search]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (search === "") {
|
if (search === "") {
|
||||||
@ -31,9 +40,9 @@ const TorrentSearch = props => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const url = getUrl();
|
const url = getUrl();
|
||||||
props.searchTorrents(url);
|
searchTorrents(url);
|
||||||
props.history.push(url);
|
history.push(url);
|
||||||
}, [url]);
|
}, [url, getUrl, searchTorrents, history, search, type]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
@ -68,9 +77,9 @@ const TorrentSearch = props => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<TorrentList
|
<TorrentList
|
||||||
searching={props.searching}
|
searching={searching}
|
||||||
results={props.results}
|
results={results}
|
||||||
addTorrent={props.addTorrent}
|
addTorrent={addTorrent}
|
||||||
searchFromURL={search}
|
searchFromURL={search}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState, useCallback } from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { setFetchedTorrents } from "../actions/torrents";
|
import { setFetchedTorrents } from "../actions/torrents";
|
||||||
import { newMovieEvent } from "../actions/movies";
|
import { newMovieEvent } from "../actions/movies";
|
||||||
@ -13,47 +14,28 @@ const mapDispatchToProps = {
|
|||||||
newEpisodeEvent
|
newEpisodeEvent
|
||||||
};
|
};
|
||||||
|
|
||||||
const WsHandler = props => {
|
const WsHandler = ({
|
||||||
|
isLogged,
|
||||||
|
setFetchedTorrents,
|
||||||
|
newMovieEvent,
|
||||||
|
newEpisodeEvent
|
||||||
|
}) => {
|
||||||
const [ws, setWs] = useState(null);
|
const [ws, setWs] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
const stop = useCallback(() => {
|
||||||
const intervalID = setInterval(() => {
|
|
||||||
if (!ws) {
|
|
||||||
connect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ws.readyState === WebSocket.CLOSED) {
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
}, 10000);
|
|
||||||
|
|
||||||
if (!ws) {
|
|
||||||
connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (ws) {
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
clearInterval(intervalID);
|
|
||||||
};
|
|
||||||
}, [ws]);
|
|
||||||
|
|
||||||
const stop = () => {
|
|
||||||
if (!ws) {
|
if (!ws) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ws.close();
|
ws.close();
|
||||||
setWs(null);
|
setWs(null);
|
||||||
};
|
}, [ws]);
|
||||||
|
|
||||||
const connect = () => {
|
const connect = useCallback(() => {
|
||||||
if (ws) {
|
if (ws) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!props.isLogged) {
|
if (!isLogged) {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,13 +73,13 @@ const WsHandler = props => {
|
|||||||
|
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case "torrents":
|
case "torrents":
|
||||||
props.setFetchedTorrents(data.message);
|
setFetchedTorrents(data.message);
|
||||||
break;
|
break;
|
||||||
case "newVideo":
|
case "newVideo":
|
||||||
if (data.message.type === "movie") {
|
if (data.message.type === "movie") {
|
||||||
props.newMovieEvent(data.message.data);
|
newMovieEvent(data.message.data);
|
||||||
} else if (data.message.type === "episode") {
|
} else if (data.message.type === "episode") {
|
||||||
props.newEpisodeEvent(data.message.data);
|
newEpisodeEvent(data.message.data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -108,9 +90,39 @@ const WsHandler = props => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
setWs(socket);
|
setWs(socket);
|
||||||
};
|
}, [ws, isLogged, newMovieEvent, setFetchedTorrents, newEpisodeEvent, stop]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const intervalID = setInterval(() => {
|
||||||
|
if (!ws) {
|
||||||
|
connect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ws.readyState === WebSocket.CLOSED) {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
if (!ws) {
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (ws) {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
clearInterval(intervalID);
|
||||||
|
};
|
||||||
|
}, [ws, connect, stop]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
WsHandler.propTypes = {
|
||||||
|
isLogged: PropTypes.bool.isRequired,
|
||||||
|
setFetchedTorrents: PropTypes.func,
|
||||||
|
newMovieEvent: PropTypes.func,
|
||||||
|
newEpisodeEvent: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(WsHandler);
|
export default connect(mapStateToProps, mapDispatchToProps)(WsHandler);
|
||||||
|
@ -104,11 +104,8 @@ const config = {
|
|||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: [".js"]
|
extensions: [".js"]
|
||||||
}
|
},
|
||||||
|
devtool: mode === "production" ? "source-map" : "inline-source-map"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== "production") {
|
|
||||||
config.devtool = "#cheap-module-source-map";
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user