Pull to refresh

Расширяем функциональность conky: добавляем функцию для отображения даты трека MPD

Reading time 7 min
Views 3.7K

Введение


Недавно я перешёл с ncmpc на ncmpcpp. Порадовал «альтернативный режим отображения», в нём информация о треке выводится не снизу, а сверху, причем в две строчки, а не в одну, выглядит это так:



Потом мне захотелось, чтобы в conky информация MPD отображалась примерно так же. Но вот незадача — conky умеет показывать название трека, альбома, исполнителя, а вот дату не умеет. Но это для нас не большая проблема, opensource, все-таки, допишем необходимую функциональность своими руками.

Анализ исходного кода


Для начала изучим исходники conky. Для этого скачаем тарболл и распакуем его:

$ wget http://downloads.sourceforge.net/project/conky/conky/1.8.1/conky-1.8.1.tar.bz2
$ tar -xf conky-1.8.1.tar.bz2
$ cd conky-1.8.1/src



Здесь можно увидеть четыре файла, в названии которых фигурирует 'mpd': mpd.c, mpd.h, libmpdclient.c и libmpdclient.h. Разработчики conky не стали заморачиваться с собственной реализацией поддержки mpd и взяли готовый libmpdclient. Ну что же, посмотрим, какую информацию о треке даёт mpd (в libmpdclient.h):

typedef struct _mpd_Song {
	/* filename of song */
	char *file;
	/* artist, maybe NULL if there is no tag */
	char *artist;
	/* title, maybe NULL if there is no tag */
	char *title;
	/* album, maybe NULL if there is no tag */
	char *album;
	/* track, maybe NULL if there is no tag */
	char *track;
	/* name, maybe NULL if there is no tag; it's the name of the current song,
	 * f.e. the icyName of the stream */
	char *name;
	/* date */
	char *date;

	/* added by qball */
	/* Genre */
	char *genre;
	/* Composer */
	char *composer;
	/* Performer */
	char *performer;
	/* Disc */
	char *disc;
	/* Comment */
	char *comment;

	/* length of song in seconds, check that it is not MPD_SONG_NO_TIME */
	int time;
	/* if plchanges/playlistinfo/playlistid used, is the position of the song
	 * in the playlist */
	int pos;
	/* song id for a song in the playlist */
	int id;
} mpd_Song;

Итак, и artist, и title, и album, и date — всё это char*. Задача упрощается — достаточно делать всё по образу и подобию.

Добавляем функционал


За основу я взял функцию conky mpd_title. Посмотрим, где она упоминается:

$ grep mpd_title *.c *.h



Для начала разберемся с mpd.h и mpd.c. В mpd.h описана структура:

struct mpd_s {
	char *title;
	char *artist;
	char *album;
	const char *status;
	const char *random;
	const char *repeat;
	char *track;
	char *name;
	char *file;
	int is_playing;
	int vol;
	float progress;
	int bitrate;
	int length;
	int elapsed;
};

Добавим в неё поле date типа char*:
	char *date;

Чуть ниже описание функции print_mpd_title:
void print_mpd_title(struct text_object *, char *, int);

Скопируем её и заменим title на date:
void print_mpd_date(struct text_object *, char *, int);

Больше в этом файле ничего изменять не требуется. Теперь нужно подредактировать mpd.c. Странно, но там вроде бы нет упоминаний mpd_title? Попробуем поискать просто title.

$ grep title mpd.c



Строка MPD_PRINT_GENERATOR(title, "%s") всё объясняет — для генерации функций используются макросы, поэтому строчка «mpd_title» не находилась. Ну что же, для каждой строчки с title сделаем аналог с date:

static void clear_mpd(void)
{
#define xfree(x) if (x) free(x)
	xfree(mpd_info.title);
	xfree(mpd_info.date); /* <-- */
	xfree(mpd_info.artist);
	xfree(mpd_info.album);
	/* do not free() the const char *status! */
	/* do not free() the const char *random! */
	/* do not free() the const char *repeat! */
	xfree(mpd_info.track);
	xfree(mpd_info.name);
	xfree(mpd_info.file);
#undef xfree
	memset(&mpd_info, 0, sizeof(struct mpd_s));
}
...
			SONGSET(artist);
			SONGSET(album);
			SONGSET(title);
			SONGSET(date); /* <-- */
			SONGSET(track);
			SONGSET(name);
			SONGSET(file);
...
MPD_PRINT_GENERATOR(title, "%s")
MPD_PRINT_GENERATOR(date, "%s") /* <-- */
MPD_PRINT_GENERATOR(artist, "%s")
MPD_PRINT_GENERATOR(album, "%s")
MPD_PRINT_GENERATOR(random, "%s")
MPD_PRINT_GENERATOR(repeat, "%s")
MPD_PRINT_GENERATOR(track, "%s")
MPD_PRINT_GENERATOR(name, "%s")
MPD_PRINT_GENERATOR(file, "%s")
MPD_PRINT_GENERATOR(vol, "%d")
MPD_PRINT_GENERATOR(bitrate, "%d")
MPD_PRINT_GENERATOR(status, "%s")

