diff --git a/gtk/Application.cc b/gtk/Application.cc index 9e250bb85..3d4101c04 100644 --- a/gtk/Application.cc +++ b/gtk/Application.cc @@ -1359,6 +1359,10 @@ void Application::Impl::on_prefs_changed(tr_quark const key) tr_sessionSetDeleteSource(tr, gtr_pref_flag_get(key)); break; + case TR_KEY_torrent_complete_verify_enabled: + tr_sessionSetCompleteVerifyEnabled(tr, gtr_pref_flag_get(key)); + break; + default: break; } diff --git a/libtransmission/quark.cc b/libtransmission/quark.cc index d4f987694..2e01650b5 100644 --- a/libtransmission/quark.cc +++ b/libtransmission/quark.cc @@ -386,6 +386,7 @@ auto constexpr MyStatic = std::array{ "torrent-complete-notification-enabled"sv, "torrent-complete-sound-command"sv, "torrent-complete-sound-enabled"sv, + "torrent-complete-verify-enabled"sv, "torrent-duplicate"sv, "torrent-get"sv, "torrent-set"sv, diff --git a/libtransmission/quark.h b/libtransmission/quark.h index 61d6d2eb5..a708cf9a4 100644 --- a/libtransmission/quark.h +++ b/libtransmission/quark.h @@ -388,6 +388,7 @@ enum // NOLINT(performance-enum-size) TR_KEY_torrent_complete_notification_enabled, TR_KEY_torrent_complete_sound_command, TR_KEY_torrent_complete_sound_enabled, + TR_KEY_torrent_complete_verify_enabled, TR_KEY_torrent_duplicate, TR_KEY_torrent_get, TR_KEY_torrent_set, diff --git a/libtransmission/session.cc b/libtransmission/session.cc index 8b9bccd44..0c1e32343 100644 --- a/libtransmission/session.cc +++ b/libtransmission/session.cc @@ -1659,6 +1659,15 @@ size_t tr_sessionGetCacheLimit_MB(tr_session const* session) // --- +void tr_sessionSetCompleteVerifyEnabled(tr_session* session, bool enabled) +{ + TR_ASSERT(session != nullptr); + + session->settings_.torrent_complete_verify_enabled = enabled; +} + +// --- + void tr_session::setDefaultTrackers(std::string_view trackers) { auto const oldval = default_trackers_; diff --git a/libtransmission/session.h b/libtransmission/session.h index c74ad72b4..cf076cff1 100644 --- a/libtransmission/session.h +++ b/libtransmission/session.h @@ -416,6 +416,7 @@ public: bool speed_limit_down_enabled = false; bool speed_limit_up_enabled = false; bool tcp_enabled = true; + bool torrent_complete_verify_enabled = false; bool utp_enabled = true; double ratio_limit = 2.0; size_t cache_size_mbytes = 4U; @@ -513,6 +514,7 @@ public: { TR_KEY_start_added_torrents, &should_start_added_torrents }, { TR_KEY_tcp_enabled, &tcp_enabled }, { TR_KEY_torrent_added_verify_mode, &torrent_added_verify_mode }, + { TR_KEY_torrent_complete_verify_enabled, &torrent_complete_verify_enabled }, { TR_KEY_trash_original_torrent_files, &should_delete_source_torrents }, { TR_KEY_umask, &umask }, { TR_KEY_upload_slots_per_torrent, &upload_slots_per_torrent }, @@ -963,6 +965,11 @@ public: return settings().torrent_added_verify_mode == TR_VERIFY_ADDED_FULL; } + [[nodiscard]] constexpr auto shouldFullyVerifyCompleteTorrents() const noexcept + { + return settings().torrent_complete_verify_enabled; + } + [[nodiscard]] constexpr auto shouldDeleteSource() const noexcept { return settings().should_delete_source_torrents; @@ -1207,6 +1214,7 @@ private: friend void tr_sessionSetAntiBruteForceEnabled(tr_session* session, bool is_enabled); friend void tr_sessionSetAntiBruteForceThreshold(tr_session* session, int max_bad_requests); friend void tr_sessionSetCacheLimit_MB(tr_session* session, size_t mbytes); + friend void tr_sessionSetCompleteVerifyEnabled(tr_session* session, bool enabled); friend void tr_sessionSetDHTEnabled(tr_session* session, bool enabled); friend void tr_sessionSetDeleteSource(tr_session* session, bool delete_source); friend void tr_sessionSetEncryption(tr_session* session, tr_encryption_mode mode); diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index 08a4359df..772c0d137 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -1786,6 +1786,12 @@ void tr_torrent::recheck_completeness() bool const recent_change = bytes_downloaded_.during_this_session() != 0U; bool const was_running = is_running(); + if (new_completeness != TR_LEECH && was_running && session->shouldFullyVerifyCompleteTorrents()) + { + tr_torrentVerify(this); + return; + } + tr_logAddTraceTor( this, fmt::format( @@ -1794,10 +1800,11 @@ void tr_torrent::recheck_completeness() get_completion_string(new_completeness))); completeness_ = new_completeness; - session->close_torrent_files(id()); if (is_done()) { + session->close_torrent_files(id()); + if (recent_change) { // https://www.bittorrent.org/beps/bep_0003.html diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index 8a67493db..be464403d 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -635,7 +635,7 @@ size_t tr_sessionGetQueueStalledMinutes(tr_session const* session); Stalled torrents are left running but are not counted by `tr_sessionGetQueueSize()`. */ void tr_sessionSetQueueStalledMinutes(tr_session* session, int minutes); -/** @return true if we're torrents idle for over N minutes will be flagged as 'stalled' */ +/** @return true if torrents idle for over N minutes will be flagged as 'stalled' */ bool tr_sessionGetQueueStalledEnabled(tr_session const* session); /** @brief Set whether or not to count torrents idle for over N minutes as 'stalled' */ @@ -646,10 +646,14 @@ void tr_sessionSetQueueStartCallback(tr_session* session, void (*callback)(tr_se // --- +/** @brief Set whether or not to verify data when torrent download is complete */ +void tr_sessionSetCompleteVerifyEnabled(tr_session* session, bool enabled); + +// --- + /** * Load all the torrents in the session's torrent folder. - * This can be used at startup to kickstart all the torrents - * from the previous session. + * This can be used at startup to kickstart all the torrents from the previous session. * * @return the number of torrents in the session */ diff --git a/macosx/Base.lproj/PrefsWindow.xib b/macosx/Base.lproj/PrefsWindow.xib index bfbb8e676..3af39f307 100644 --- a/macosx/Base.lproj/PrefsWindow.xib +++ b/macosx/Base.lproj/PrefsWindow.xib @@ -1076,6 +1076,17 @@ + @@ -1084,9 +1095,9 @@ + - @@ -1099,6 +1110,7 @@ + @@ -1117,6 +1129,7 @@ + @@ -1135,6 +1148,7 @@ + diff --git a/macosx/Controller.mm b/macosx/Controller.mm index 735499093..ca030a0a2 100644 --- a/macosx/Controller.mm +++ b/macosx/Controller.mm @@ -497,6 +497,7 @@ void onTorrentCompletenessChanged(tr_torrent* tor, tr_completeness status, bool TR_KEY_incomplete_dir, [_fDefaults stringForKey:@"IncompleteDownloadFolder"].stringByExpandingTildeInPath.UTF8String); tr_variantDictAddBool(&settings, TR_KEY_incomplete_dir_enabled, [_fDefaults boolForKey:@"UseIncompleteDownloadFolder"]); + tr_variantDictAddBool(&settings, TR_KEY_torrent_complete_verify_enabled, [_fDefaults boolForKey:@"VerifyDataOnCompletion"]); tr_variantDictAddBool(&settings, TR_KEY_lpd_enabled, [_fDefaults boolForKey:@"LocalPeerDiscoveryGlobal"]); tr_variantDictAddInt(&settings, TR_KEY_message_level, TR_LOG_DEBUG); tr_variantDictAddInt(&settings, TR_KEY_peer_limit_global, [_fDefaults integerForKey:@"PeersTotal"]); diff --git a/macosx/PrefsController.mm b/macosx/PrefsController.mm index 8460dcec0..0858797f3 100644 --- a/macosx/PrefsController.mm +++ b/macosx/PrefsController.mm @@ -916,6 +916,12 @@ static NSString* const kWebUIURLFormat = @"http://localhost:%ld/"; [self updateShowAddMagnetWindowField]; } +- (IBAction)setVerifyDataOnCompletion:(id)sender +{ + bool enabled = [self.fDefaults boolForKey:@"VerifyDataOnCompletion"]; + tr_sessionSetCompleteVerifyEnabled(self.fHandle, enabled); +} + - (void)folderSheetShow:(id)sender { NSOpenPanel* panel = [NSOpenPanel openPanel];