diff --git a/examples/client_test.cpp b/examples/client_test.cpp index fefae6d9a..e95f6dd13 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -1273,6 +1273,11 @@ int main(int argc, char* argv[]) ses.get_torrent_status(&handles, boost::bind(&show_torrent, _1, torrent_filter, (int*)counters)); if (active_torrent >= int(handles.size())) active_torrent = handles.size() - 1; + std::vector feeds; + ses.get_feeds(feeds); + + counters[torrents_feeds] = feeds.size(); + std::sort(handles.begin(), handles.end(), &compare_torrent); if (loop_limit > 1) --loop_limit; @@ -1526,8 +1531,6 @@ int main(int argc, char* argv[]) if (torrent_filter == torrents_feeds) { - std::vector feeds; - ses.get_feeds(feeds); for (std::vector::iterator i = feeds.begin() , end(feeds.end()); i != end; ++i) { diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 11587ecd1..d4ada3745 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -270,6 +270,7 @@ namespace libtorrent torrent_handle add_torrent(add_torrent_params const&, error_code& ec); void remove_torrent(torrent_handle const& h, int options); + void remove_torrent_impl(boost::shared_ptr tptr, int options); void get_torrent_status(std::vector* ret , boost::function const& pred diff --git a/include/libtorrent/rss.hpp b/include/libtorrent/rss.hpp index ee28d5738..13b041ddc 100644 --- a/include/libtorrent/rss.hpp +++ b/include/libtorrent/rss.hpp @@ -153,10 +153,13 @@ namespace libtorrent // private: + void add_item(feed_item const& item); + feed_handle my_handle(); error_code m_error; std::vector m_items; + std::set m_urls; std::string m_title; std::string m_description; time_t m_last_attempt; diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 76c12787b..0284345b9 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -701,7 +701,11 @@ namespace libtorrent { return *m_torrent_file; } std::string const& uuid() const { return m_uuid; } + void set_uuid(std::string const& s) { m_uuid = s; } std::string const& url() const { return m_url; } + void set_url(std::string const& s) { m_url = s; } + std::string const& source_feed_url() const { return m_source_feed_url; } + void set_source_feed_url(std::string const& s) { m_source_feed_url = s; } std::vector const& trackers() const { return m_trackers; } diff --git a/src/rss.cpp b/src/rss.cpp index e20d7b6a8..cc3332cec 100644 --- a/src/rss.cpp +++ b/src/rss.cpp @@ -211,7 +211,7 @@ void parse_feed(feed_state& f, int token, char const* name, char const* val) f.in_item = false; if (!f.current_item.title.empty() && !f.current_item.url.empty()) - f.ret.m_items.push_back(f.current_item); + f.ret.add_item(f.current_item); f.current_item = feed_item(); } f.current_tag = ""; @@ -453,6 +453,14 @@ void feed::load_state(lazy_entry const& rd) m_items.push_back(feed_item()); load_struct(*e->list_at(i), &m_items.back(), feed_item_map , sizeof(feed_item_map)/sizeof(feed_item_map[0])); + + // don't load duplicates + if (m_urls.find(m_items.back().url) != m_urls.end()) + { + m_items.pop_back(); + continue; + } + m_urls.insert(m_items.back().url); } } load_struct(rd, &m_settings, feed_settings_map @@ -485,6 +493,16 @@ void feed::save_state(entry& rd) const , sizeof(add_torrent_map)/sizeof(add_torrent_map[0]), &add_def); } +void feed::add_item(feed_item const& item) +{ + // don't add duplicates + if (m_urls.find(item.url) != m_urls.end()) + return; + + m_urls.insert(item.url); + m_items.push_back(item); +} + void feed::update_feed() { if (m_updating) return; diff --git a/src/session_impl.cpp b/src/session_impl.cpp index cdec24565..8bdf0cb17 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -4034,11 +4034,20 @@ namespace aux { // is the torrent already active? boost::shared_ptr torrent_ptr = find_torrent(*ih).lock(); if (!torrent_ptr && !params.uuid.empty()) torrent_ptr = find_torrent(params.uuid).lock(); + // TODO: find by url? if (torrent_ptr) { if (!params.duplicate_is_error) + { + if (!params.uuid.empty() && torrent_ptr->uuid().empty()) + torrent_ptr->set_uuid(params.uuid); + if (!params.url.empty() && torrent_ptr->url().empty()) + torrent_ptr->set_url(params.url); + if (!params.source_feed_url.empty() && torrent_ptr->source_feed_url().empty()) + torrent_ptr->set_source_feed_url(params.source_feed_url); return torrent_handle(torrent_ptr); + } ec = errors::duplicate_torrent; return torrent_handle(); @@ -4148,7 +4157,17 @@ namespace aux { #else throw_invalid_handle(); #endif + remove_torrent_impl(tptr, options); + if (m_alerts.should_post()) + m_alerts.post_alert(torrent_removed_alert(tptr->get_handle(), tptr->info_hash())); + + tptr->set_queue_position(-1); + tptr->abort(); + } + + void session_impl::remove_torrent_impl(boost::shared_ptr tptr, int options) + { INVARIANT_CHECK; // remove from uuid list @@ -4175,10 +4194,6 @@ namespace aux { torrent& t = *i->second; if (options & session::delete_files) t.delete_files(); - t.abort(); - - if (m_alerts.should_post()) - m_alerts.post_alert(torrent_removed_alert(t.get_handle(), t.info_hash())); #ifdef TORRENT_DEBUG sha1_hash i_hash = t.torrent_file().info_hash(); @@ -4192,7 +4207,6 @@ namespace aux { if (i == m_next_connect_torrent) ++m_next_connect_torrent; - t.set_queue_position(-1); m_torrents.erase(i); #ifndef TORRENT_DISABLE_DHT diff --git a/src/torrent.cpp b/src/torrent.cpp index be3bf4eb6..a4264cfc6 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -612,9 +612,38 @@ namespace libtorrent #ifdef TORRENT_DEBUG int num_torrents = m_ses.m_torrents.size(); #endif - m_ses.m_torrents.erase(m_torrent_file->info_hash()); + // we're about to erase the session's reference to this + // torrent, create another reference + boost::shared_ptr me(shared_from_this()); + + m_ses.remove_torrent_impl(me, 0); + m_torrent_file = tf; - m_ses.m_torrents.insert(std::make_pair(m_torrent_file->info_hash(), shared_from_this())); + + // now, we might already have this torrent in the session. + session_impl::torrent_map::iterator i = m_ses.m_torrents.find(m_torrent_file->info_hash()); + if (i != m_ses.m_torrents.end()) + { + if (!m_uuid.empty() && i->second->uuid().empty()) + i->second->set_uuid(m_uuid); + if (!m_url.empty() && i->second->url().empty()) + i->second->set_url(m_url); + if (!m_source_feed_url.empty() && i->second->source_feed_url().empty()) + i->second->set_source_feed_url(m_source_feed_url); + + // insert this torrent in the uuid index + if (!m_uuid.empty() || !m_url.empty()) + { + m_ses.m_uuids.insert(std::make_pair(m_uuid.empty() + ? m_url : m_uuid, i->second)); + } + set_error(error_code(errors::duplicate_torrent, get_libtorrent_category()), ""); + abort(); + return; + } + + m_ses.m_torrents.insert(std::make_pair(m_torrent_file->info_hash(), me)); + if (!m_uuid.empty()) m_ses.m_uuids.insert(std::make_pair(m_uuid, me)); TORRENT_ASSERT(num_torrents == int(m_ses.m_torrents.size())); @@ -4308,6 +4337,16 @@ namespace libtorrent m_url = rd.dict_find_string_value("url"); m_uuid = rd.dict_find_string_value("uuid"); + m_source_feed_url = rd.dict_find_string_value("feed"); + + if (!m_uuid.empty() || !m_url.empty()) + { + boost::shared_ptr me(shared_from_this()); + + // insert this torrent in the uuid index + m_ses.m_uuids.insert(std::make_pair(m_uuid.empty() + ? m_url : m_uuid, me)); + } m_added_time = rd.dict_find_int_value("added_time", m_added_time); m_completed_time = rd.dict_find_int_value("completed_time", m_completed_time); @@ -4470,6 +4509,7 @@ namespace libtorrent if (!m_url.empty()) ret["url"] = m_url; if (!m_uuid.empty()) ret["uuid"] = m_uuid; + if (!m_source_feed_url.empty()) ret["feed"] = m_source_feed_url; const sha1_hash& info_hash = torrent_file().info_hash(); ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end());