You are not logged in.
Is there a straightforward way to rate songs in ncmpcpp? It wouldn't matter if the ratings were stored in a custom tag or database.
The only (not so straightforward) way that came to my mind was to edit the comment tag which I think ncmpcpp could search afterwards. Though doing this manually would be pretty straightbackward...
Last edited by Markus00000 (2011-04-02 06:07:49)
Offline
#!/bin/bash
### MPD Ratings ################
# Version 0.1 by Scott Garrett #
# Wintervenom [(at)] gmail.com #
################################
# Dependencies:
# - mpc
#
# Be sure to change these to reflect your setup.
library="$HOME/Music/Library"
playlists="$HOME/Music/Playlists"
song=$(mpc current -f '%file%')
pl_prefix='rated-'
pl_suffix='.m3u'
if [[ -z "$song" ]]; then
echo 'No song is playing.'
exit 1
elif [[ "$1" -lt 1 || "$1" -gt 5 ]]; then
echo 'Rating must be between 1 and 5.'
exit 1
fi
# Remove the song from other rating playlists if found.
for n in {1..5}; do
f="$playlists/${pl_prefix}$n${pl_suffix}"
if [[ -f "$f" ]]; then
grep -vF "/$song" "$f" > "/tmp/new.m3u"
sort -u "/tmp/new.m3u" -o "$f"
# Remove rating playlist if empty.
# It takes more than three bytes to store a path.
[[ $(wc -c < "$f") -lt 4 ]] &&
rm "$f"
fi
done
# Append the song to the new rating playlist.
f="$playlists/${pl_prefix}$1${pl_suffix}"
mkdir -p "$playlists"
echo "$library/$song" >> "$f"
sort -u "$f" -o "$f"
[[ -f "/tmp/new.m3u" ]] && rm "/tmp/new.m3u"
Last edited by Wintervenom (2011-04-02 01:14:07)
Offline
Thanks so much. This seems to be an excellent solution!
Offline
I changed your script slightly to work with ncmpcpp. I also added the possibility to remove a song from all rating lists. Here it goes:
#!/bin/bash
#
# Modified version for ncmpcpp. Based on:
#
### MPD Ratings ################
# Version 0.1 by Scott Garrett #
# Wintervenom [(at)] gmail.com #
################################
# Dependencies:
# - ncmpcpp
#
# Usage: Save the script to a file, e.g. "ratesong", make it executable.
# Invoke the script with "ratesong [rating]", where rating is a number between 0 and 5.
# 0 will remove the current song from any rating playlist.
# 1-5 will add the current song to the appropriate rating playlist and remove it from all others.
## Be sure to change these to reflect your setup.
library="" # with trailing slash; leave empty for using paths relative to your mpd library
playlists="$HOME/.mpd/playlists"
song=`ncmpcpp --now-playing '%D/%f'`
song="$library$song"
## Prefix and suffix strings for the playlist file name.
pl_prefix=''
pl_suffix='.m3u'
## Error cases.
if [[ -z "$song" || "$song" == 'Cannot connect to mpd: Connection refused' ]]; then
echo 'No song is playing.'
exit 1
elif [[ "$1" -lt 0 || "$1" -gt 5 ]]; then
echo "Rating must be between 1 and 5. Or zero to delete the current song's rating."
exit 1
fi
## Allow only one instance by creating a lock file.
if [[ -f "$playlists/lock" ]]; then
zenity --info --text="Rating failed!\n\nAnother instance is running." &
exit 1
fi
touch "$playlists/lock"
## Remove the song from other rating playlists if found.
for n in {1..5}; do
f="$playlists/${pl_prefix}$n${pl_suffix}"
tmp="$playlists/tmp.m3u"
if [[ -f "$f" ]]; then
cp "$f" "$tmp"
grep -vF "$song" "$tmp" > "$f"
rm "$tmp"
## Don't do this, it seems to empty rating playlists occasionally:
#grep -vF "$song" "$f" > "$tmp"
#mv "$tmp" "$f"
fi
done
## Append the song to the new rating playlist.
if [[ $1 -ne 0 ]]; then
f="$playlists/${pl_prefix}$1${pl_suffix}"
mkdir -p "$playlists"
echo "$song" >> "$f"
sort -u "$f" -o "$f"
fi
rm "$playlists/lock"
Thanks again!
Edit: Added possibility for relative paths in playlists. Also there is no entry added to a playlist if mpd is not running.
Last edited by Markus00000 (2011-06-12 17:34:20)
Offline
I updated the script again. I was invoking it via keyboard shortcuts and noticed that playlists could be deleted or mixed up with duplicates when two instances ran at the same time. The script now uses a lock file to allow only one instance.
I also removed "sort" after deleting the rated song from each playlist. Deleting a song seemed not to mess up the sorted playlist. Should be fine as playlists are still sorted after adding a new song.
Last edited by Markus00000 (2011-04-21 21:02:43)
Offline
Still my playlists ended up being empty sometimes and I think I know why:
grep -vF "$song" "$f" > "$f"
Reading and writing from/into the same file seemed to be the cause. When I use a temporary file, my playlists won't be emptied:
grep -vF "$song" "$f" > "$tmp"
mv "$tmp" "$f"
I updated the script (again).
Offline
Markus00000
A couple of months ago I was trying to do what your first post mentioned in ncmpcpp but had some problems. I added a number into the comment song tag which seemed to work, but for some reason ncmpcpp would not search by criteria in the comments field. Anyway after a while I gave up.
Can you post the latest script? I am not to familiar with bash scripts so I have a few questions which hopefully do not seem silly.
1. Does the script actually write the value of 0, 1, 2, 3, 4, or 5 to the comments tag on the song?
2. I am using flac music files; would the script have a problem with this?
Anyway, I don't want to ask to much since I should play around with the script to get a better idea of what is happening. A very brief (just a couple points or sentences) summary on how the script works and what it does would be helpful if you don't mind.
Thanx
Offline
It toggles the currently-playing song from numbered rating playlists.
Offline
1. Does the script actually write the value of 0, 1, 2, 3, 4, or 5 to the comments tag on the song?
No, it does not. It manages five .m3u playlists in the specified playlists folder. These are simple text files listing the paths to all files in the playlist. The playlists will show up in ncmpcpp so there is no need to search for certain comment tags. (Comment tags are not altered by the script.)
2. I am using flac music files; would the script have a problem with this?
I have no flac files but as the playlists simply list paths to files, their file extensions should not matter at all.
I added some more comments to the script (see above). Hopefully this makes it easier to understand for you.
If you have further questions, feel free to ask.
Last edited by Markus00000 (2011-05-13 22:09:15)
Offline
Markus00000:
The details you posted and comments added into the script are just what I needed to get started. I will try this out. I think it solves a problem with mpd/mpd clients that I have in that I could not rate songs since I have quite a large library. I am using a small computer (alix) embedded with voyage linux running mpd to supply my DAC and pulling song off my server running Arch so I don't want to use Amarok or anything. I like mpd better anyway. I will play with this for a while and let you know if I get stuck on something.
Thanks again.
Offline
*deleted*
Last edited by Markus00000 (2011-05-13 22:20:15)
Offline
Sorry for my editing mess. I noticed two problems and therefore updated my original script incorporating all changes and comments. To avoid confusion, I removed the second version of the script.
The relevant problem was that sometimes a rating playlist was overwritten with an empty file (backup!). I don't understand why, but after switching to a seemingly equivalent implementation it seems to work. The problematic code is:
## Don't do the following, it seems to empty rating playlists occasionally.
## Anyone knows why?
#grep -vF "$song" "$f" > "$tmp"
#mv "$tmp" "$f"
Last edited by Markus00000 (2011-11-10 18:44:34)
Offline
Ending up with empty files was caused by a race condition. It can happen when locking with "touch" as I did. More than one instance can bypass the check whether the lock file exists. Then both touch it and run simultaneously. I am not exactly sure how I got into a race condition with such a short script. Maybe accidentally hitting two rating shortcuts at once. Maybe the execution was slow sometimes while disk I/O was high. Either way playlists could end up emptied.
Here are some correct examples about how to lock files without race conditions.
And for the record, the current, race-free version of the script follows. Note that this version is for cmus. Exchanging a line or two from the ncmpcpp version should be easy:
#!/bin/bash
## Usage: rate-music [0-5]
## Path to playlists
playlists="$HOME/music"
## Prefix and suffix strings for the playlist file name
pl_prefix=''
pl_suffix='.m3u'
## Get current song from cmus
song=`cmus-remote -Q | grep file`
## Error cases
if [[ -z "$song" ]]; then
echo 'No song is playing.'
exit 1
elif [[ "$1" -lt 0 || "$1" -gt 5 ]]; then
echo "Rating must be between 1 and 5. Or zero to delete the current song's rating."
exit 1
fi
## Path to lock file
lock="/tmp/rate-music.lock"
## Lock the file
exec 9>"$lock"
if ! flock -n 9; then
notify-send "Rating failed: Another instance is running."
exit 1
fi
## Strip "file " from the output
song=${song/file \///}
## Temporary file for grepping and sorting
tmp="$playlists/tmp.m3u"
## Remove the song from all rating playlists
for n in {1..5}; do
f="$playlists/${pl_prefix}$n${pl_suffix}"
if [[ -f "$f" ]]; then
grep -vF "$song" "$f" > "$tmp"
mv -f $tmp $f
fi
done
## Append the song to the new rating playlist
if [[ $1 -ne 0 ]]; then
f="$playlists/${pl_prefix}$1${pl_suffix}"
mkdir -p "$playlists"
echo "$song" >> "$f"
sort -u "$f" -o "$tmp"
mv -f $tmp $f
fi
## The lock file will be unlocked when the script ends
Any feedback and suggestions welcome!
Last edited by Markus00000 (2011-11-10 19:16:25)
Offline
Thank yoiu for your script, Markus.
I'm using your last script (the one for cmus) with ncmcpp. I'm fetching the song with the:
song=`ncmpcpp --now--playing '%D/%f'`
The problem is that I get the error:
song_list_format: invalid character at position 18: '}'
I made some searching but I can't find where or why is this character inserted. Could you help me?
Thanks!
Offline
I am not sure. Where in the script does the error occur? Maybe some variable must be put in quotes.
You might have better chances by starting a new thread.
Offline
Can't we actually add the rating into a the song's metadata?
Offline
Most certainly. There are many programs to modify music metadata. Though I don't like the rating in there.
Offline
Nice thread, I directly copied your script and amended it to work with ncmpcpp and cmus (N.B I didn't try the latter as I don't use it, but it should be straightforward) and added a couple of descriptive lines. I actually was looking to rate playlists, mostly because I use these for radiostations which are of varying quality, but haven't gotten around to consider it further.
Did I say thanks?
#!/bin/bash
## Usage: rate-music [0-5]
#
# Adds current playing song to the mpd playlist corresponding to the
# rating assigned. Any previous rating is removed. If 0 is given, the
# songs rating will be removed.
#
# From: https://bbs.archlinux.org/viewtopic.php?id=116113
## USER CONFIGURATION-----------------------------------------------------
## Path to playlists
playlists="$HOME/.mpd/playlists"
## END USER CONFIGURATION--------------------------------------------------
## Prefix and suffix strings for the playlist file name
pl_prefix=''
pl_suffix='.m3u'
## Get current song from ncmpcpp or cmus or throw an error
song=`ncmpcpp --now-playing '%D/%f' 2>/dev/null` || \
song=`cmus-remote -Q 2>/dev/null | grep file` || \
{ echo "Error: you need either ncmpcpp or cmus installed to run this script. Aborting." >&2; exit 1; }
## Error cases
if [[ -z "$song" ]]; then
echo 'No song is playing.'
exit 1
elif [[ "$1" -lt 0 || "$1" -gt 5 ]]; then
echo "Rating must be between 1 and 5. Or zero to delete the current song's rating."
exit 1
fi
## Path to lock file
lock="/tmp/rate-music.lock"
## Lock the file
exec 9>"$lock"
if ! flock -n 9; then
notify-send "Rating failed: Another instance is running."
exit 1
fi
## Strip "file " from the output
song=${song/file \///}
## Temporary file for grepping and sorting
tmp="$playlists/tmp.m3u"
## Remove the song from all rating playlists
for n in {1..5}; do
f="$playlists/${pl_prefix}$n${pl_suffix}"
if [[ -f "$f" ]]; then
grep -vF "$song" "$f" > "$tmp"
mv -f $tmp $f
fi
done
## Append the song to the new rating playlist
if [[ $1 -ne 0 ]]; then
f="$playlists/${pl_prefix}$1${pl_suffix}"
mkdir -p "$playlists"
echo "$song" >> "$f"
sort -u "$f" -o "$tmp"
mv -f $tmp $f
fi
## The lock file will be unlocked when the script ends
Offline
Most certainly. There are many programs to modify music metadata. Though I don't like the rating in there.
How come? There is a tag, POPM (popularimeter) in the id3v2 specification: http://id3.org/id3v2.3.0. Why not use that? If you only want 5 levels i assume you would just use 0 = 0, 1 = 51, 2 = 102, 3 = 153, 4 = 204, 5 = 255... Would really like to see full implementation of ratings in MPD. It's the only thing i still miss from classic media players...
Last edited by iOfWhy (2012-12-19 16:53:58)
Offline
Changing the metadata changes the file, therefore rsync would back it up again.
Syncing often works with playlists. Not sure how often it works based on metadata. I can also use rsync to sync all songs of a certain rating by feeding the playlist straight into it.
Well, these are my reasons and they might be wrong and/or outdated. :-)
Offline
Rsync is so freaking fast thats not a problem for me i guess... eitherway i want updated files to be resynced. But hey different tasks call for different conventions. To quote stanford algorithm expert Donald Knuth, "Who are you and what are you doing in my house?" http://xkcd.com/163/
Great script by the way... easy to add a line so it updates the metadata as well. Thanks a bunch!
Offline
Is there a keyboard shortcut assigned to the ratings which you press when on an instance of ncmpcpp and the selected file gets rated? Or is that you have to fire up a terminal and issue the command "ratesong 1/2/3/4/5"?
Sorry for the noobish question.
Offline
Is there a keyboard shortcut assigned to the ratings which you press when on an instance of ncmpcpp and the selected file gets rated? Or is that you have to fire up a terminal and issue the command "ratesong 1/2/3/4/5"?
I have keyboard shortcuts defined in my window manager (xmonad, mod4 + F1-F6, where F6 removes the rating). The shortcuts were the reason why I had to take care of parallel execution: Accidentally pressing something like mod4+F1+F2 would sometimes empty a playlist.
Offline
Markus, it would be great if you could put the instructions for noobs, like where do you put the script file and what command to assign for the keyboard shortcuts.
Sorry, if it sounds like asking too much
Also, would like to bring your attention towards this thread about starting mpd and ncmpcpp together - https://bbs.archlinux.org/viewtopic.php?id=155471
Last edited by ravisghosh (2013-01-02 21:05:21)
Offline
It depends on your window manager or desktop environment how defining keyboard shortcuts works. There could be a GUI for this or just a configuration text file. What WM/DE are you using?
If you find where to define shortcuts, it should be possible to assign a command. The commands would then be "music-rate 1", "music-rate 2" etc. If that doesn't work, it's likely that the music-rate script is not in your path. If so, read this: https://wiki.archlinux.org/index.php/En … es_Locally
I'm currently using the script with cmus to which I switched from mpd.
Offline