После этих изменений mpd.c тоже можно закрывать. На этом этапе мы добились того, чтобы conky получал необходимую информацию от MPD. Осталось научить его показывать эту информацию. Редактируем conky.c тем же образом — копируем то, что есть для mpd_title, и изменяем title на date:

#ifdef MPD
			OBJ(mpd_title)
				print_mpd_title(obj, p, p_max_size);
			OBJ(mpd_date) /* <-- */
				print_mpd_date(obj, p, p_max_size); /* <-- */

Теперь то же самое в core.c:

	END OBJ(mpd_title, &update_mpd)
		mpd_set_maxlen(mpd_title);
		init_mpd();	
	END OBJ(mpd_date, &update_mpd) /* <-- */
		mpd_set_maxlen(mpd_date); /* <-- */
		init_mpd(); /* <-- */

Ну и заключительный штрих — text_object.h:

#ifdef MPD
	OBJ_mpd_title,
	OBJ_mpd_date, /* <-- */

На этом работа с исходным текстом закончена, осталось собрать. Сначала — конфигурация:

$ cd ..; ./configure

Здесь я не указываю никаких дополнительных параметров, так как поддержка mpd включена по умолчанию. Про все доступные параметры можно узнать из вывода ./configure --help.

configure в случае успешной конфигурации выведет информацию о включенных и выключенных опциональных возможностях:



MPD: yes — это нам и нужно. Теперь нужно собственно собрать:

make

В случае успешной сборки уже можно проверять, работает ли наша функция mpd_date. Для этого допишем её куда-нибудь в ~/.conkyrc. В моём случае кусок конфига выглядит так:

