diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/playlist/embcue_playlist_plugin.c | 168 | ||||
-rw-r--r-- | src/playlist/embcue_playlist_plugin.h | 25 | ||||
-rw-r--r-- | src/playlist_list.c | 2 | ||||
-rw-r--r-- | src/tag_file.c | 90 | ||||
-rw-r--r-- | src/tag_file.h | 37 |
5 files changed, 322 insertions, 0 deletions
diff --git a/src/playlist/embcue_playlist_plugin.c b/src/playlist/embcue_playlist_plugin.c new file mode 100644 index 000000000..b05b98e49 --- /dev/null +++ b/src/playlist/embcue_playlist_plugin.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** \file + * + * Playlist plugin that reads embedded cue sheets from the "CUESHEET" + * tag of a music file. + */ + +#include "config.h" +#include "playlist/embcue_playlist_plugin.h" +#include "playlist_plugin.h" +#include "tag.h" +#include "tag_handler.h" +#include "tag_file.h" +#include "tag_ape.h" +#include "tag_id3.h" +#include "song.h" +#include "cue/cue_parser.h" + +#include <glib.h> +#include <assert.h> +#include <string.h> + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "cue" + +struct embcue_playlist { + struct playlist_provider base; + + /** + * The value of the file's "CUESHEET" tag. + */ + char *cuesheet; + + /** + * The offset of the next line within "cuesheet". + */ + char *next; + + struct cue_parser *parser; +}; + +static void +embcue_tag_pair(const char *name, const char *value, void *ctx) +{ + struct embcue_playlist *playlist = ctx; + + if (playlist->cuesheet == NULL && + g_ascii_strcasecmp(name, "cuesheet") == 0) + playlist->cuesheet = g_strdup(value); +} + +static const struct tag_handler embcue_tag_handler = { + .pair = embcue_tag_pair, +}; + +static struct playlist_provider * +embcue_playlist_open_uri(const char *uri, + G_GNUC_UNUSED GMutex *mutex, + G_GNUC_UNUSED GCond *cond) +{ + if (!g_path_is_absolute(uri)) + /* only local files supported */ + return NULL; + + struct embcue_playlist *playlist = g_new(struct embcue_playlist, 1); + playlist_provider_init(&playlist->base, &embcue_playlist_plugin); + playlist->cuesheet = NULL; + + tag_file_scan(uri, &embcue_tag_handler, playlist); + if (playlist->cuesheet == NULL) { + tag_ape_scan2(uri, &embcue_tag_handler, playlist); + if (playlist->cuesheet == NULL) + tag_id3_scan(uri, &embcue_tag_handler, playlist); + } + + if (playlist->cuesheet == NULL) { + /* no "CUESHEET" tag found */ + g_free(playlist); + return NULL; + } + + playlist->next = playlist->cuesheet; + playlist->parser = cue_parser_new(); + + return &playlist->base; +} + +static void +embcue_playlist_close(struct playlist_provider *_playlist) +{ + struct embcue_playlist *playlist = (struct embcue_playlist *)_playlist; + + cue_parser_free(playlist->parser); + g_free(playlist->cuesheet); + g_free(playlist); +} + +static struct song * +embcue_playlist_read(struct playlist_provider *_playlist) +{ + struct embcue_playlist *playlist = (struct embcue_playlist *)_playlist; + + struct song *song = cue_parser_get(playlist->parser); + if (song != NULL) + return song; + + while (*playlist->next != 0) { + const char *line = playlist->next; + char *eol = strpbrk(playlist->next, "\r\n"); + if (eol != NULL) { + /* null-terminate the line */ + *eol = 0; + playlist->next = eol + 1; + } else + /* last line; put the "next" pointer to the + end of the buffer */ + playlist->next += strlen(line); + + cue_parser_feed(playlist->parser, line); + song = cue_parser_get(playlist->parser); + if (song != NULL) + return song; + } + + cue_parser_finish(playlist->parser); + return cue_parser_get(playlist->parser); +} + +static const char *const embcue_playlist_suffixes[] = { + /* a few codecs that are known to be supported; there are + probably many more */ + "flac", + "mp3", "mp2", + "mp4", "mp4a", "m4b", + "ape", + "wv", + "ogg", "oga", + NULL +}; + +const struct playlist_plugin embcue_playlist_plugin = { + .name = "cue", + + .open_uri = embcue_playlist_open_uri, + .close = embcue_playlist_close, + .read = embcue_playlist_read, + + .suffixes = embcue_playlist_suffixes, + .mime_types = NULL, +}; diff --git a/src/playlist/embcue_playlist_plugin.h b/src/playlist/embcue_playlist_plugin.h new file mode 100644 index 000000000..c5f21b27e --- /dev/null +++ b/src/playlist/embcue_playlist_plugin.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_PLAYLIST_EMBCUE_PLAYLIST_PLUGIN_H +#define MPD_PLAYLIST_EMBCUE_PLAYLIST_PLUGIN_H + +extern const struct playlist_plugin embcue_playlist_plugin; + +#endif diff --git a/src/playlist_list.c b/src/playlist_list.c index f89ab386d..0593ed0db 100644 --- a/src/playlist_list.c +++ b/src/playlist_list.c @@ -29,6 +29,7 @@ #include "playlist/asx_playlist_plugin.h" #include "playlist/rss_playlist_plugin.h" #include "playlist/cue_playlist_plugin.h" +#include "playlist/embcue_playlist_plugin.h" #include "playlist/flac_playlist_plugin.h" #include "input_stream.h" #include "uri.h" @@ -55,6 +56,7 @@ static const struct playlist_plugin *const playlist_plugins[] = { &lastfm_playlist_plugin, #endif &cue_playlist_plugin, + &embcue_playlist_plugin, #ifdef HAVE_FLAC &flac_playlist_plugin, #endif diff --git a/src/tag_file.c b/src/tag_file.c new file mode 100644 index 000000000..8d8a0f5fb --- /dev/null +++ b/src/tag_file.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "tag_file.h" +#include "uri.h" +#include "decoder_list.h" +#include "decoder_plugin.h" +#include "input_stream.h" + +#include <assert.h> +#include <unistd.h> /* for SEEK_SET */ + +bool +tag_file_scan(const char *path_fs, + const struct tag_handler *handler, void *handler_ctx) +{ + assert(path_fs != NULL); + assert(handler != NULL); + + /* check if there's a suffix and a plugin */ + + const char *suffix = uri_get_suffix(path_fs); + if (suffix == NULL) + return false; + + const struct decoder_plugin *plugin = + decoder_plugin_from_suffix(suffix, NULL); + if (plugin == NULL) + return false; + + struct input_stream *is = NULL; + GMutex *mutex = NULL; + GCond *cond = NULL; + + do { + /* load file tag */ + if (decoder_plugin_scan_file(plugin, path_fs, + handler, handler_ctx)) + break; + + /* fall back to stream tag */ + if (plugin->scan_stream != NULL) { + /* open the input_stream (if not already + open) */ + if (is == NULL) { + mutex = g_mutex_new(); + cond = g_cond_new(); + is = input_stream_open(path_fs, mutex, cond, + NULL); + } + + /* now try the stream_tag() method */ + if (is != NULL) { + if (decoder_plugin_scan_stream(plugin, is, + handler, + handler_ctx)) + break; + + input_stream_lock_seek(is, 0, SEEK_SET, NULL); + } + } + + plugin = decoder_plugin_from_suffix(suffix, plugin); + } while (plugin != NULL); + + if (is != NULL) { + input_stream_close(is); + g_cond_free(cond); + g_mutex_free(mutex); + } + + return plugin != NULL; +} diff --git a/src/tag_file.h b/src/tag_file.h new file mode 100644 index 000000000..8cf1af3cb --- /dev/null +++ b/src/tag_file.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_TAG_FILE_H +#define MPD_TAG_FILE_H + +#include "check.h" + +#include <stdbool.h> + +struct tag_handler; + +/** + * Scan the tags of a song file. Invokes matching decoder plugins, + * but does not invoke the special "APE" and "ID3" scanners. + */ +bool +tag_file_scan(const char *path_fs, + const struct tag_handler *handler, void *handler_ctx); + +#endif |