9b70a76bd3b82d55a45b0f5e5dae9e26ae2e3ff2
1 /*
2 * (c) 2006 by Kalle Wallin <kaw@linux.se>
3 * Copyright (C) 2008 Max Kellermann <max@duempel.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 */
20 #include <sys/stat.h>
21 #include "i18n.h"
22 #include "options.h"
23 #include "mpdclient.h"
24 #include "command.h"
25 #include "screen.h"
26 #include "screen_utils.h"
27 #include "strfsong.h"
28 #include "lyrics.h"
29 #include "charset.h"
31 #include <stdlib.h>
32 #include <string.h>
33 #include <glib.h>
34 #include <unistd.h>
35 #include <stdio.h>
37 static list_window_t *lw = NULL;
39 static const struct mpd_song *next_song;
41 static struct {
42 struct mpd_song *song;
44 char *artist, *title;
46 struct plugin_cycle *loader;
48 GPtrArray *lines;
49 } current;
51 static void
52 screen_lyrics_abort(void)
53 {
54 if (current.loader != NULL) {
55 plugin_stop(current.loader);
56 current.loader = NULL;
57 }
59 if (current.artist != NULL) {
60 g_free(current.artist);
61 current.artist = NULL;
62 }
64 if (current.title != NULL) {
65 g_free(current.title);
66 current.artist = NULL;
67 }
69 if (current.song != NULL) {
70 mpd_freeSong(current.song);
71 current.song = NULL;
72 }
73 }
75 static void
76 screen_lyrics_clear(void)
77 {
78 guint i;
80 list_window_reset(lw);
82 for (i = 0; i < current.lines->len; ++i)
83 g_free(g_ptr_array_index(current.lines, i));
85 g_ptr_array_set_size(current.lines, 0);
86 }
88 static void
89 lyrics_paint(void);
91 /**
92 * Repaint and update the screen.
93 */
94 static void
95 lyrics_repaint(void)
96 {
97 lyrics_paint();
98 wrefresh(lw->w);
99 }
101 /**
102 * Repaint and update the screen, if it is currently active.
103 */
104 static void
105 lyrics_repaint_if_active(void)
106 {
107 if (screen_is_visible(&screen_lyrics)) {
108 lyrics_repaint();
110 /* XXX repaint the screen title */
111 }
112 }
114 static void
115 screen_lyrics_set(const GString *str)
116 {
117 const char *p, *eol, *next;
119 screen_lyrics_clear();
121 p = str->str;
122 while ((eol = strchr(p, '\n')) != NULL) {
123 char *line;
125 next = eol + 1;
127 /* strip whitespace at end */
129 while (eol > p && (unsigned char)eol[-1] <= 0x20)
130 --eol;
132 /* create copy and append it to current.lines*/
134 line = g_malloc(eol - p + 1);
135 memcpy(line, p, eol - p);
136 line[eol - p] = 0;
138 g_ptr_array_add(current.lines, line);
140 /* reset control characters */
142 for (eol = line + (eol - p); line < eol; ++line)
143 if ((unsigned char)*line < 0x20)
144 *line = ' ';
146 p = next;
147 }
149 if (*p != 0)
150 g_ptr_array_add(current.lines, g_strdup(p));
152 /* paint new data */
154 lyrics_repaint_if_active();
155 }
157 static void
158 screen_lyrics_callback(const GString *result, G_GNUC_UNUSED void *data)
159 {
160 assert(current.loader != NULL);
162 if (result != NULL)
163 screen_lyrics_set(result);
164 else
165 screen_status_message (_("No lyrics"));
167 plugin_stop(current.loader);
168 current.loader = NULL;
169 }
171 static void
172 screen_lyrics_load(const struct mpd_song *song)
173 {
174 char buffer[MAX_SONGNAME_LENGTH];
176 assert(song != NULL);
178 screen_lyrics_abort();
179 screen_lyrics_clear();
181 current.song = mpd_songDup(song);
183 strfsong(buffer, sizeof(buffer), "%artist%", song);
184 current.artist = g_strdup(buffer);
186 strfsong(buffer, sizeof(buffer), "%title%", song);
187 current.title = g_strdup(buffer);
189 current.loader = lyrics_load(current.artist, current.title,
190 screen_lyrics_callback, NULL);
191 }
193 static FILE *create_lyr_file(const char *artist, const char *title)
194 {
195 char path[1024];
197 snprintf(path, 1024, "%s/.lyrics",
198 getenv("HOME"));
199 mkdir(path, S_IRWXU);
201 snprintf(path, 1024, "%s/.lyrics/%s - %s.txt",
202 getenv("HOME"), artist, title);
204 return fopen(path, "w");
205 }
207 static int store_lyr_hd(void)
208 {
209 FILE *lyr_file;
210 unsigned i;
212 lyr_file = create_lyr_file(current.artist, current.title);
213 if (lyr_file == NULL)
214 return -1;
216 for (i = 0; i < current.lines->len; ++i)
217 fprintf(lyr_file, "%s\n",
218 (const char*)g_ptr_array_index(current.lines, i));
220 fclose(lyr_file);
221 return 0;
222 }
224 static const char *
225 list_callback(unsigned idx, G_GNUC_UNUSED bool *highlight,
226 G_GNUC_UNUSED void *data)
227 {
228 static char buffer[256];
229 char *value;
231 if (idx >= current.lines->len)
232 return NULL;
234 value = utf8_to_locale(g_ptr_array_index(current.lines, idx));
235 g_strlcpy(buffer, value, sizeof(buffer));
236 free(value);
238 return buffer;
239 }
242 static void
243 lyrics_screen_init(WINDOW *w, int cols, int rows)
244 {
245 current.lines = g_ptr_array_new();
246 lw = list_window_init(w, cols, rows);
247 lw->hide_cursor = true;
248 }
250 static void
251 lyrics_resize(int cols, int rows)
252 {
253 lw->cols = cols;
254 lw->rows = rows;
255 }
257 static void
258 lyrics_exit(void)
259 {
260 list_window_free(lw);
262 screen_lyrics_abort();
263 screen_lyrics_clear();
265 g_ptr_array_free(current.lines, TRUE);
266 current.lines = NULL;
267 }
269 static void
270 lyrics_open(mpdclient_t *c)
271 {
272 if (next_song == NULL)
273 next_song = c->song;
275 if (next_song != NULL &&
276 (current.song == NULL ||
277 strcmp(next_song->file, current.song->file) != 0))
278 screen_lyrics_load(next_song);
280 next_song = NULL;
281 }
284 static const char *
285 lyrics_title(char *str, size_t size)
286 {
287 if (current.loader != NULL) {
288 snprintf(str, size, "%s (%s)",
289 _("Lyrics"), _("loading..."));
290 return str;
291 } else if (current.artist != NULL && current.title != NULL &&
292 current.lines->len > 0) {
293 snprintf(str, size, "%s: %s - %s",
294 _("Lyrics"),
295 current.artist, current.title);
296 return str;
297 } else
298 return _("Lyrics");
299 }
301 static void
302 lyrics_paint(void)
303 {
304 list_window_paint(lw, list_callback, NULL);
305 }
307 static bool
308 lyrics_cmd(mpdclient_t *c, command_t cmd)
309 {
310 if (list_window_scroll_cmd(lw, current.lines->len, cmd)) {
311 lyrics_repaint();
312 return true;
313 }
315 switch(cmd) {
316 case CMD_INTERRUPT:
317 if (current.loader != NULL) {
318 screen_lyrics_abort();
319 screen_lyrics_clear();
320 }
321 return true;
322 case CMD_ADD:
323 if (current.loader == NULL && current.artist != NULL &&
324 current.title != NULL && store_lyr_hd() == 0)
325 screen_status_message (_("Lyrics saved"));
326 return true;
327 case CMD_LYRICS_UPDATE:
328 if (c->song != NULL) {
329 screen_lyrics_load(c->song);
330 lyrics_repaint();
331 }
332 return true;
334 #ifdef ENABLE_SONG_SCREEN
335 case CMD_VIEW:
336 if (current.song != NULL) {
337 screen_song_switch(c, current.song);
338 return true;
339 }
341 break;
342 #endif
344 case CMD_LOCATE:
345 if (current.song != NULL) {
346 screen_file_goto_song(c, current.song);
347 return true;
348 }
350 return false;
352 default:
353 break;
354 }
356 lw->selected = lw->start+lw->rows;
357 if (screen_find(lw, current.lines->len,
358 cmd, list_callback, NULL)) {
359 /* center the row */
360 list_window_center(lw, current.lines->len, lw->selected);
361 lyrics_repaint();
362 return true;
363 }
365 return false;
366 }
368 const struct screen_functions screen_lyrics = {
369 .init = lyrics_screen_init,
370 .exit = lyrics_exit,
371 .open = lyrics_open,
372 .close = NULL,
373 .resize = lyrics_resize,
374 .paint = lyrics_paint,
375 .cmd = lyrics_cmd,
376 .get_title = lyrics_title,
377 };
379 void
380 screen_lyrics_switch(struct mpdclient *c, const struct mpd_song *song)
381 {
382 assert(song != NULL);
384 next_song = song;
385 screen_switch(&screen_lyrics, c);
386 }