X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fscreen_lyrics.c;h=30a89a163973ddaf8f29143bf2bd5c88fdea20f1;hb=299a27c8dee0e7eeab3448ed7cdfe1ac7c97ebaf;hp=15f5721ec1bfcbf293a13df3ff0ed285dae953c6;hpb=2d0bc2a3f794ec9d974396e1b06a4b47849b551c;p=ncmpc.git diff --git a/src/screen_lyrics.c b/src/screen_lyrics.c index 15f5721..30a89a1 100644 --- a/src/screen_lyrics.c +++ b/src/screen_lyrics.c @@ -1,10 +1,6 @@ -/* - * $Id: screen_lyrics.c 3355 2006-09-1 17:44:04Z tradiaz $ - * +/* * (c) 2006 by Kalle Wallin - * Tue Aug 1 23:17:38 2006 - * lyrics enhancement written by Andreas Obergrusberger - * using www.leoslyrics.com XML API + * Copyright (C) 2008 Max Kellermann * * 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 @@ -21,523 +17,359 @@ * */ -#include -#include -#include -#include -#include -#include - -#include "config.h" -#ifndef DISABLE_LYRICS_SCREEN -#include "ncmpc.h" +#include +#include "i18n.h" #include "options.h" #include "mpdclient.h" #include "command.h" #include "screen.h" #include "screen_utils.h" -#include "easy_download.h" #include "strfsong.h" +#include "lyrics.h" +#include "charset.h" +#include "gcc.h" -#define LEOSLYRICS_SEARCH_URL "http://api.leoslyrics.com/api_search.php?auth=QuodLibet&artist=%s&songtitle=%s" - -#define LEOSLYRICS_CONTENT_URL "http://api.leoslyrics.com/api_lyrics.php?auth=QuodLibet&hid=%s" +#define _GNU_SOURCE +#include +#include +#include +#include +#include -#define CREDITS "Lyrics provided by www.LeosLyrics.com" -typedef struct _formed_text -{ - GString *text; - GArray *lines; - int val; -} formed_text; +static list_window_t *lw = NULL; +static const struct mpd_song *next_song; -XML_Parser parser, contentp; -static int lyrics_text_rows = -1; -static list_window_t *lw = NULL; -guint8 result; -char *hid; -GTimer *dltime; -short int lock; -//GString *lyr_text; -//char *lyr_text; -//GArray *textline; -formed_text lyr_text; -/* result is a bitset in which the succes when searching 4 lyrics is logged -countend by position - backwards -0: lyrics in database -1: proper access to the lyrics provider -2: lyrics found -3: exact match -4: lyrics downloaded -5: lyrics saved -wasting 3 bits doesn't mean being a fat memory hog like kde.... does it? -*/ -static void lyrics_paint(screen_t *screen, mpdclient_t *c); - -void get_text_line(formed_text *text, int num, char *dest, int len) +static struct { + struct mpd_song *song; + + char *artist, *title; + + struct lyrics_loader *loader; + + GPtrArray *lines; +} current; + +static void +screen_lyrics_abort(void) { - memset(dest, '\0', len*sizeof(char)); - if(num >= text->lines->len-1) return; - int linelen; - if(num == 0) - { - linelen = g_array_index(text->lines, int, num); - memcpy(dest, text->text->str, linelen*sizeof(char)); - } - else if(num == 1) - { //dont ask me why, but this is needed.... - linelen = g_array_index(text->lines, int, num) - - g_array_index(text->lines, int, num-1); - memcpy(dest, &text->text->str[g_array_index(text->lines, int, num-1)], - linelen*sizeof(char)); - } - else - { - linelen = g_array_index(text->lines, int, num+1) - - g_array_index(text->lines, int, num); - memcpy(dest, &text->text->str[g_array_index(text->lines, int, num)], - linelen*sizeof(char)); + if (current.loader != NULL) { + lyrics_free(current.loader); + current.loader = NULL; } - dest[linelen] = '\n'; - dest[linelen+1] = '\0'; -} - -void add_text_line(formed_text *dest, const char *src, int len) -{ - // need this because g_array_append_val doesnt work with literals - // and expat sends "\n" as an extra line everytime - if(len == 0) - { - dest->val = strlen(src); - if(dest->lines->len > 0) dest->val += g_array_index(dest->lines, int, - dest->lines->len-1); - g_string_append(dest->text, src); - g_array_append_val(dest->lines, dest->val); - return; + + if (current.artist != NULL) { + g_free(current.artist); + current.artist = NULL; } - if(len > 1 || dest->val == 0) - { - dest->val = len; - if(dest->lines->len > 0) dest->val += g_array_index(dest->lines, int, - dest->lines->len-1); + + if (current.title != NULL) { + g_free(current.title); + current.artist = NULL; } - else if (len == 1 && dest->val != 0) dest->val = 0; - - if(dest->val > 0) - { - g_string_append_len(dest->text, src, len); - g_array_append_val(dest->lines, dest->val); + + if (current.song != NULL) { + mpd_freeSong(current.song); + current.song = NULL; } } -void formed_text_init(formed_text *text) +static void +screen_lyrics_clear(void) { - if(text->text != NULL) g_string_free(text->text, TRUE); - text->text = g_string_new(""); - - if(text->lines != NULL) g_array_free(text->lines, TRUE); - text->lines = g_array_new(FALSE, TRUE, 4); - - text->val = 0; + guint i; + + for (i = 0; i < current.lines->len; ++i) + g_free(g_ptr_array_index(current.lines, i)); + + g_ptr_array_set_size(current.lines, 0); } -/* -char *check_lyr_hd(char *artist, char *title, int how) -{ //checking whether for lyrics file existence and proper access - static char path[1024]; - snprintf(path, 1024, "%s/.lyrics/%s/%s.lyric", - getenv("HOME"), artist, title); - - if(g_access(path, how) != 0) return NULL; - return path; -} - -int get_lyr_hd(char *artist, char *title) -{ - char *path = check_lyr_hd(artist, title, R_OK); - if(path == NULL) return -1; - - FILE *lyr_file; - lyr_file = fopen(path, "r"); - if(lyr_file == NULL) return -1; - - char *buf = NULL; - char **line = &buf; - size_t n = 0; - - while(1) - { - n = getline(line, &n, lyr_file); - if( n < 1 || *line == NULL || feof(lyr_file) != 0 ) return 0; - add_text_line(&lyr_text, *line, n+1); - free(*line); - *line = NULL; n = 0; - } - - return 0; -} - -int store_lyr_hd() + +static void +lyrics_paint(void); + +/** + * Repaint and update the screen. + */ +static void +lyrics_repaint(void) { - char artist[512]; - char title[512]; - static char path[1024]; - FILE *lyr_file; - - get_text_line(&lyr_text, 0, artist, 512); - get_text_line(&lyr_text, 1, title, 512); - artist[strlen(artist)-2] = '\0'; - title[strlen(title)-2] = '\0'; - - snprintf(path, 1024, "%s/.lyrics/%s/%s.lyric", - getenv("HOME"), artist, title); - - if (check_lyr_hd(artist, title, F_OK) == 0) lyr_file = fopen(path, "w"); - else lyr_file = fopen(path, "xw"); - if(lyr_file == NULL) return -1; - - int i; - char line_buf[1024]; - - for(i = 2; i <= lyr_text.text->len; i++) - { - get_text_line(&lyr_text, i, line_buf, 0); - fputs(line_buf, lyr_file); - } - fclose(lyr_file); - return 0; + lyrics_paint(); + wrefresh(lw->w); } - -*/ -void check_repaint() + +/** + * Repaint and update the screen, if it is currently active. + */ +static void +lyrics_repaint_if_active(void) { - if(screen_get_id("lyrics") == get_cur_mode_id())lyrics_paint(NULL, NULL); + if (screen_is_visible(&screen_lyrics)) { + lyrics_repaint(); + + /* XXX repaint the screen title */ + } } -int check_dl_progress(void *clientp, double dltotal, double dlnow, - double ultotal, double ulnow) +static void +screen_lyrics_set(const GString *str) { - if(g_timer_elapsed(dltime, NULL) >= options.lyrics_timeout) - { - formed_text_init(&lyr_text); - return -1; - } - return 0; -} + const char *p, *eol, *next; + screen_lyrics_clear(); + p = str->str; + while ((eol = strchr(p, '\n')) != NULL) { + char *line; -static void check_content(void *data, const char *name, const char **atts) -{ - if(strstr(name, "text") != NULL) - { + next = eol + 1; + + /* strip whitespace at end */ + + while (eol > p && (unsigned char)eol[-1] <= 0x20) + --eol; + + /* create copy and append it to current.lines*/ - result |= 16; + line = g_malloc(eol - p + 1); + memcpy(line, p, eol - p); + line[eol - p] = 0; + + g_ptr_array_add(current.lines, line); + + /* reset control characters */ + + for (eol = line + (eol - p); line < eol; ++line) + if ((unsigned char)*line < 0x20) + *line = ' '; + + p = next; } + + if (*p != 0) + g_ptr_array_add(current.lines, g_strdup(p)); + + /* paint new data */ + + lyrics_repaint_if_active(); } - -static void check_search_response(void *data, const char *name, - const char **atts) +static void +screen_lyrics_callback(const GString *result, mpd_unused void *data) { - if(strstr(name, "response") != NULL) - { - result |=2; - return; - } - - if(result & 4) - { - if(strstr(name, "result") != NULL) - { - if(strstr(atts[2], "hid") != NULL) - { - hid = atts[3]; - } - - if(strstr(atts[2], "exactMatch") != NULL) - { - result |= 8; - } - } - } - + assert(current.loader != NULL); + + if (result != NULL) + screen_lyrics_set(result); + else + screen_status_message (_("No lyrics")); + + lyrics_free(current.loader); + current.loader = NULL; } -static void end_tag(void *data, const char *name) +static void +screen_lyrics_load(const struct mpd_song *song) { - //hmmmmmm + char buffer[MAX_SONGNAME_LENGTH]; + + assert(song != NULL); + + screen_lyrics_abort(); + screen_lyrics_clear(); + + current.song = mpd_songDup(song); + + strfsong(buffer, sizeof(buffer), "%artist%", song); + current.artist = g_strdup(buffer); + + strfsong(buffer, sizeof(buffer), "%title%", song); + current.title = g_strdup(buffer); + + current.loader = lyrics_load(current.artist, current.title, + screen_lyrics_callback, NULL); } - static void check_search_success(void *userData, const XML_Char *s, int len) - { - if(result & 2) //lets first check whether we're right - { //we don't really want to search in the wrong string - if(strstr((char*) s, "SUCCESS")) - { - result |=4; - } - } - } +static FILE *create_lyr_file(const char *artist, const char *title) +{ + char path[1024]; -static void fetch_text(void *userData, const XML_Char *s, int len) + snprintf(path, 1024, "%s/.lyrics", + getenv("HOME")); + mkdir(path, S_IRWXU); + + snprintf(path, 1024, "%s/.lyrics/%s - %s.txt", + getenv("HOME"), artist, title); + + return fopen(path, "w"); +} + +static int store_lyr_hd(void) { - if(result & 16) - { - add_text_line(&lyr_text, s, len); - } + FILE *lyr_file; + unsigned i; + + lyr_file = create_lyr_file(current.artist, current.title); + if (lyr_file == NULL) + return -1; + + for (i = 0; i < current.lines->len; ++i) + fprintf(lyr_file, "%s\n", + (const char*)g_ptr_array_index(current.lines, i)); + + fclose(lyr_file); + return 0; } -gpointer get_lyr(void *c) +static const char * +list_callback(unsigned idx, mpd_unused int *highlight, mpd_unused void *data) { - mpd_Status *status = ((mpdclient_t*)c)->status; - mpd_Song *cur = ((mpdclient_t*)c)->song; - mpdclient_update((mpdclient_t*)c); - - if(!(IS_PAUSED(status->state)||IS_PLAYING(status->state))) - { - formed_text_init(&lyr_text); + static char buffer[256]; + char *value; + + if (idx >= current.lines->len) return NULL; - } - - char url_avail[256]; - char url_hid[256]; - char artist[MAX_SONGNAME_LENGTH]; - char title[MAX_SONGNAME_LENGTH]; - lock = 2; - result = 0; - - if(dltime == NULL) dltime = g_timer_new(); - - strfsong(artist, MAX_SONGNAME_LENGTH, "%artist%", cur); - strfsong(title, MAX_SONGNAME_LENGTH, "%title%", cur); - - formed_text_init(&lyr_text); - add_text_line(&lyr_text, artist, 0); - add_text_line(&lyr_text, title, 0); - - //if(get_lyr_hd(artist, title) == 0) return &lyr_text; - - //this replacess the whitespaces with '+' - g_strdelimit(artist, " ", '+'); - g_strdelimit(title, " ", '+'); - - //we insert the artist and the title into the url - snprintf(url_avail, 512, LEOSLYRICS_SEARCH_URL, artist, title); - - //download that xml! - easy_download_struct lyr_avail = {NULL, 0,-1}; - - g_timer_start(dltime); - if(!easy_download(url_avail, &lyr_avail, check_dl_progress)) return NULL; - g_timer_stop(dltime); - - //we gotta parse that stuff with expat - parser = XML_ParserCreate(NULL); - XML_SetUserData(parser, NULL); - - int state = 0; - - XML_SetElementHandler(parser, check_search_response, end_tag); - XML_SetCharacterDataHandler(parser, check_search_success); - XML_Parse(parser, lyr_avail.data, strlen(lyr_avail.data), state); - XML_ParserFree(parser); - - if(!(result & 4)) return NULL; //check whether lyrics found - easy_download_struct lyr_content = {NULL, 0,-1}; - snprintf(url_hid, 512, LEOSLYRICS_CONTENT_URL, hid); - - g_timer_continue(dltime); - if(!(easy_download(url_hid, &lyr_content, check_dl_progress))) return NULL; - g_timer_stop(dltime); - - contentp = XML_ParserCreate(NULL); - XML_SetUserData(contentp, NULL); - XML_SetElementHandler(contentp, check_content, end_tag); - XML_SetCharacterDataHandler(contentp, fetch_text); - XML_Parse(contentp, lyr_content.data, strlen(lyr_content.data), state); - XML_ParserFree(contentp); - - lw->start = 0; - check_repaint(); - - lock = 1; - return &lyr_text; -} - -static char * -list_callback(int index, int *highlight, void *data) -{ - static char buf[512]; - int linelen; - - //i think i'ts fine to write it into the 1st line... - if((index == lyr_text.lines->len && lyr_text.lines->len != 2)|| - ((lyr_text.lines->len == 0 - ||lyr_text.lines->len == 2) && index == 0)) - { - *highlight=3; - return CREDITS; - } - - if(index < 2 && lyr_text.lines->len > 2) *highlight=3; - else if(index >= lyr_text.lines->len || index == 2) - { - return ""; - } - if(index >1) index--; - get_text_line(&lyr_text, index, buf, 512); - return buf; -} + + value = utf8_to_locale(g_ptr_array_index(current.lines, idx)); + g_strlcpy(buffer, value, sizeof(buffer)); + free(value); + + return buffer; +} static void -lyrics_init(WINDOW *w, int cols, int rows) +lyrics_screen_init(WINDOW *w, int cols, int rows) { - lw = list_window_init(w, cols, rows); - lw->flags = LW_HIDE_CURSOR; - //lyr_text.lines = g_array_new(FALSE, TRUE, 4); - formed_text_init(&lyr_text); - if (!g_thread_supported()) g_thread_init(NULL); - + current.lines = g_ptr_array_new(); + lw = list_window_init(w, cols, rows); + lw->flags = LW_HIDE_CURSOR; } static void lyrics_resize(int cols, int rows) { - lw->cols = cols; - lw->rows = rows; + lw->cols = cols; + lw->rows = rows; } static void lyrics_exit(void) { - list_window_free(lw); + list_window_free(lw); + + screen_lyrics_abort(); + screen_lyrics_clear(); + + g_ptr_array_free(current.lines, TRUE); + current.lines = NULL; } +static void +lyrics_open(mpdclient_t *c) +{ + if (next_song == NULL) + next_song = c->song; + + if (next_song != NULL && + (current.song == NULL || + strcmp(next_song->file, current.song->file) != 0)) + screen_lyrics_load(next_song); -static char * + next_song = NULL; +} + + +static const char * lyrics_title(char *str, size_t size) { - if(lyr_text.lines->len == 2){ - if(lock == 1 && !(result & 2)) return _("Lyrics [No connection]"); - if(lock == 1 && !(result & 4)) return _("Lyrics [Not found]"); - if(lock == 2) return _("Lyrics [retrieving]"); - } - /*if(lyr_text.lines->len > 2) - { - static char buf[512]; - char artist[512]; - char title[512]; - get_text_line(&lyr_text, 0, artist, 512); - get_text_line(&lyr_text, 1, artist, 512); - snprintf(buf, 512, "Lyrics %s - %s", artist, title); - return buf; - }*/ - return "Lyrics"; + if (current.loader != NULL) { + snprintf(str, size, "%s (%s)", + _("Lyrics"), _("loading...")); + return str; + } else if (current.artist != NULL && current.title != NULL && + current.lines->len > 0) { + snprintf(str, size, "%s: %s - %s", + _("Lyrics"), + current.artist, current.title); + return str; + } else + return _("Lyrics"); } -static void -lyrics_paint(screen_t *screen, mpdclient_t *c) +static void +lyrics_paint(void) { - lw->clear = 1; - list_window_paint(lw, list_callback, NULL); - wrefresh(lw->w); + list_window_paint(lw, list_callback, NULL); } -static void -lyrics_update(screen_t *screen, mpdclient_t *c) -{ - if( lw->repaint ) - { - list_window_paint(lw, list_callback, NULL); - wrefresh(lw->w); - lw->repaint = 0; - } -} +static int +lyrics_cmd(mpdclient_t *c, command_t cmd) +{ + if (list_window_scroll_cmd(lw, current.lines->len, cmd)) { + lyrics_repaint(); + return 1; + } + switch(cmd) { + case CMD_INTERRUPT: + if (current.loader != NULL) { + screen_lyrics_abort(); + screen_lyrics_clear(); + } + return 1; + case CMD_ADD: + if (current.loader == NULL && current.artist != NULL && + current.title != NULL && store_lyr_hd() == 0) + screen_status_message (_("Lyrics saved!")); + return 1; + case CMD_LYRICS_UPDATE: + if (c->song != NULL) { + screen_lyrics_load(c->song); + lyrics_repaint(); + } + return 1; + + case CMD_LOCATE: + if (current.song != NULL) { + screen_file_goto_song(c, current.song); + return true; + } + + return false; -static int -lyrics_cmd(screen_t *screen, mpdclient_t *c, command_t cmd) -{ - lw->repaint=1; - switch(cmd) - { - case CMD_LIST_NEXT: - if( lw->start+lw->rows < lyr_text.lines->len+1 ) - lw->start++; - return 1; - case CMD_LIST_PREVIOUS: - if( lw->start >0 ) - lw->start--; - return 1; - case CMD_LIST_FIRST: - lw->start = 0; - return 1; - case CMD_LIST_LAST: - lw->start = lyrics_text_rows-lw->rows; - if( lw->start<0 ) - lw->start = 0; - return 1; - case CMD_LIST_NEXT_PAGE: - lw->start = lw->start + lw->rows-1; - if( lw->start+lw->rows >= lyr_text.lines->len+1 ) - lw->start = lyr_text.lines->len-lw->rows+1; - if( lw->start<0 ) - lw->start = 0; - return 1; - case CMD_LIST_PREVIOUS_PAGE: - lw->start = lw->start - lw->rows; - if( lw->start<0 ) - lw->start = 0; - return 1; - case CMD_SELECT: - g_thread_create(get_lyr, c, FALSE, NULL); - return 1; default: - break; - } - - lw->selected = lw->start+lw->rows; - if( screen_find(screen, c, - lw, lyrics_text_rows, - cmd, list_callback, NULL) ) - { - /* center the row */ - lw->start = lw->selected-(lw->rows/2); - if( lw->start+lw->rows > lyrics_text_rows ) - lw->start = lyrics_text_rows-lw->rows; - if( lw->start<0 ) - lw->start=0; - return 1; - } - - return 0; -} + break; + } -static list_window_t * -lyrics_lw(void) -{ - return lw; + lw->selected = lw->start+lw->rows; + if (screen_find(lw, current.lines->len, + cmd, list_callback, NULL)) { + /* center the row */ + list_window_center(lw, current.lines->len, lw->selected); + lyrics_repaint(); + return 1; + } + + return 0; } -screen_functions_t * -get_screen_lyrics(void) +const struct screen_functions screen_lyrics = { + .init = lyrics_screen_init, + .exit = lyrics_exit, + .open = lyrics_open, + .close = NULL, + .resize = lyrics_resize, + .paint = lyrics_paint, + .cmd = lyrics_cmd, + .get_title = lyrics_title, +}; + +void +screen_lyrics_switch(struct mpdclient *c, const struct mpd_song *song) { - static screen_functions_t functions; - - memset(&functions, 0, sizeof(screen_functions_t)); - functions.init = lyrics_init; - functions.exit = lyrics_exit; - functions.open = NULL; - functions.close = NULL; - functions.resize = lyrics_resize; - functions.paint = lyrics_paint; - functions.update = lyrics_update; - functions.cmd = lyrics_cmd; - functions.get_lw = lyrics_lw; - functions.get_title = lyrics_title; - - return &functions; + assert(song != NULL); + + next_song = song; + screen_switch(&screen_lyrics, c); } -#endif /* ENABLE_LYRICS_SCREEN */