예제 #1
0
static void
currently_playing_update_info (currently_playing_t *entry, xmmsv_t *value)
{
	const gchar *noinfo_fields[] = { "playback_status", "playtime", "position"};
	const gchar *time_fields[] = { "duration"};
	xmmsv_t *info;
	gint i;

	info = xmmsv_propdict_to_dict (value, NULL);

	enrich_mediainfo (info);

	/* copy over fields that are not from metadata */
	for (i = 0; i < G_N_ELEMENTS (noinfo_fields); i++) {
		xmmsv_t *copy;
		if (xmmsv_dict_get (entry->data, noinfo_fields[i], &copy)) {
			xmmsv_dict_set (info, noinfo_fields[i], copy);
		}
	}

	/* pretty format time fields */
	for (i = 0; i < G_N_ELEMENTS (time_fields); i++) {
		gint32 tim;
		if (xmmsv_dict_entry_get_int (info, time_fields[i], &tim)) {
			gchar *p = format_time (tim, FALSE);
			xmmsv_dict_set_string (info, time_fields[i], p);
			g_free (p);
		}
	}

	xmmsv_unref (entry->data);
	entry->data = info;
}
예제 #2
0
static void
cli_list_print_row (column_display_t *coldisp, xmmsv_t *propdict)
{
	xmmsv_t *info = xmmsv_propdict_to_dict (propdict, NULL);
	enrich_mediainfo (info);
	column_display_print (coldisp, info);
}
예제 #3
0
static gboolean
ol_player_xmms2_get_music_length (int *len)
{
  /* ol_log_func (); */
  ol_assert_ret (len != NULL, FALSE);
  if (!ol_player_xmms2_ensure_connection ())
    return FALSE;
  *len = 0;
  int32_t id = ol_player_xmms2_get_currend_id ();
  if (id > 0)
  {
    xmmsc_result_t *result = xmmsc_medialib_get_info (connection, id);
    xmmsc_result_wait (result);
    xmmsv_t *return_value = xmmsc_result_get_value (result);
    if (xmmsv_is_error (return_value))
    {
      ol_error ("Get music info from XMMS2 failed.");
    }
    else
    {
      xmmsv_t *dict = xmmsv_propdict_to_dict (return_value, NULL);
      *len = ol_player_xmms2_get_dict_int (return_value, "duration");
      xmmsv_unref (dict);
    }
    xmmsc_result_unref (result);
  }
  return TRUE;
}
예제 #4
0
/*
 * call-seq:
 *  rawdict.to_propdict( src_prefs ) -> propdict
 *
 * Transforms a RawDict (key-source-value) to a regular
 * key-value dict.
 * The optional src_prefs argument restricts which sources
 * are considered. The value may be a string or an array
 * of strings, which may contain wildcards.
 * Example: rawdict.to_propdict( ['server','plugin/*'] )
 */
