[patch] Song ratings v2



I've developed Adrian's patch a little further to allow modification of the ratings:

The branch is based on 2.6-alpha3.

This works by creating plain text files in any directory that has rated music files.


  • Works for any file type and on all file systems
  • Ratings belong to users, not to files. The ratings file name is an option (default: "ratings"), so you can do "ratings_alice", "ratings_bob", etc for shared music libraries
  • Ratings are very easy to backup and very hard to lose
  • Reorganizing folders is no problem
  • Renaming files breaks the ratings, but seeing the ratings file should hint at that and you can still match them manually (or with some scripting) after that.
  • Changing ratings does not change large binary files (which using tags would do) and slow down backups
  • It's one file per directory, so there's not much clutter (and it's a bit like cover.jpg)
  • Simple, fast, unixy and you can do all kinds of scripting with this (finding all 5-star songs for a playlist and such)

Tried to buid it and I get segmentation fault at start. I started MOC with --no-config. Here's the backtrace

#0 0x00007ffff61643cc in ?? () from /lib64/libc.so.6 #1 0x0000000000439130 in menu_item_set_rating (mi=0x7578c0, rating=0x0) at menu.c:651 #2 0x000000000042e557 in update_menu_item (mi=0x7578c0, plist=0x7dd100, n=0, full_path=0) at interface_elements.c:1419 #3 0x000000000042e7ac in side_menu_update_item (m=0x683068 <main_win+40>, plist=0x7dd100, n=0) at interface_elements.c:1460 #4 0x0000000000430530 in main_win_update_item (w=0x683040 <main_win>, iface_menu=IFACE_MENU_DIR, plist=0x7dd100, n=0) at interface_elements.c:2016 #5 0x0000000000435eec in iface_update_item (menu=IFACE_MENU_DIR, plist=0x7dd100, n=0) at interface_elements.c:3890 #6 0x00000000004226e2 in ev_file_tags (data=0x7582e0) at interface.c:684 #7 0x00000000004238dd in server_event (event=17, data=0x7582e0) at interface.c:1180 #8 0x00000000004287a4 in get_and_handle_event () at interface.c:3525 #9 0x0000000000428deb in interface_loop () at interface.c:3691 #10 0x0000000000415117 in start_moc (params=0x6809e0 <params>, args=0x7234f0) at main.c:227 #11 0x0000000000417723 in main (argc=3, argv=0x7fffffffd7b8) at main.c:1270

Same thing happens with -D -no-config -O 'RatingShow=no'.

Oops, I did some initialization in options_parse(...) (I thought that would always get called). Fix is in git. Sorry that it's mixed in with my other changes now.

And since we're in Contrib anyway, here's a script to find files by rating:

#!/bin/perl use strict; use warnings; use File::Spec; use File::Find; use Cwd; my $RATINGS_FILE = "ratings"; sub usage() { my ($vol,$path,$name) = File::Spec->splitpath($0); print "Usage: $name <n>\n"; print " $name <min> <max>\n"; print "\n"; print "Finds all files below the cwd that are rated\n"; print "exactly n stars or between min and max (both\n"; print "inclusive) stars.\n"; exit 0; } my ($min, $max); if (@ARGV == 2) { $min = $ARGV[0]; $max = $ARGV[1]; usage if $min!~/^\d+$/ or $max!~/^\d+$/; exit 0 if $min > $max; } elsif (@ARGV == 1) { $min = $max = $ARGV[0]; usage if $min!~/^\d+$/; } else { usage; } sub handler { return if $_ ne $RATINGS_FILE or !-f $_; open(my $rf, "<", $File::Find::name) or return; while(<$rf>) { next unless /^([0-5]) (.+)$/; next unless $1 >= $min and $1 <= $max; print $File::Find::dir, "/", $2, "\n"; } close $rf; } find(\&handler, cwd());

Ok, thanks. Now it works. However first start was for some reason very long (I believed the app hung (at "Loading Playlist"). I don't know what was the reason and I can't reproduce it now.

As for the script, you could add it to tools directory in your repo. An idea: you could also expand it, so it could be called from within MOC via ExecCommand and feed its output back to MOC playlist.

It probably updated the tags cache on the first start. BTW: I've not looked into that at all (using moc with and without ratings in parallel and what that does to the tags cache).

Tags were my guess as well, but it was not that. I removed tags cache when investigation the previous segfault. Moreover since tags db version was bumped in the patch, MOC just discards older/newer tags cache without any problem.

Anyway, I'll try to cherry pick some of your changes and commit them also to my fork of MOC: https://github.com/tomaszg7/mocp

I tried modifying this script a bit to work better with ExecCommand but it turns out that since MOC client is single-threaded it doesn't work as I expected. Thus I just created a "helper" script:

cd "`dirname "$2"`" ~/moc-find-by-rating.pl $1 5 > /tmp/pl.m3u mocp -cap /tmp/pl.m3u&

which I trigger via

ExecCommand4 = "/home/user/moc-play-rating.sh 4 %f" ExecCommand5 = "/home/user/moc-play-rating.sh 5 %f"

It would be better if MOC would have a %letter to give current directory in the interface (see https://github.com/tomaszg7/mocp/commit/c93fb042fac518bd040e12dcaf99549a54c0b6e8 in my fork), but since it doesn't I had to work around it.