diff --git a/CMakeLists.txt b/CMakeLists.txt
index db30a328..9f840322 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -154,6 +154,8 @@ add_executable(
src/methods/torrentspropertiesget.hpp
src/methods/torrentsquery.cpp
src/methods/torrentsquery.hpp
+ src/methods/torrentsrecheck.cpp
+ src/methods/torrentsrecheck.hpp
src/methods/torrentsremove.cpp
src/methods/torrentsremove.hpp
src/methods/torrentsresume.cpp
diff --git a/html/src/components/TorrentsList.tsx b/html/src/components/TorrentsList.tsx
index fb4a0b02..97dbaaf9 100644
--- a/html/src/components/TorrentsList.tsx
+++ b/html/src/components/TorrentsList.tsx
@@ -6,6 +6,7 @@ type TorrentsListProps = {
isDeleting: (torrent: Torrent) => boolean;
onMove: (torrent: Torrent) => void;
onPause: (torrent: Torrent) => void;
+ onRecheck: (torrent: Torrent) => void;
onRemove: (torrent: Torrent) => void;
onResume: (torrent: Torrent) => void;
onShowProperties: (torrent: Torrent) => void;
@@ -64,6 +65,7 @@ export default function TorrentsList(props: TorrentsListProps) {
onMove={props.onMove}
isDeleting={props.isDeleting}
onPause={props.onPause}
+ onRecheck={props.onRecheck}
onRemove={props.onRemove}
onResume={props.onResume}
onShowProperties={props.onShowProperties} />
diff --git a/html/src/components/TorrentsListItem.tsx b/html/src/components/TorrentsListItem.tsx
index 0e4231aa..1c61efed 100644
--- a/html/src/components/TorrentsListItem.tsx
+++ b/html/src/components/TorrentsListItem.tsx
@@ -1,7 +1,7 @@
import { Box, CircularProgress, CircularProgressLabel, Flex, Grid, GridItem, HStack, Icon, IconButton, Link, Menu, MenuButton, MenuDivider, MenuGroup, MenuItem, MenuList, Text, textDecoration, useColorMode } from "@chakra-ui/react";
import { filesize } from "filesize";
import { IconType } from "react-icons/lib";
-import { MdCheck, MdDelete, MdDriveFileMove, MdFileCopy, MdFolder, MdFolderOpen, MdLabel, MdOutlineMoreVert, MdOutlineReport, MdPause, MdPlayArrow, MdSchedule, MdTag, MdUpload, MdViewList } from "react-icons/md";
+import { MdCheck, MdDelete, MdDriveFileMove, MdFileCopy, MdFolder, MdFolderOpen, MdLabel, MdOutlineMoreVert, MdOutlineReport, MdPause, MdPlayArrow, MdSchedule, MdSearch, MdTag, MdUpload, MdViewList } from "react-icons/md";
import { Torrent } from "../types"
import useNinja from "../contexts/ninja";
@@ -12,6 +12,7 @@ type TorrentsListItemProps = {
isDeleting: (torrent: Torrent) => boolean;
onMove: (torrent: Torrent) => void;
onPause: (torrent: Torrent) => void;
+ onRecheck: (torrent: Torrent) => void;
onRemove: (torrent: Torrent) => void;
onResume: (torrent: Torrent) => void;
onShowProperties: (torrent: Torrent) => void;
@@ -62,6 +63,7 @@ function stateColor(torrent: Torrent) {
}
switch (torrent.state) {
+ case 1: return "gray.500";
case 2: return "gray.600";
case 3: return "blue.500";
case 5: return "green.300";
@@ -104,7 +106,7 @@ function progressLabel(torrent: Torrent) {
if (isPaused(torrent.flags)) {
return "checking_files_queued";
}
- return "checking_files";
+ break;
}
case 2: return ;
case 3: {
@@ -314,33 +316,40 @@ export default function TorrentsListItem(props: TorrentsListItemProps) {
size={"sm"}
/>
+ {
+ isPaused(props.torrent.flags)
+ ? }
+ onClick={() => props.onResume(props.torrent)}
+ >
+ Resume
+
+ : }
+ onClick={() => props.onPause(props.torrent)}
+ >
+ Pause
+
+ }
+
- {
- isPaused(props.torrent.flags)
- ? }
- onClick={() => props.onResume(props.torrent)}
- >
- Resume
-
- : }
- onClick={() => props.onPause(props.torrent)}
- >
- Pause
-
- }
+ }
+ onClick={() => props.onRecheck(props.torrent)}
+ >
+ Check files
+
}
onClick={() => props.onMove(props.torrent)}
>
- Move
+ Move contents
}
onClick={() => props.onRemove(props.torrent)}
>
- Remove
+ Remove torrent
diff --git a/html/src/pages/Home.tsx b/html/src/pages/Home.tsx
index 114bd562..74180ef7 100644
--- a/html/src/pages/Home.tsx
+++ b/html/src/pages/Home.tsx
@@ -38,6 +38,7 @@ export default function Home() {
const torrentsMove = useInvoker("torrents.move");
const torrentsPause = useInvoker("torrents.pause");
+ const torrentsRecheck = useInvoker("torrents.recheck");
const torrentsRemove = useInvoker("torrents.remove");
const torrentsResume = useInvoker("torrents.resume");
@@ -176,6 +177,10 @@ export default function Home() {
});
await mutate();
}}
+ onRecheck={async (t) => {
+ await torrentsRecheck({ info_hash: t.info_hash });
+ await mutate();
+ }}
onRemove={(torrent) => setRemoveTorrent(torrent)}
onResume={async (t) => {
await torrentsResume({
diff --git a/src/json/all.hpp b/src/json/all.hpp
index e7405a00..144e972c 100644
--- a/src/json/all.hpp
+++ b/src/json/all.hpp
@@ -20,6 +20,7 @@
#include "torrentspeerslist.hpp"
#include "torrentspropertiesget.hpp"
#include "torrentsquery.hpp"
+#include "torrentsrecheck.hpp"
#include "torrentsremove.hpp"
#include "torrentsresume.hpp"
#include "torrentspropertiesset.hpp"
diff --git a/src/json/torrentsrecheck.hpp b/src/json/torrentsrecheck.hpp
new file mode 100644
index 00000000..9c4940ac
--- /dev/null
+++ b/src/json/torrentsrecheck.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include
+
+#include "../methods/torrentsrecheck_reqres.hpp"
+#include "ltinfohash.hpp"
+#include "utils.hpp"
+
+namespace porla::Methods
+{
+ NLOHMANN_JSONIFY_ALL_THINGS(
+ TorrentsRecheckReq,
+ info_hash)
+
+ static void to_json(json& j, const TorrentsRecheckRes& res)
+ {
+ j = {};
+ }
+}
diff --git a/src/main.cpp b/src/main.cpp
index e75bb9fe..774a60cf 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -43,6 +43,7 @@
#include "methods/torrentspeersadd.hpp"
#include "methods/torrentspeerslist.hpp"
#include "methods/torrentsquery.hpp"
+#include "methods/torrentsrecheck.hpp"
#include "methods/torrentsremove.hpp"
#include "methods/torrentsresume.hpp"
#include "methods/torrentspropertiesget.hpp"
@@ -151,6 +152,7 @@ int main(int argc, char* argv[])
{"torrents.peers.list", porla::Methods::TorrentsPeersList(session)},
{"torrents.properties.get", porla::Methods::TorrentsPropertiesGet(session)},
{"torrents.properties.set", porla::Methods::TorrentsPropertiesSet(session)},
+ {"torrents.recheck", porla::Methods::TorrentsRecheck(session)},
{"torrents.query", porla::Methods::TorrentsQuery(session)},
{"torrents.remove", porla::Methods::TorrentsRemove(session)},
{"torrents.resume", porla::Methods::TorrentsResume(session)},
diff --git a/src/methods/torrentsmove.cpp b/src/methods/torrentsmove.cpp
index ce159cc0..6fcd1b3b 100644
--- a/src/methods/torrentsmove.cpp
+++ b/src/methods/torrentsmove.cpp
@@ -21,7 +21,7 @@ void TorrentsMove::Invoke(const TorrentsMoveReq &req, WriteCb c
return cb.Error(-1, "Torrent not found");
}
- lt::move_flags_t flags = lt::move_flags_t::always_replace_files;
+ lt::move_flags_t flags = lt::move_flags_t::dont_replace;
if (req.flags.has_value())
{
diff --git a/src/methods/torrentsrecheck.cpp b/src/methods/torrentsrecheck.cpp
new file mode 100644
index 00000000..ac87dd87
--- /dev/null
+++ b/src/methods/torrentsrecheck.cpp
@@ -0,0 +1,30 @@
+#include "torrentsrecheck.hpp"
+
+#include
+#include
+
+#include "../session.hpp"
+
+using porla::Methods::TorrentsRecheck;
+using porla::Methods::TorrentsRecheckReq;
+using porla::Methods::TorrentsRecheckRes;
+
+TorrentsRecheck::TorrentsRecheck(porla::ISession &session)
+ : m_session(session)
+{
+}
+
+void TorrentsRecheck::Invoke(const TorrentsRecheckReq &req, WriteCb cb)
+{
+ auto const& torrents = m_session.Torrents();
+ auto const& handle = torrents.find(req.info_hash);
+
+ if (handle == torrents.end())
+ {
+ return cb.Error(-1, "Torrent not found");
+ }
+
+ m_session.Recheck(req.info_hash);
+
+ return cb.Ok(TorrentsRecheckRes{});
+}
diff --git a/src/methods/torrentsrecheck.hpp b/src/methods/torrentsrecheck.hpp
new file mode 100644
index 00000000..f2fd31d5
--- /dev/null
+++ b/src/methods/torrentsrecheck.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "method.hpp"
+#include "torrentsrecheck_reqres.hpp"
+
+namespace porla
+{
+ class ISession;
+}
+
+namespace porla::Methods
+{
+ class TorrentsRecheck : public Method
+ {
+ public:
+ explicit TorrentsRecheck(ISession& session);
+
+ protected:
+ void Invoke(const TorrentsRecheckReq& req, WriteCb cb) override;
+
+ private:
+ ISession& m_session;
+ };
+}
diff --git a/src/methods/torrentsrecheck_reqres.hpp b/src/methods/torrentsrecheck_reqres.hpp
new file mode 100644
index 00000000..c60a7243
--- /dev/null
+++ b/src/methods/torrentsrecheck_reqres.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include
+#include
+
+#include
+
+namespace porla::Methods
+{
+ struct TorrentsRecheckReq
+ {
+ libtorrent::info_hash_t info_hash;
+ };
+
+ struct TorrentsRecheckRes
+ {
+ };
+}
diff --git a/src/session.cpp b/src/session.cpp
index 644a6b67..d2e16144 100644
--- a/src/session.cpp
+++ b/src/session.cpp
@@ -397,6 +397,60 @@ int Session::Query(const std::string_view& query, const std::function(alert);
+ BOOST_LOG_TRIVIAL(info) << "Torrent " << tca->torrent_name() << " finished checking";
+
+ if (m_oneshot_torrent_callbacks.contains({ alert->type(), tca->handle.info_hashes()}))
+ {
+ for (auto && cb : m_oneshot_torrent_callbacks.at({ alert->type(), tca->handle.info_hashes() }))
+ {
+ cb();
+ }
+
+ m_oneshot_torrent_callbacks.erase({ alert->type(), tca->handle.info_hashes() });
+ }
+
+ break;
+ }
case lt::torrent_finished_alert::alert_type:
{
auto tfa = lt::alert_cast(alert);
auto const& status = tfa->handle.status();
- BOOST_LOG_TRIVIAL(info) << "Torrent " << status.name << " finished";
if (status.total_download > 0)
{
// Only emit this event if we have downloaded any data this session.
+ BOOST_LOG_TRIVIAL(info) << "Torrent " << status.name << " finished";
m_torrentFinished(status);
}
diff --git a/src/session.hpp b/src/session.hpp
index f3d0b965..356d2e84 100644
--- a/src/session.hpp
+++ b/src/session.hpp
@@ -49,6 +49,7 @@ namespace porla
virtual void ApplySettings(const libtorrent::settings_pack& settings) = 0;
virtual void Pause() = 0;
virtual int Query(const std::string_view& query, const std::function& cb) = 0;
+ virtual void Recheck(const lt::info_hash_t& hash) = 0;
virtual void Remove(const lt::info_hash_t& hash, bool remove_data) = 0;
virtual void Resume() = 0;
virtual libtorrent::settings_pack Settings() = 0;
@@ -118,6 +119,7 @@ namespace porla
void ApplySettings(const libtorrent::settings_pack& settings) override;
void Pause() override;
int Query(const std::string_view& query, const std::function& cb) override;
+ void Recheck(const lt::info_hash_t& hash) override;
void Remove(const lt::info_hash_t& hash, bool remove_data) override;
void Resume() override;
libtorrent::settings_pack Settings() override;
@@ -149,5 +151,6 @@ namespace porla
std::unique_ptr m_session;
std::map m_torrents;
+ std::map, std::vector>> m_oneshot_torrent_callbacks;
};
}