|Portada|Blog|Space|

[Índice] > Plugin para música en XChat

Para aquellos que hayan sentido la necesidad de tener un plugin
livianito para mostrar por el IRC la canción que están escuchando al
momento, les traigo una solución que hice en un par de horas ayer.

Para ejecutarlo alcanza: /music

El plugin autodetecta qué programa están usando, Y si están usando más
de uno, para ejecutarlo especificando el programa del cual quieren
obtener el tema actual: /music programa, por ejemplo /music xmms

Por el momento solo soporta amarok1 y xmms, que son los dos programas
que uso con más frecuencia.

El Makefile, infaltable como siempre:

music.so:music.c Makefile
	$(CC) -std=c99 -Wall -shared -fPIC -I/usr/include/xchat $< -o $@

Y el código del plugin de xchat:

#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "xchat-plugin.h"

typedef struct {
  const char * name;
  bool (*get_theme)(void);
} music_method_t;

// GLOBAL VARIABLES:
static xchat_plugin * ph;
static const music_method_t music_methods[]; // forward declaration

int music_command_music(char*[], char*[], void*);

int xchat_plugin_init(xchat_plugin * plugin_handle,
    char ** plugin_name, char ** plugin_desc, char ** plugin_version,
    char * arg) {

  ph = plugin_handle;

  *plugin_name = "music";
  *plugin_desc = "Implements the /music command";
  *plugin_version = "1";

  xchat_hook_command(ph, "MUSIC", XCHAT_PRI_NORM, music_command_music, NULL, NULL);

  xchat_print(ph, "\"music\" loaded\n");

  return 1;
}

int xchat_plugin_deinit(void) {
  xchat_print(ph, "music unloaded\n");
  return 1;
}

int music_command_music(char * word[], char * word_eol[], void * user_data) {
  if (*word[2]) {
    for (const music_method_t * method = music_methods; method->name; method++) {
      if (!strcasecmp(word[2], method->name)) {
	method->get_theme();
	return XCHAT_EAT_ALL;
      }
    }
  }
  for (const music_method_t * method = music_methods; method->name; method++) {
    if (method->get_theme())
      return XCHAT_EAT_ALL;
  }
  xchat_print(ph, "Warning: all /music methods failed.\n");
  return XCHAT_EAT_ALL;
}

///////////////// UTILITIES:

static int run_program(file, params, buffer, size)
	const char * file;
	char * const params[];
	char * buffer;
	size_t size;
{
  int status;
  int mypipe[2];
  if (!size)
    buffer = NULL; // an empty buffer is useless
  if (buffer) {
    pipe(mypipe); // create the pipe
  }
  pid_t pid = fork();
  if (pid > 0) { // PARENT PROCESS
    int n;
    close(mypipe[1]); // we don't need to write
    if (buffer) {
      while (n = read(mypipe[0], buffer, size), n > 0) {
	buffer += n;
	size -= n;
      }
      if (size)
	*buffer = 0; // having a null terminated buffer is a safer
      else
	buffer[-1] = 0; // we must lose one data byte
    }
    waitpid(pid, &status, 0);
    if (buffer)
      close(mypipe[0]);
  } else if (!pid) { // CHILD PROCESS
    if (buffer) {
      close(mypipe[0]); // and we don't need to read
      close(STDOUT_FILENO);
      dup2(mypipe[1], STDOUT_FILENO);
    }
    execvp(file, params);
    printf("execvp failed(): %s\n", strerror(errno));
    exit(1);
  } else {
    if (buffer) {
      close(mypipe[0]);
      close(mypipe[1]);
    }
    xchat_printf(ph, "ERROR: fork() failed: %s\n", strerror(errno));
    return -1;
  }
  return status;
}

////////////////// /MUSIC METHODS:

#define music_xmms_format "me está escuchando %T [XMMS]"
#define music_amarok_format "me está escuchando %s [Amarok1]"

bool music_amarok1_get_theme(void){
  char buffer[256];
  int res = run_program("dcop",
      (char*[]){"dcop", "amarok", "default", "nowPlaying", NULL},
      buffer, 256);
  char * s = strchr(buffer, '\n');
  if (s) *s = 0;
  if (res || !strcmp(buffer, "\n"))
    return false;
  xchat_commandf(ph, music_amarok_format, buffer);
  return true;
}

bool music_xmms_get_theme(void) {
  char buffer[256];
  int res = run_program("xmmsctrl",
      (char*[]){"xmmsctrl", "playing", NULL},
      buffer, 256);
  if (res)
    return false;
  res = run_program("xmmsctrl",
      (char*[]){"xmmsctrl", "print", music_xmms_format, NULL},
      buffer, 256);
  if (!res) {
    xchat_command(ph, buffer);
    return true;
  } else
    return false;
}

static const music_method_t music_methods[] = {
  {
    .name = "amarok1",
    .get_theme = &music_amarok1_get_theme
  },
  {
    .name = "xmms",
    .get_theme = &music_xmms_get_theme
  }, {}
};

---------
Los documentos en este sitio se encuentran licenciados bajo la GFDL.
Ver comentarios: [Hay i comentarios]
Para agregar un comentario: agregue a la URL: ?do=show_comment_form (explicación)