playlist: make kept song count collision resistant
This commit is contained in:
@@ -398,7 +398,7 @@ void Browser::LocateSong(const MPD::Song &s)
|
|||||||
GetDirectory(s.getDirectory());
|
GetDirectory(s.getDirectory());
|
||||||
for (size_t i = 0; i < w.size(); ++i)
|
for (size_t i = 0; i < w.size(); ++i)
|
||||||
{
|
{
|
||||||
if (w[i].value().type == itSong && s.getHash() == w[i].value().song->getHash())
|
if (w[i].value().type == itSong && s == *w[i].value().song)
|
||||||
{
|
{
|
||||||
w.highlight(i);
|
w.highlight(i);
|
||||||
break;
|
break;
|
||||||
@@ -460,16 +460,7 @@ void Browser::GetDirectory(std::string dir, std::string subdir)
|
|||||||
}
|
}
|
||||||
case itSong:
|
case itSong:
|
||||||
{
|
{
|
||||||
bool bold = 0;
|
w.addItem(*it, myPlaylist->checkForSong(*it->song));
|
||||||
for (size_t i = 0; i < myPlaylist->main().size(); ++i)
|
|
||||||
{
|
|
||||||
if (myPlaylist->main().at(i).value().getHash() == it->song->getHash())
|
|
||||||
{
|
|
||||||
bold = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.addItem(*it, bold);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -980,11 +980,11 @@ void MediaLibrary::LocateSong(const MPD::Song &s)
|
|||||||
if (Songs.empty())
|
if (Songs.empty())
|
||||||
update();
|
update();
|
||||||
|
|
||||||
if (s.getHash() != Songs.current().value().getHash())
|
if (s != Songs.current().value())
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < Songs.size(); ++i)
|
for (size_t i = 0; i < Songs.size(); ++i)
|
||||||
{
|
{
|
||||||
if (s.getHash() == Songs[i].value().getHash())
|
if (s == Songs[i].value())
|
||||||
{
|
{
|
||||||
Songs.highlight(i);
|
Songs.highlight(i);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -360,20 +360,20 @@ unsigned Playlist::currentSongLength() const
|
|||||||
|
|
||||||
bool Playlist::checkForSong(const MPD::Song &s)
|
bool Playlist::checkForSong(const MPD::Song &s)
|
||||||
{
|
{
|
||||||
return m_song_hashes.find(s.getHash()) != m_song_hashes.end();
|
return m_song_refs.find(s) != m_song_refs.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Playlist::registerHash(size_t hash)
|
void Playlist::registerSong(const MPD::Song &s)
|
||||||
{
|
{
|
||||||
++m_song_hashes[hash];
|
++m_song_refs[s];
|
||||||
}
|
}
|
||||||
|
|
||||||
void Playlist::unregisterHash(size_t hash)
|
void Playlist::unregisterSong(const MPD::Song &s)
|
||||||
{
|
{
|
||||||
auto it = m_song_hashes.find(hash);
|
auto it = m_song_refs.find(s);
|
||||||
assert(it != m_song_hashes.end());
|
assert(it != m_song_refs.end());
|
||||||
if (it->second == 1)
|
if (it->second == 1)
|
||||||
m_song_hashes.erase(it);
|
m_song_refs.erase(it);
|
||||||
else
|
else
|
||||||
--it->second;
|
--it->second;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ struct Playlist: Screen<NC::Menu<MPD::Song>>, Filterable, HasSongs, Searchable,
|
|||||||
unsigned currentSongLength() const;
|
unsigned currentSongLength() const;
|
||||||
|
|
||||||
bool checkForSong(const MPD::Song &s);
|
bool checkForSong(const MPD::Song &s);
|
||||||
void registerHash(size_t hash);
|
void registerSong(const MPD::Song &s);
|
||||||
void unregisterHash(size_t hash);
|
void unregisterSong(const MPD::Song &s);
|
||||||
|
|
||||||
void reloadTotalLength() { m_reload_total_length = true; }
|
void reloadTotalLength() { m_reload_total_length = true; }
|
||||||
void reloadRemaining() { m_reload_remaining = true; }
|
void reloadRemaining() { m_reload_remaining = true; }
|
||||||
@@ -95,7 +95,7 @@ private:
|
|||||||
|
|
||||||
std::string m_stats;
|
std::string m_stats;
|
||||||
|
|
||||||
std::unordered_map<size_t, int> m_song_hashes;
|
std::unordered_map<MPD::Song, int, MPD::Song::Hash> m_song_refs;
|
||||||
|
|
||||||
size_t m_total_length;;
|
size_t m_total_length;;
|
||||||
size_t m_remaining_time;
|
size_t m_remaining_time;
|
||||||
|
|||||||
10
src/song.cpp
10
src/song.cpp
@@ -30,13 +30,13 @@
|
|||||||
#include "utility/wide_string.h"
|
#include "utility/wide_string.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
|
|
||||||
namespace {//
|
namespace {
|
||||||
|
|
||||||
size_t calc_hash(const char* s, unsigned seed = 0)
|
size_t calc_hash(const char* s, unsigned seed = 0)
|
||||||
{
|
{
|
||||||
size_t hash = seed;
|
size_t hash = seed;
|
||||||
while (*s)
|
while (*s)
|
||||||
hash = hash * 101 + *s++;
|
hash = hash * 101 + *s++;
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,12 +211,6 @@ std::string MPD::Song::getTags(GetFunction f, const std::string &tags_separator)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned Song::getHash() const
|
|
||||||
{
|
|
||||||
assert(m_song);
|
|
||||||
return m_hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned Song::getDuration() const
|
unsigned Song::getDuration() const
|
||||||
{
|
{
|
||||||
assert(m_song);
|
assert(m_song);
|
||||||
|
|||||||
20
src/song.h
20
src/song.h
@@ -21,6 +21,7 @@
|
|||||||
#ifndef NCMPCPP_SONG_H
|
#ifndef NCMPCPP_SONG_H
|
||||||
#define NCMPCPP_SONG_H
|
#define NCMPCPP_SONG_H
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -32,6 +33,10 @@ namespace MPD {//
|
|||||||
|
|
||||||
struct Song
|
struct Song
|
||||||
{
|
{
|
||||||
|
struct Hash {
|
||||||
|
size_t operator()(const Song &s) const { return s.m_hash; }
|
||||||
|
};
|
||||||
|
|
||||||
typedef std::string (Song::*GetFunction)(unsigned) const;
|
typedef std::string (Song::*GetFunction)(unsigned) const;
|
||||||
|
|
||||||
Song() { }
|
Song() { }
|
||||||
@@ -61,7 +66,6 @@ struct Song
|
|||||||
|
|
||||||
virtual std::string getTags(GetFunction f, const std::string &tags_separator) const;
|
virtual std::string getTags(GetFunction f, const std::string &tags_separator) const;
|
||||||
|
|
||||||
virtual unsigned getHash() const;
|
|
||||||
virtual unsigned getDuration() const;
|
virtual unsigned getDuration() const;
|
||||||
virtual unsigned getPosition() const;
|
virtual unsigned getPosition() const;
|
||||||
virtual unsigned getID() const;
|
virtual unsigned getID() const;
|
||||||
@@ -76,9 +80,19 @@ struct Song
|
|||||||
virtual std::string toString(const std::string &fmt, const std::string &tags_separator,
|
virtual std::string toString(const std::string &fmt, const std::string &tags_separator,
|
||||||
const std::string &escape_chars = "") const;
|
const std::string &escape_chars = "") const;
|
||||||
|
|
||||||
bool operator==(const Song &rhs) const { return m_hash == rhs.m_hash; }
|
bool operator==(const Song &rhs) const {
|
||||||
bool operator!=(const Song &rhs) const { return m_hash != rhs.m_hash; }
|
if (m_hash != rhs.m_hash)
|
||||||
|
return false;
|
||||||
|
return strcmp(c_uri(), rhs.c_uri()) == 0;
|
||||||
|
}
|
||||||
|
bool operator!=(const Song &rhs) const {
|
||||||
|
if (m_hash != rhs.m_hash)
|
||||||
|
return true;
|
||||||
|
return strcmp(c_uri(), rhs.c_uri()) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *c_uri() const { return m_song ? mpd_song_get_uri(m_song.get()) : ""; }
|
||||||
|
|
||||||
static std::string ShowTime(unsigned length);
|
static std::string ShowTime(unsigned length);
|
||||||
static void validateFormat(const std::string &fmt);
|
static void validateFormat(const std::string &fmt);
|
||||||
|
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ void Status::Changes::playlist()
|
|||||||
auto it = myPlaylist->main().begin()+playlist_length;
|
auto it = myPlaylist->main().begin()+playlist_length;
|
||||||
auto end = myPlaylist->main().end();
|
auto end = myPlaylist->main().end();
|
||||||
for (; it != end; ++it)
|
for (; it != end; ++it)
|
||||||
myPlaylist->unregisterHash(it->value().getHash());
|
myPlaylist->unregisterSong(it->value());
|
||||||
myPlaylist->main().resizeList(playlist_length);
|
myPlaylist->main().resizeList(playlist_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,12 +267,12 @@ void Status::Changes::playlist()
|
|||||||
{
|
{
|
||||||
// if song's already in playlist, replace it with a new one
|
// if song's already in playlist, replace it with a new one
|
||||||
MPD::Song &old_s = myPlaylist->main()[pos].value();
|
MPD::Song &old_s = myPlaylist->main()[pos].value();
|
||||||
myPlaylist->unregisterHash(old_s.getHash());
|
myPlaylist->unregisterSong(old_s);
|
||||||
old_s = s;
|
old_s = s;
|
||||||
}
|
}
|
||||||
else // otherwise just add it to playlist
|
else // otherwise just add it to playlist
|
||||||
myPlaylist->main().addItem(s);
|
myPlaylist->main().addItem(s);
|
||||||
myPlaylist->registerHash(s.getHash());
|
myPlaylist->registerSong(s);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1025,7 +1025,7 @@ void TagEditor::LocateSong(const MPD::Song &s)
|
|||||||
// highlight our file
|
// highlight our file
|
||||||
for (size_t i = 0; i < Tags->size(); ++i)
|
for (size_t i = 0; i < Tags->size(); ++i)
|
||||||
{
|
{
|
||||||
if ((*Tags)[i].value().getHash() == s.getHash())
|
if ((*Tags)[i].value() == s)
|
||||||
{
|
{
|
||||||
Tags->highlight(i);
|
Tags->highlight(i);
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user