static VALUE
c_raw_dict_to_propdict (int argc, VALUE *argv, VALUE self)
{
	VALUE value, sources = Qnil;
	RbDict *dict = NULL, *dict2 = NULL;
	xmmsv_t *inner_dict;
	const char **csources = NULL;

	Data_Get_Struct (self, RbDict, dict);

	rb_scan_args (argc, argv, "01", &sources);

	if (!NIL_P (sources))
		csources = parse_string_array (sources);
	inner_dict = xmmsv_propdict_to_dict (dict->real, csources);
	if (csources)
		free (csources);

	value = Data_Make_Struct (cDict, RbDict,
	                          c_dict_mark, c_dict_free,
	                          dict2);

	// don't add a second reference here
	dict2->real = inner_dict;
	dict2->parent = dict->parent;

	rb_obj_call_init (value, 0, NULL);

	return value;
}
예제 #5
0
파일: dict.cpp 프로젝트: chrippa/xmms2
void PropDict::setSource( const std::list< std::string >& src )
{
    std::vector< const char* > prefs;
    fillCharArray( src, prefs );

    xmmsv_t *flat = xmmsv_propdict_to_dict( propdict_, &prefs[0] );
    setValue( flat );
    // setValue refs flat, unref here to get back to refcount of 1
    xmmsv_unref ( flat );
}
예제 #6
0
파일: dict.cpp 프로젝트: chrippa/xmms2
PropDict::PropDict( xmmsv_t* val ) : Dict( val ), propdict_( val )
{
    xmmsv_ref( propdict_ );

    // Immediately replace with a "flat" dict (default sources)
    xmmsv_t *flat = xmmsv_propdict_to_dict( propdict_, NULL );
    setValue( flat );
    // setValue refs flat, unref here to get back to refcount of 1
    xmmsv_unref ( flat );
}
예제 #7
0
static void
id_coldisp_print_info (cli_infos_t *infos, column_display_t *coldisp, guint id)
{
	xmmsc_result_t *infores;
	xmmsv_t *info;

	infores = xmmsc_medialib_get_info (infos->sync, id);
	xmmsc_result_wait (infores);
	info = xmmsv_propdict_to_dict (xmmsc_result_get_value (infores), NULL);
	column_display_print (coldisp, info);

	xmmsc_result_unref (infores);
	xmmsv_unref (info);
}
예제 #8
0
static gboolean
ol_player_xmms2_get_music_info (OlMusicInfo *info)
{
  /* ol_log_func (); */
  ol_assert_ret (info != NULL, FALSE);
  if (!ol_player_xmms2_ensure_connection ())
    return FALSE;
  ol_music_info_clear (info);
  int32_t id = ol_player_xmms2_get_currend_id ();
  if (id > 0)
  {
    xmmsc_result_t *result = xmmsc_medialib_get_info (connection, id);
    xmmsc_result_wait (result);
    xmmsv_t *return_value = xmmsc_result_get_value (result);
    if (xmmsv_is_error (return_value))
    {
      ol_error ("Get music info from XMMS2 failed.");
    }
    else
    {
      xmmsv_t *dict = xmmsv_propdict_to_dict (return_value, NULL);
      info->title = ol_player_xmms2_get_dict_string (dict, "title");
      info->artist = ol_player_xmms2_get_dict_string (dict, "artist");
      info->album = ol_player_xmms2_get_dict_string (dict, "album");
      info->track_number = ol_player_xmms2_get_dict_int (dict, "tracknr");
      info->uri = ol_player_xmms2_get_dict_string (dict, "url");
      ol_logf (OL_DEBUG,
               "%s\n"
               "  title:%s\n"
               "  artist:%s\n"
               "  album:%s\n"
               "  uri:%s\n",
               __FUNCTION__,
               info->title,
               info->artist,
               info->album,
               info->uri);
      xmmsv_unref (dict);
    }
    xmmsc_result_unref (result);
  }
  return TRUE;
}
예제 #9
0
static int
handle_mediainfo (xmmsv_t *v, void *userdata)
{
	static const gchar *props[] = {"chain", NULL};
	static const gchar *pref[] = {"server", NULL};
	GString *str;
	const gchar *tstr;
	gint tint, i;
	xmmsv_t *dict;

	str = g_string_new ("");

	/* convert propdict to dict */
	dict = xmmsv_propdict_to_dict (v, pref);

	for (i = 0; props[i]; i++) {
		switch (xmmsv_dict_entry_get_type (dict, props[i])) {
		case XMMSV_TYPE_STRING:
			if (xmmsv_dict_entry_get_string (dict, props[i], &tstr)) {
				g_string_append_printf (str, "%s=%s\n", props[i], tstr);
			}
			break;
		case XMMSV_TYPE_INT32:
			if (xmmsv_dict_entry_get_int (dict, props[i], &tint)) {
				g_string_append_printf (str, "%s=%d\n", props[i], tint);
			}
			break;
		default:
			/* noop */
			break;
		}
	}

	send_msg ("New media", str);

	g_string_free (str, TRUE);
	return TRUE; /* keep broadcast alive */
}
예제 #10
0
void media_info_get (xmmsv_t *value, media_info *info) {
	xmmsv_t *infos, *dict_entry;
	const char *artist, *album, *title, *url, *comment, *genre, *date;

	assert(value);
	assert(info);

	infos = xmmsv_propdict_to_dict(value, NULL);
	
	if (!xmmsv_dict_get (infos, "id", &dict_entry) ||
	    !xmmsv_get_int (dict_entry, &info->id)) {
		info->id = 0;
	}
	if (!xmmsv_dict_get (infos, "artist", &dict_entry) ||
	    !xmmsv_get_string (dict_entry, &artist)) {
		artist = "[Unknown Artist]";
	}
	if (!xmmsv_dict_get (infos, "album", &dict_entry) ||
	    !xmmsv_get_string (dict_entry, &album)) {
		album = "[Unknown Album]";
	}
	if (!xmmsv_dict_get (infos, "url", &dict_entry) ||
	    !xmmsv_get_string (dict_entry, &url)) {
		url = "[Unknown URL]";
	}
	if (!xmmsv_dict_get (infos, "title", &dict_entry) ||
	    !xmmsv_get_string (dict_entry, &title)) {
		title = ecore_file_file_get(url);
	}
	if (!xmmsv_dict_get (infos, "comment", &dict_entry) ||
	    !xmmsv_get_string (dict_entry, &comment)) {
		comment = "";
	}
	if (!xmmsv_dict_get (infos, "genre", &dict_entry) ||
	    !xmmsv_get_string (dict_entry, &genre)) {
		genre = "[Unknown Genre]";
	}
	if (!xmmsv_dict_get (infos, "date", &dict_entry) ||
	    !xmmsv_get_string (dict_entry, &date)) {
		date = "";
	}	
	if (!xmmsv_dict_get (infos, "duration", &dict_entry) ||
	    !xmmsv_get_int (dict_entry, &info->duration)) {
		info->duration = 0;
	}
	if (!xmmsv_dict_get (infos, "bitrate", &dict_entry) ||
	    !xmmsv_get_int (dict_entry, &info->bitrate)) {
		info->bitrate = 0;
	}
	if (!xmmsv_dict_get (infos, "tracknr", &dict_entry) ||
	    !xmmsv_get_int (dict_entry, &info->tracknr)) {
		info->tracknr = 0;
	}

	info->artist = strdup(artist);
	info->album = strdup(album);
	info->title = decode_url(title);
	info->url = decode_url(url);
	info->comment = strdup(comment);
	info->genre = strdup(genre);
	info->date = strdup(date);

	xmmsv_unref(infos);
}
예제 #11
0
파일: xmmsinfo.c 프로젝트: Donearm/Mpd-Info
int show_xmmsinfo_c(lua_State *L)
{
	xmmsc_connection_t *connection;
	xmmsc_result_t *state;
	xmmsv_t *state_value;
	const char *err_buf;
	int32_t status;

	// string containing the current xmms2 state
	char *state_str;

	// initialize the Info struct
	struct Info i;

	// initialize the connection
	connection = xmmsc_init("xmmsinfo");
	if (!connection) {
		fprintf(stderr, "No connection!\n");
		return(EXIT_FAILURE);
	}

	// try to connect
	if (!xmmsc_connect(connection, getenv("XMMS_PATH"))) {
		fprintf(stderr, "Connection failed, %s\n",
				xmmsc_get_last_error(connection));
		return(EXIT_FAILURE);
	}

	// get current xmms2 status
	state = xmmsc_playback_status(connection);
	xmmsc_result_wait(state);
	state_value = xmmsc_result_get_value(state);

	if(xmmsv_get_error(state_value, &err_buf)) {
		fprintf(stderr, "Error while asking for the connection status, %s\n",
				err_buf);
	}

	if(!xmmsv_get_int(state_value, &status)) {
		fprintf(stderr, "Couldn't get connection status, %d\n", status);
	}

	// 0 == stopped; 1 == playing; 2 == paused
	if(status == XMMS_PLAYBACK_STATUS_PLAY) {
		state_str = "playing";
	} else if (status == XMMS_PLAYBACK_STATUS_PAUSE) {
		state_str = "paused";
	} else {
		state_str = "stopped";
	}

	i.state = state_str;

	// get current position in the playlist
	xmmsc_result_t *current_id;
	xmmsv_t *current_id_value;
	int32_t cur_id;

	current_id = xmmsc_playback_current_id(connection);
	xmmsc_result_wait(current_id);
	current_id_value = xmmsc_result_get_value(current_id);
	xmmsv_get_int(current_id_value, &cur_id);



	// initialize variables for the song info
	xmmsc_result_t *result;
	xmmsv_t *return_value;
	xmmsv_t *dict_entry;
	xmmsv_t *infos;
	const char *val;

	result = xmmsc_medialib_get_info(connection, cur_id);
	xmmsc_result_wait(result);
	return_value = xmmsc_result_get_value(result);

	if(xmmsv_get_error(return_value, &err_buf)) {
		fprintf(stderr, "Medialib returns error, %s\n",
				err_buf);
		return(EXIT_FAILURE);
	}

	infos = xmmsv_propdict_to_dict(return_value, NULL);
	if(!xmmsv_dict_get(infos, "artist", &dict_entry) ||
			!xmmsv_get_string(dict_entry, &val)) {
		val = "No Artist";
	}

	i.artist = val;

	if(!xmmsv_dict_get(infos, "album", &dict_entry) ||
			!xmmsv_get_string(dict_entry, &val)) {
		val = "No Album";
	}

	i.album = val;

	if(!xmmsv_dict_get(infos, "title", &dict_entry) ||
			!xmmsv_get_string(dict_entry, &val)) {
		val = "No Title";
	}

	i.song = val;

	i.id = cur_id;

	if(!xmmsv_dict_get(infos, "url", &dict_entry) ||
			!xmmsv_get_string(dict_entry, &val)) {
		val = NULL;
	}

	i.uri = val;

	// push everything to lua
	lua_pushstring(L, i.state);
	lua_pushstring(L, i.artist);
	lua_pushstring(L, i.album);
	lua_pushstring(L, i.song);
	lua_pushinteger(L, i.id);
	lua_pushstring(L, i.uri);


	// clean up
	xmmsv_unref(infos);
	xmmsc_result_unref(result);
	xmmsc_result_unref(state);
	xmmsc_result_unref(current_id);
	xmmsc_unref(connection);
	return 6;
}
예제 #12
0
파일: common.c 프로젝트: dreamerc/xmms2
void
format_pretty_list (xmmsc_connection_t *conn, GList *list)
{
	guint count = 0;
	GList *n;
	gint columns;
	gchar *format_header, *format_rows;

	columns = find_terminal_width ();
	format_header = make_justified_columns_format (columns, 's');
	format_rows   = make_justified_columns_format (columns, 'd');

	print_padded_string (columns, '-', TRUE, "-[Result]-");
	print_info (format_header, "Id", "Artist", "Album", "Title");

	for (n = list; n; n = g_list_next (n)) {
		const gchar *title;
		xmmsc_result_t *res;
		xmmsv_t *propdict, *val;
		gint mid = XPOINTER_TO_INT (n->data);

		if (!mid) {
			print_error ("Empty result!");
		}

		res = xmmsc_medialib_get_info (conn, mid);
		xmmsc_result_wait (res);
		propdict = xmmsc_result_get_value (res);
		val = xmmsv_propdict_to_dict (propdict, NULL);

		if (xmmsv_dict_entry_get_string (val, "title", &title)) {
			const gchar *artist, *album;
			if (!xmmsv_dict_entry_get_string (val, "artist", &artist)) {
				artist = "Unknown";
			}

			if (!xmmsv_dict_entry_get_string (val, "album", &album)) {
				album = "Unknown";
			}

			print_info (format_rows, mid, artist, album, title);
		} else {
			const gchar *url;
			xmmsv_dict_entry_get_string (val, "url", &url);
			if (url) {
				gchar *filename = g_path_get_basename (url);
				if (filename) {
					print_info ("%-5.5d| %s", mid, filename);
					g_free (filename);
				}
			}
		}

		count++;

		xmmsv_unref (val);
		xmmsc_result_unref (res);
	}

	print_padded_string (columns, '-', FALSE, "-[Count:%6.d]-----", count);

	g_free (format_header);
	g_free (format_rows);
}
예제 #13
0
파일: tut3.c 프로젝트: eggpi/xmms2-tutorial
int
main (int argc, char **argv)
{
	/*
	 * The first part of this program is
	 * commented on in tut1.c and tut2.c
	 */
	xmmsc_connection_t *connection;
	xmmsc_result_t *result;
	xmmsv_t *return_value;
	const char *err_buf;

	/*
	 * Variables that we'll need later
	 */
	const char *val;
	int intval;
	int id;
	xmmsv_t *dict_entry;
	xmmsv_t *infos;

	connection = xmmsc_init ("tutorial3");
	if (!connection) {
		fprintf (stderr, "OOM!\n");
		exit (EXIT_FAILURE);
	}

	if (!xmmsc_connect (connection, getenv ("XMMS_PATH"))) {
		fprintf (stderr, "Connection failed: %s\n",
		         xmmsc_get_last_error (connection));

		exit (EXIT_FAILURE);
	}

	/*
	 * Ok, let' do the same thing as we did in
	 * tut2.c and retrieve the current playing
	 * entry. We need that to get information
	 * about the song.
	 */
	result = xmmsc_playback_current_id (connection);
	xmmsc_result_wait (result);
	return_value = xmmsc_result_get_value (result);

	if (xmmsv_is_error (return_value) &&
	    xmmsv_get_error (return_value, &err_buf)) {
		fprintf (stderr, "playback current id returns error, %s\n",
		         err_buf);
	}

	if (!xmmsv_get_int (return_value, &id)) {
		fprintf (stderr, "xmmsc_playback_current_id didn't "
		         "return int as expected\n");
		/* Fake id (ids are >= 1) used as an error flag. */
		id = 0;
	}

	/* Print the value */
	printf ("Currently playing id is %d\n", id);

	/*
	 * Same drill as before. Release memory
	 * so that we can reuse it in the next
	 * clientlib call.
	 * */
	xmmsc_result_unref (result);

	/*
	 * Something about the medialib and xmms2. All
	 * entries that are played, put into playlists
	 * have to be in the medialib. A song's metadata
	 * will be added to the medialib the first time
	 * you do "xmms2 add" or equivalent.
	 *
	 * When we request information for an entry, it will
	 * be requested from the medialib, not the playlist
	 * or the playback. The playlist and playback only
	 * know the unique id of the entry. All other
	 * information must be retrieved in subsequent calls.
	 *
	 * Entry 0 is non valid. Only 1-inf is valid.
	 * So let's check for 0 and don't ask medialib for it.
	 */
	if (id == 0) {
		fprintf (stderr, "Nothing is playing.\n");
		exit (EXIT_FAILURE);
	}

	/*
	 * And now for something about return types from
	 * clientlib. The clientlib will always return
	 * an xmmsc_result_t that will eventually contain the
	 * return value as a xmmsv_t struct.
	 * The value can contain an int and string as
	 * base type. It can also contain more complex
	 * types like lists and dicts.
	 * A list is a sequence of values, each of them
	 * wrapped in its own xmmsv_t struct (of any type).

	 * A dict is a key<->value representation where key
	 * is always a string but the value is again wrapped
	 * in its own xmmsv_t struct (of any type).
	 *
	 * When retrieving an entry from the medialib, you
	 * get a dict as return. Let's print out some
	 * entries from it and then traverse the dict.
	 */
	result = xmmsc_medialib_get_info (connection, id);

	/* And waaait for it .. */
	xmmsc_result_wait (result);

	/* Let's reuse the previous return_value pointer, it
	 * was invalidated as soon as we freed the result that
	 * contained it anyway.
	 */
	return_value = xmmsc_result_get_value (result);

	if (xmmsv_is_error (return_value) &&
	    xmmsv_get_error (return_value, &err_buf)) {
		/*
		 * This can return error if the id
		 * is not in the medialib
		 */
		fprintf (stderr, "medialib get info returns error, %s\n",
		         err_buf);
		exit (EXIT_FAILURE);
	}

	/*
	 * Because of the nature of the dict returned by
	 * xmmsc_medialib_get_info, we need to convert it to
	 * a simpler dict using xmmsv_propdict_to_dict.
	 * Let's not worry about that for now and accept it
	 * as a fact of life.
	 *
	 * See tut5 for a discussion about dicts and propdicts.
	 *
	 * Note that xmmsv_propdict_to_dict creates a new
	 * xmmsv_t struct, which we will need to free manually
	 * when we're done with it.
	 */
	infos = xmmsv_propdict_to_dict (return_value, NULL);

	/*
	 * We must first retrieve the xmmsv_t struct
	 * corresponding to the "artist" key in the dict,
	 * and then extract the string from that struct.
	 */
	if (!xmmsv_dict_get (infos, "artist", &dict_entry) ||
	    !xmmsv_get_string (dict_entry, &val)) {
		/*
		 * if we end up here it means that the key "artist" wasn't
		 * in the dict or that the value for "artist" wasn't a
		 * string.
		 *
		 * You can check the type of the entry (if there is one) with
		 * xmmsv_get_type (dict_entry). It will return an
		 * xmmsv_type_t enum describing the type.
		 *
		 * Actually this is no disaster, it might just mean that
		 * we don't have an artist tag on this entry. Let's
		 * call it "No Artist" for now.
		 */
		val = "No Artist";
	}

	/* print the value */
	printf ("artist = %s\n", val);

	if (!xmmsv_dict_get (infos, "title", &dict_entry) ||
	    !xmmsv_get_string (dict_entry, &val)) {
		val = "No Title";
	}
	printf ("title = %s\n", val);

	/*
	 * Let's extract an integer as well
	 */
	if (!xmmsv_dict_get (infos, "bitrate", &dict_entry) ||
	    !xmmsv_get_int (dict_entry, &intval)) {
		intval = 0;
	}
	printf ("bitrate = %i\n", intval);

	/*
	 * We need to free infos manually here, else we will leak.
	 */
	xmmsv_unref (infos);

	/*
	 * !!Important!!
	 *
	 * When unreffing the result here we will free
	 * the memory that we have extracted from the dict,
	 * and that includes all the string pointers of the
	 * dict entries! So if you want to keep strings
	 * somewhere you need to copy that memory! Very
	 * important otherwise you will get undefined behaviour.
	 */
	xmmsc_result_unref (result);

	xmmsc_unref (connection);

	return (EXIT_SUCCESS);
}
예제 #14
0
void
cmd_list (xmmsc_connection_t *conn, gint argc, gchar **argv)
{
	gchar *playlist = NULL;
	xmmsc_result_t *res;
	xmmsv_t *val;
	xmmsv_list_iter_t *it;
	gulong total_playtime = 0;
	gint p = 0;
	guint pos = 0;

	if (argc > 2) {
		playlist = argv[2];
	}

	res = xmmsc_playlist_current_pos (conn, playlist);
	xmmsc_result_wait (res);
	val = xmmsc_result_get_value (res);

	if (!xmmsv_is_error (val)) {
		if (!xmmsv_dict_entry_get_int (val, "position", &p)) {
			print_error ("Broken resultset");
		}
		xmmsc_result_unref (res);
	}

	res = xmmsc_playlist_list_entries (conn, playlist);
	xmmsc_result_wait (res);
	val = xmmsc_result_get_value (res);

	if (xmmsv_is_error (val)) {
		print_error ("%s", xmmsv_get_error_old (val));
	}

	xmmsv_get_list_iter (val, &it);
	while (xmmsv_list_iter_valid (it)) {
		xmmsc_result_t *info_res;
		xmmsv_t *val_id, *propdict, *info_val;
		gchar line[80];
		gint playtime = 0;
		guint ui;

		xmmsv_list_iter_entry (it, &val_id);
		if (!xmmsv_get_uint (val_id, &ui)) {
			print_error ("Broken resultset");
		}

		info_res = xmmsc_medialib_get_info (conn, ui);
		xmmsc_result_wait (info_res);
		propdict = xmmsc_result_get_value (info_res);
		info_val = xmmsv_propdict_to_dict (propdict, NULL);

		if (xmmsv_is_error (info_val)) {
			print_error ("%s", xmmsv_get_error_old (info_val));
		}

		if (xmmsv_dict_entry_get_int (info_val, "duration", &playtime)) {
			total_playtime += playtime;
		}

		if (val_has_key (info_val, "channel")) {
			if (val_has_key (info_val, "title")) {
				xmmsc_entry_format (line, sizeof (line),
				                    "[stream] ${title}", info_val);
			} else {
				xmmsc_entry_format (line, sizeof (line),
				                    "${channel}", info_val);
			}
		} else if (!val_has_key (info_val, "title")) {
			const gchar *url;
			gchar dur[10];

			xmmsc_entry_format (dur, sizeof (dur),
			                    "(${minutes}:${seconds})", info_val);

			if (xmmsv_dict_entry_get_string (info_val, "url", &url)) {
				gchar *filename = g_path_get_basename (url);
				if (filename) {
					g_snprintf (line, sizeof (line), "%s %s", filename, dur);
					g_free (filename);
				} else {
					g_snprintf (line, sizeof (line), "%s %s", url, dur);
				}
			}
		} else {
			xmmsc_entry_format (line, sizeof (line), listformat, info_val);
		}

		if (p == pos) {
			print_info ("->[%d/%d] %s", pos, ui, line);
		} else {
			print_info ("  [%d/%d] %s", pos, ui, line);
		}

		pos++;

		xmmsc_result_unref (info_res);
		xmmsv_unref (info_val);
		xmmsv_list_iter_next (it);
	}
	xmmsc_result_unref (res);

	/* rounding */
	total_playtime += 500;

	print_info ("\nTotal playtime: %d:%02d:%02d", total_playtime / 3600000,
	            (total_playtime / 60000) % 60, (total_playtime / 1000) % 60);
}