1
0
mirror of https://github.com/SuperBFG7/ympd synced 2024-06-22 21:03:13 +00:00

Feat: Smart playlists (most played and best rated) #38

This commit is contained in:
jcorporation 2018-09-24 21:55:53 +01:00
parent a8a8503a26
commit 76161dc0ac
11 changed files with 143 additions and 20 deletions

View File

@ -55,3 +55,4 @@ install(FILES dist/htdocs/css/bootstrap.min.css DESTINATION share/${PROJECT_NAME
install(FILES dist/htdocs/css/mympd.min.css DESTINATION share/${PROJECT_NAME}/htdocs/css/)
install(DIRECTORY htdocs/assets DESTINATION share/${PROJECT_NAME}/htdocs)
install(DIRECTORY DESTINATION ../var/lib/${PROJECT_NAME}/pics)
install(DIRECTORY DESTINATION ../var/lib/${PROJECT_NAME}/tmp)

View File

@ -28,6 +28,7 @@ This fork provides a reworked ui based on Bootstrap 4, a modernized backend and
- Play statistics and song voting (uses mpd stickers)
- Embedded Webserver (mongoose)
- Jukebox mode (add's random songs from database or playlists to queue)
- Smart playlists (most played and best rated songs)
myMPD is work in progress. Bugreportes and feature requests are very welcome.
- https://github.com/jcorporation/myMPD/issues

View File

@ -11,11 +11,8 @@ post_upgrade() {
[ "$?" = "2" ] && useradd --system -d /var/lib/mympd -s /usr/sbin/nologin -g mympd mympd
# fix ownership of /var/lib/mympd
if ! [ $(stat -c '%U:%G' /var/lib/mympd/) = 'mympd:mympd' ]
then
echo "INFO: Fixing ownership of /var/lib/mympd"
chown -R mympd.mympd /var/lib/mympd
fi
echo "INFO: Fixing ownership of /var/lib/mympd"
chown -R mympd.mympd /var/lib/mympd
# link music directory to mympd if not already exising
echo "INFO: Trying to link musicdir to library"

View File

@ -44,11 +44,8 @@ getent group mympd > /dev/null
getent passwd mympd > /dev/null
[ "$?" = "2" ] && useradd -r mympd -g mympd -d /var/lib/mympd -s /usr/sbin/nologin
if ! [ $(stat -c '%U:%G' /var/lib/mympd/) = 'mympd:mympd' ]
then
echo "Fixing ownership of /var/lib/mympd"
chown -R mympd.mympd /var/lib/mympd
fi
echo "Fixing ownership of /var/lib/mympd"
chown -R mympd.mympd /var/lib/mympd
if [ -d /etc/systemd ]
then

View File

@ -35,3 +35,6 @@ stickers = true
#List of tags in myMPD gui
#Supported tags: Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer
taglist = Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer
#Enable smart playlists
smartplaylists = true

7
debian/postinst vendored
View File

@ -6,11 +6,8 @@ getent group mympd > /dev/null
getent passwd mympd > /dev/null
[ "$?" = "2" ] && useradd -r mympd -g mympd -d /var/lib/mympd -s /usr/sbin/nologin
if ! [ $(stat -c '%U:%G' /var/lib/mympd/) = 'mympd:mympd' ]
then
echo "Fixing ownership of /var/lib/mympd"
chown -R mympd.mympd /var/lib/mympd
fi
echo "Fixing ownership of /var/lib/mympd"
chown -R mympd.mympd /var/lib/mympd
echo "Trying to link musicdir to library"
if [ -f /etc/mpd.conf ]

View File

@ -24,10 +24,11 @@
</a>
<div class="dropdown-menu bg-dark">
<a class="dropdown-item text-light bg-dark" href="#" data-href='{"cmd": "showAddToPlaylist", "options": ["stream"]}'>Add Stream</a>
<a id="navDBupdate" class="dropdown-item text-light bg-dark" data-toggle="collapse" href="#menu-dbupdate"><span class="material-icons material-icons-left">keyboard_arrow_right</span>Database</a>
<a id="navDBupdate" class="dropdown-item text-light bg-dark" data-toggle="collapse" href="#menu-dbupdate"><span class="material-icons material-icons-left">keyboard_arrow_right</span>Update</a>
<div class="collapse" id="menu-dbupdate">
<a class="dropdown-item text-light bg-dark" href="#" data-href='{"cmd": "updateDB", "options": []}'>Update</a>
<a class="dropdown-item text-light bg-dark" href="#" data-href='{"cmd": "rescanDB", "options": []}'>Rescan</a>
<a class="dropdown-item text-light bg-dark" href="#" data-href='{"cmd": "updateDB", "options": []}'>Update Database</a>
<a class="dropdown-item text-light bg-dark" href="#" data-href='{"cmd": "rescanDB", "options": []}'>Rescan Database</a>
<a class="dropdown-item text-light bg-dark" href="#" data-href='{"cmd": "updateSmartPlaylists", "options": []}'>Update Smart Playlists</a>
</div>
<a class="dropdown-item text-light bg-dark" href="#" data-href='{"cmd": "openLocalPlayer", "options": []}'>Local Player</a>
<a class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#modalSettings">Settings</a>

View File

@ -1542,6 +1542,10 @@ function getAllPlaylists(obj) {
}
}
function updateSmartPlaylists() {
sendAPI({"cmd": "MPD_API_SMARTPLS_UPDATE"});
}
function voteSong(vote) {
var uri = domCache.currentTrack.getAttribute('data-uri');
if (uri == '')

View File

@ -183,7 +183,14 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
uint_rc = mpd_run_rescan(mpd.conn, NULL);
if (uint_rc > 0)
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}");
break;
break;
case MPD_API_SMARTPLS_UPDATE:
uint_rc = mympd_smartpls_update_all();
if (uint_rc == 0)
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Smart Playlists updated\"}");
else
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Smart Playlists update failed\"}");
break;
case MPD_API_PLAYER_PAUSE:
mpd_run_toggle_pause(mpd.conn);
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}");
@ -549,6 +556,7 @@ void mympd_parse_idle(struct mg_mgr *s, int idle_bitmask) {
switch(idle_event) {
case MPD_IDLE_DATABASE:
len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_database\"}");
mympd_smartpls_update_all();
break;
case MPD_IDLE_STORED_PLAYLIST:
len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_stored_playlist\"}");
@ -628,6 +636,10 @@ void mympd_mpd_features() {
printf("MPD don't support stickers, disabling myMPD feature\n");
config.stickers = false;
}
if (config.stickers == false && config.smartplaylists == true) {
printf("Stickers are disabled, disabling smartplaylists\n");
config.smartplaylists = false;
}
printf("MPD supported tags: ");
mpd_send_list_tag_types(mpd.conn);
@ -736,6 +748,7 @@ void mympd_idle(struct mg_mgr *s, int timeout) {
mpd_connection_set_timeout(mpd.conn, mpd.timeout);
mpd.conn_state = MPD_CONNECTED;
mympd_mpd_features();
mympd_smartpls_update_all();
if (mympd_state.jukeboxMode == true)
mympd_jukebox();
mpd_send_idle(mpd.conn);
@ -1805,7 +1818,7 @@ int mympd_search_queue(char *buffer, char *mpdtagtype, unsigned int offset, char
else {
len = json_printf(&out, "{type: queuesearch, data: [");
while((song = mpd_recv_song(mpd.conn)) != NULL) {
while ((song = mpd_recv_song(mpd.conn)) != NULL) {
entity_count ++;
if (entity_count > offset && entity_count <= offset + MAX_ELEMENTS_PER_PAGE) {
if (entities_returned ++)
@ -1868,3 +1881,102 @@ void mympd_disconnect() {
mpd.conn_state = MPD_DISCONNECT;
mympd_idle(NULL, 0);
}
int mympd_smartpls_update_all() {
if (!config.smartplaylists)
return 0;
if (mympd_smartpls_update("like", "myMPDsmart-bestRated") != 0)
return 1;
if (mympd_smartpls_update("playCount", "myMPDsmart-mostPlayed") != 0)
return 1;
return 0;
}
int mympd_smartpls_update(char *sticker, char *playlist) {
struct mpd_pair *pair;
char *uri = NULL;
char *name;
char *p_value;
char *crap;
long value;
long value_max = 0;
size_t len = 0;
ssize_t read;
unsigned i = 0;
struct mpd_playlist *pl;
const char *plpath;
bool exists = false;
FILE *fp = fopen("/var/lib/mympd/tmp/playlist.tmp", "w");
if (fp == NULL) {
printf("Error opening /var/lib/mympd/tmp/playlist.tmp");
return 1;
}
if (!mpd_send_sticker_find(mpd.conn, "song", "", sticker)) {
LOG_ERROR_AND_RECOVER("mpd_run_rm");
return 1;
}
while ((pair = mpd_recv_pair(mpd.conn)) != NULL) {
if (strcmp(pair->name, "file") == 0) {
uri = strdup(pair->value);
}
else if (strcmp(pair->name, "sticker") == 0) {
name = strtok(strdup(pair->value), "=");
p_value = strtok(NULL, "=");
value = strtol(p_value, &crap, 10);
if (value > 1)
fprintf(fp, "%s::%ld\n", uri, value);
if (value > value_max)
value_max = value;
}
mpd_return_pair(mpd.conn, pair);
}
mpd_response_finish(mpd.conn);
fclose(fp);
if (!mpd_send_list_playlists(mpd.conn)) {
LOG_ERROR_AND_RECOVER("mpd_run_rm");
return 1;
}
while((pl = mpd_recv_playlist(mpd.conn)) != NULL) {
plpath = mpd_playlist_get_path(pl);
if (strcmp(playlist, plpath) == 0)
exists = true;
mpd_playlist_free(pl);
}
if (exists)
if (!mpd_run_rm(mpd.conn, playlist)) {
LOG_ERROR_AND_RECOVER("mpd_run_rm");
return 1;
}
if (value_max > 2)
value_max = value_max / 2;
fp = fopen("/var/lib/mympd/tmp/playlist.tmp", "r");
if (fp == NULL) {
printf("Error opening /var/lib/mympd/tmp/playlist.tmp");
return 1;
}
while ((read = getline(&uri, &len, fp)) != -1) {
name = strtok(uri, "::");
p_value = strtok(NULL, "::");
value = strtol(p_value, &crap, 10);
if (strcmp(sticker, "playCount") == 0) {
if (value <= value_max)
continue;
}
if (!mpd_run_playlist_add(mpd.conn, playlist, name)) {
LOG_ERROR_AND_RECOVER("mpd_run_rm");
fclose(fp);
free(uri);
return 1;
}
i++;
}
fclose(fp);
free(uri);
unlink("/var/lib/mympd/tmp/playlist.tmp");
printf("Updated %s with %u songs, minValue: %ld\n", playlist, i, value_max);
return 0;
}

View File

@ -72,6 +72,7 @@
X(MPD_API_PLAYLIST_RM_TRACK) \
X(MPD_API_PLAYLIST_LIST) \
X(MPD_API_PLAYLIST_CONTENT_LIST) \
X(MPD_API_SMARTPLS_UPDATE) \
X(MPD_API_DATABASE_SEARCH) \
X(MPD_API_DATABASE_UPDATE) \
X(MPD_API_DATABASE_RESCAN) \
@ -161,6 +162,7 @@ typedef struct {
bool stickers;
bool mixramp;
const char* taglist;
bool smartplaylists;
} t_config;
t_config config;
@ -196,6 +198,8 @@ void mympd_last_played_song_uri(const char *uri);
void mympd_last_played_song_id(int song_id);
void mympd_get_sticker(const char *uri, t_sticker *sticker);
void mympd_jukebox();
int mympd_smartpls_update_all();
int mympd_smartpls_update(char *sticker, char *playlist);
int mympd_get_updatedb_state(char *buffer);
int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, int *last_song_id, unsigned *queue_version, unsigned *queue_length);
int mympd_put_outputs(char *buffer);

View File

@ -162,6 +162,11 @@ static int inihandler(void* user, const char* section, const char* name, const c
p_config->stickers = true;
else
p_config->stickers = false;
else if (MATCH("smartplaylists"))
if (strcmp(value, "true") == 0)
p_config->smartplaylists = true;
else
p_config->smartplaylists = false;
else if (MATCH("mixramp"))
if (strcmp(value, "true") == 0)
p_config->mixramp = true;
@ -198,6 +203,7 @@ int main(int argc, char **argv) {
config.stickers = true;
config.mixramp = true;
config.taglist = "Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer";
config.smartplaylists = true;
mpd.timeout = 3000;
mpd.last_update_sticker_song_id = -1;