${alignc}$mpd_title
${alignc}${color #dddd55}$mpd_artist
${alignc}${color #55dd88}$mpd_album $color(${color yellow}$mpd_date$color)

Запускаем только что собранный conky:

./src/conky



Работает!

Сборка пакета


Теперь осталось собрать пакет для своего дистрибутива и заменить им тот, что поставляется с дистрибутивом. Если же это делать лень, можно просто сделать sudo make install, в этом случае conky установится в /usr/local; однако так делать не рекомендуется по разным причинам.

Итак, бонусная часть: сборка пакета для своего дистрибутива.

Portage-based (Gentoo, Sabayon)

Если у вас ещё нет локального оверлея, то сейчас самое время его создать.

Предположим, ваш локальный оверлей расположен в /usr/local/portage. Создаём каталог для conky и копируем ебилд и уже существующие патчи:

# mkdir -p /usr/local/portage/app-admin/conky/files
# cd /usr/local/portage/app-admin/conky
# cp /usr/portage/app-admin/conky/conky-1.8.1-r5.ebuild conky-1.8.1-r6.ebuild
# cp /usr/portage/app-admin/conky/files files/

Теперь нужно сделать патч. Чтобы его сделать, надо во-первых очистить исходники от того, что там появилось после сборки, во-вторых, распаковать в другое место оригинальные исходники, в-третьих, выполнить «diff -aur <оригинал> <измененная копия>». Не мудрствуя лукаво, просто выложу сюда его текст:

diff -aur conky-1.8.1.orig/src/conky.c conky-1.8.1/src/conky.c
--- conky-1.8.1.orig/src/conky.c	2010-10-06 01:29:36.000000000 +0400
+++ conky-1.8.1/src/conky.c	2011-11-13 01:11:06.894704215 +0400
@@ -1945,6 +1945,8 @@
 				print_mpd_artist(obj, p, p_max_size);
 			OBJ(mpd_album)
 				print_mpd_album(obj, p, p_max_size);
+			OBJ(mpd_date)
+				print_mpd_date(obj, p, p_max_size);
 			OBJ(mpd_random)
 				print_mpd_random(obj, p, p_max_size);
 			OBJ(mpd_repeat)
diff -aur conky-1.8.1.orig/src/core.c conky-1.8.1/src/core.c
--- conky-1.8.1.orig/src/core.c	2010-10-06 01:29:36.000000000 +0400
+++ conky-1.8.1/src/core.c	2011-11-13 01:11:06.894704215 +0400
@@ -925,6 +925,9 @@
 	END OBJ(mpd_album, &update_mpd)
 		mpd_set_maxlen(mpd_album);
 		init_mpd();
+	END OBJ(mpd_date, &update_mpd)
+		mpd_set_maxlen(mpd_date);
+		init_mpd();
 	END OBJ(mpd_vol, &update_mpd) init_mpd();
 	END OBJ(mpd_bitrate, &update_mpd) init_mpd();
 	END OBJ(mpd_status, &update_mpd) init_mpd();
@@ -1733,6 +1736,7 @@
 			case OBJ_mpd_title:
 			case OBJ_mpd_artist:
 			case OBJ_mpd_album:
+			case OBJ_mpd_date:
 			case OBJ_mpd_random:
 			case OBJ_mpd_repeat:
 			case OBJ_mpd_vol:
diff -aur conky-1.8.1.orig/src/mpd.c conky-1.8.1/src/mpd.c
--- conky-1.8.1.orig/src/mpd.c	2010-10-06 01:29:36.000000000 +0400
+++ conky-1.8.1/src/mpd.c	2011-11-13 01:16:50.699508331 +0400
@@ -95,6 +95,7 @@
 	xfree(mpd_info.title);
 	xfree(mpd_info.artist);
 	xfree(mpd_info.album);
+	xfree(mpd_info.date);
 	/* do not free() the const char *status! */
 	/* do not free() the const char *random! */
 	/* do not free() the const char *repeat! */
@@ -273,6 +274,7 @@
 			SONGSET(artist);
 			SONGSET(album);
 			SONGSET(title);
+			SONGSET(date);
 			SONGSET(track);
 			SONGSET(name);
 			SONGSET(file);
@@ -403,6 +405,7 @@
 MPD_PRINT_GENERATOR(title, "%s")
 MPD_PRINT_GENERATOR(artist, "%s")
 MPD_PRINT_GENERATOR(album, "%s")
+MPD_PRINT_GENERATOR(date, "%s")
 MPD_PRINT_GENERATOR(random, "%s")
 MPD_PRINT_GENERATOR(repeat, "%s")
 MPD_PRINT_GENERATOR(track, "%s")
diff -aur conky-1.8.1.orig/src/mpd.h conky-1.8.1/src/mpd.h
--- conky-1.8.1.orig/src/mpd.h	2010-10-06 01:29:36.000000000 +0400
+++ conky-1.8.1/src/mpd.h	2011-11-13 01:11:06.898037530 +0400
@@ -7,6 +7,7 @@
 	char *title;
 	char *artist;
 	char *album;
+	char *date;
 	const char *status;
 	const char *random;
 	const char *repeat;
@@ -41,6 +42,7 @@
 void print_mpd_title(struct text_object *, char *, int);
 void print_mpd_artist(struct text_object *, char *, int);
 void print_mpd_album(struct text_object *, char *, int);
+void print_mpd_date(struct text_object *, char *, int);
 void print_mpd_random(struct text_object *, char *, int);
 void print_mpd_repeat(struct text_object *, char *, int);
 void print_mpd_track(struct text_object *, char *, int);
Только в conky-1.8.1/src: stamp-h1
diff -aur conky-1.8.1.orig/src/text_object.h conky-1.8.1/src/text_object.h
--- conky-1.8.1.orig/src/text_object.h	2010-10-06 01:29:36.000000000 +0400
+++ conky-1.8.1/src/text_object.h	2011-11-13 01:13:54.990460229 +0400
@@ -327,6 +327,7 @@
 	OBJ_mpd_title,
 	OBJ_mpd_artist,
 	OBJ_mpd_album,
+	OBJ_mpd_date,
 	OBJ_mpd_random,
 	OBJ_mpd_repeat,
 	OBJ_mpd_vol,

Этот патч нужно сохранить в папку files, я не стал изменять принцип именования патчей и назвал его «conky-1.8.1-mpd-date.patch». Теперь нужно немножко подправить ebuild, чтобы наш патч тоже применялся. Открываем ебилд, и в функции «src_prepare» добавить наш патч к списку применяемых:

src_prepare() {
	epatch "${FILESDIR}/${P}-nvidia-x.patch" \
		"${FILESDIR}/${P}-xmms2.patch" \
		"${FILESDIR}/${P}-secunia-SA43225.patch" \
		"${FILESDIR}/${P}-acpitemp.patch" \
		"${FILESDIR}/${P}-curl-headers.patch" \
		"${FILESDIR}/${P}-maxinterfaces.patch" \
		"${FILESDIR}/${P}-utf8-scroll.patch" \
		"${FILESDIR}/${P}-mpd-date.patch"
	eautoreconf
}

Сохраняем изменения, создаём Manifest:

# ebuild conky-1.8.1-r6.ebuild manifest

Теперь можно устанавливать:

# emerge conky

DEB-based (Debian, Ubuntu), RPM-based (Fedora, OpenSuSE), Slackware

Воспользуемся универсальной программой checkinstall. Сначала переконфигурируем исходники, указав нормальные пути для установки, и соберём их:

$ ./configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --datadir=/usr/share --sysconfdir=/etc --localstatedir=/var/lib --libdir=/usr/lib
$ make

Теперь вместо make install запустим checkinstall.

Для создания deb-пакета:

checkinstall -D make install

Для создания rpm-пакета:

checkinstall -R make install

Для создания пакета Slackware:

checkinstall -S make install

После чего полученный пакет можно устанавливать средствами вашего дистрибутива.

Примечание: не имею большого опыта в создании пакетов для таких пакетных менеджеров, посему, возможно, выбранный способ — не лучший.
Tags:
Hubs:
+24
Comments 9
Comments Comments 9

Articles