885a35a766c843eac8aa3878e19f41b5b2288b49
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 "config.h"
21 #ifndef DISABLE_LYRICS_SCREEN
22 #include <sys/stat.h>
23 #include "ncmpc.h"
24 #include "options.h"
25 #include "mpdclient.h"
26 #include "command.h"
27 #include "screen.h"
28 #include "screen_utils.h"
29 #include "strfsong.h"
30 #include "lyrics.h"
31 #include "gcc.h"
33 #define _GNU_SOURCE
34 #include <stdlib.h>
35 #include <string.h>
36 #include <glib.h>
37 #include <ncurses.h>
38 #include <unistd.h>
39 #include <stdio.h>
41 static list_window_t *lw = NULL;
42 static int lyrics_text_rows = -1;
44 static struct {
45 const struct mpd_song *song;
47 char *artist, *title;
49 struct lyrics_loader *loader;
51 GPtrArray *lines;
52 } current;
54 static void
55 screen_lyrics_abort(void)
56 {
57 if (current.loader != NULL) {
58 lyrics_free(current.loader);
59 current.loader = NULL;
60 }
62 if (current.artist != NULL) {
63 g_free(current.artist);
64 current.artist = NULL;
65 }
67 if (current.title != NULL) {
68 g_free(current.title);
69 current.artist = NULL;
70 }
72 current.song = NULL;
73 }
75 static void
76 screen_lyrics_clear(void)
77 {
78 guint i;
80 assert(current.loader == NULL ||
81 lyrics_result(current.loader) == LYRICS_SUCCESS);
83 current.song = NULL;
85 for (i = 0; i < current.lines->len; ++i)
86 g_free(g_ptr_array_index(current.lines, i));
88 g_ptr_array_set_size(current.lines, 0);
89 }
91 static void
92 screen_lyrics_set(const GString *str)
93 {
94 const char *p, *eol, *next;
96 screen_lyrics_clear();
98 p = str->str;
99 while ((eol = strchr(p, '\n')) != NULL) {
100 char *line;
102 next = eol + 1;
104 /* strip whitespace at end */
106 while (eol > p && (unsigned char)eol[-1] <= 0x20)
107 --eol;
109 /* create copy and append it to current.lines*/
111 line = g_malloc(eol - p + 1);
112 memcpy(line, p, eol - p);
113 line[eol - p] = 0;
115 g_ptr_array_add(current.lines, line);
117 /* reset control characters */
119 for (eol = line + (eol - p); line < eol; ++line)
120 if ((unsigned char)*line < 0x20)
121 *line = ' ';
123 p = next;
124 }
126 if (*p != 0)
127 g_ptr_array_add(current.lines, g_strdup(p));
128 }
130 static int
131 screen_lyrics_poll(void)
132 {
133 assert(current.loader != NULL);
135 switch (lyrics_result(current.loader)) {
136 case LYRICS_BUSY:
137 return 0;
139 case LYRICS_SUCCESS:
140 screen_lyrics_set(lyrics_get(current.loader));
141 lyrics_free(current.loader);
142 current.loader = NULL;
143 return 1;
145 case LYRICS_FAILED:
146 lyrics_free(current.loader);
147 current.loader = NULL;
148 screen_status_message (_("No lyrics"));
149 return -1;
150 }
152 assert(0);
153 return -1;
154 }
156 static void
157 screen_lyrics_load(struct mpd_song *song)
158 {
159 char buffer[MAX_SONGNAME_LENGTH];
161 assert(song != NULL);
163 screen_lyrics_abort();
164 screen_lyrics_clear();
166 strfsong(buffer, sizeof(buffer), "%artist%", song);
167 current.artist = g_strdup(buffer);
169 strfsong(buffer, sizeof(buffer), "%title%", song);
170 current.title = g_strdup(buffer);
172 current.loader = lyrics_load(current.artist, current.title);
173 }
175 static void lyrics_paint(screen_t *screen, mpdclient_t *c);
177 static FILE *create_lyr_file(const char *artist, const char *title)
178 {
179 char path[1024];
181 snprintf(path, 1024, "%s/.lyrics",
182 getenv("HOME"));
183 mkdir(path, S_IRWXU);
185 snprintf(path, 1024, "%s/.lyrics/%s - %s.txt",
186 getenv("HOME"), artist, title);
188 return fopen(path, "w");
189 }
191 static int store_lyr_hd(void)
192 {
193 FILE *lyr_file;
194 unsigned i;
196 lyr_file = create_lyr_file(current.artist, current.title);
197 if (lyr_file == NULL)
198 return -1;
200 for (i = 0; i < current.lines->len; ++i)
201 fprintf(lyr_file, "%s\n",
202 (const char*)g_ptr_array_index(current.lines, i));
204 fclose(lyr_file);
205 return 0;
206 }
208 static const char *
209 list_callback(unsigned idx, mpd_unused int *highlight, mpd_unused void *data)
210 {
211 if (current.lines == NULL || idx >= current.lines->len)
212 return "";
214 return g_ptr_array_index(current.lines, idx);
215 }
218 static void
219 lyrics_screen_init(WINDOW *w, int cols, int rows)
220 {
221 current.lines = g_ptr_array_new();
222 lw = list_window_init(w, cols, rows);
223 lw->flags = LW_HIDE_CURSOR;
224 }
226 static void
227 lyrics_resize(int cols, int rows)
228 {
229 lw->cols = cols;
230 lw->rows = rows;
231 }
233 static void
234 lyrics_exit(void)
235 {
236 list_window_free(lw);
238 screen_lyrics_abort();
239 screen_lyrics_clear();
241 g_ptr_array_free(current.lines, TRUE);
242 current.lines = NULL;
243 }
245 static void
246 lyrics_open(mpd_unused screen_t *screen, mpdclient_t *c)
247 {
248 if (c->song != NULL && c->song != current.song)
249 screen_lyrics_load(c->song);
250 else if (current.loader != NULL)
251 screen_lyrics_poll();
252 }
255 static const char *
256 lyrics_title(char *str, size_t size)
257 {
258 if (current.loader != NULL)
259 return "Lyrics (loading)";
260 else if (current.artist != NULL && current.title != NULL &&
261 current.lines->len > 0) {
262 snprintf(str, size, "Lyrics: %s - %s",
263 current.artist, current.title);
264 return str;
265 } else
266 return "Lyrics";
267 }
269 static void
270 lyrics_paint(mpd_unused screen_t *screen, mpd_unused mpdclient_t *c)
271 {
272 lw->clear = 1;
273 list_window_paint(lw, list_callback, NULL);
274 wrefresh(lw->w);
275 }
278 static void
279 lyrics_update(mpd_unused screen_t *screen, mpd_unused mpdclient_t *c)
280 {
281 if( lw->repaint ) {
282 list_window_paint(lw, list_callback, NULL);
283 wrefresh(lw->w);
284 lw->repaint = 0;
285 }
286 }
289 static int
290 lyrics_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
291 {
292 lw->repaint=1;
293 switch(cmd) {
294 case CMD_LIST_NEXT:
295 if (current.lines != NULL && lw->start+lw->rows < current.lines->len+1)
296 lw->start++;
297 return 1;
298 case CMD_LIST_PREVIOUS:
299 if( lw->start >0 )
300 lw->start--;
301 return 1;
302 case CMD_LIST_FIRST:
303 lw->start = 0;
304 return 1;
305 case CMD_LIST_LAST:
306 if ((unsigned)lyrics_text_rows > lw->rows)
307 lw->start = lyrics_text_rows - lw->rows;
308 else
309 lw->start = 0;
310 return 1;
311 case CMD_LIST_NEXT_PAGE:
312 lw->start = lw->start + lw->rows - 1;
313 if (lw->start + lw->rows >= (unsigned)lyrics_text_rows + 1) {
314 if ((unsigned)lyrics_text_rows + 1 > lw->rows)
315 lw->start = lyrics_text_rows + 1 - lw->rows;
316 else
317 lw->start = 0;
318 }
319 return 1;
320 case CMD_LIST_PREVIOUS_PAGE:
321 if (lw->start > lw->rows)
322 lw->start -= lw->rows;
323 else
324 lw->start = 0;
325 return 1;
326 case CMD_SELECT:
327 /* XXX */
328 if (current.loader != NULL) {
329 int ret = screen_lyrics_poll();
330 if (ret != 0)
331 lyrics_paint(NULL, NULL);
332 }
333 return 1;
334 case CMD_INTERRUPT:
335 if (current.loader != NULL) {
336 screen_lyrics_abort();
337 screen_lyrics_clear();
338 }
339 return 1;
340 case CMD_ADD:
341 if (current.loader == NULL && current.artist != NULL &&
342 current.title != NULL && store_lyr_hd() == 0)
343 screen_status_message (_("Lyrics saved!"));
344 return 1;
345 case CMD_LYRICS_UPDATE:
346 if (c->song != NULL) {
347 screen_lyrics_load(c->song);
348 lyrics_paint(NULL, NULL);
349 }
350 return 1;
351 default:
352 break;
353 }
355 lw->selected = lw->start+lw->rows;
356 if (screen_find(screen,
357 lw, lyrics_text_rows,
358 cmd, list_callback, NULL)) {
359 /* center the row */
360 lw->start = lw->selected - (lw->rows / 2);
361 if (lw->start + lw->rows > (unsigned)lyrics_text_rows) {
362 if (lw->rows < (unsigned)lyrics_text_rows)
363 lw->start = lyrics_text_rows - lw->rows;
364 else
365 lw->start = 0;
366 }
367 return 1;
368 }
370 return 0;
371 }
373 static list_window_t *
374 lyrics_lw(void)
375 {
376 return lw;
377 }
379 const struct screen_functions screen_lyrics = {
380 .init = lyrics_screen_init,
381 .exit = lyrics_exit,
382 .open = lyrics_open,
383 .close = NULL,
384 .resize = lyrics_resize,
385 .paint = lyrics_paint,
386 .update = lyrics_update,
387 .cmd = lyrics_cmd,
388 .get_lw = lyrics_lw,
389 .get_title = lyrics_title,
390 };
392 #endif /* ENABLE_LYRICS_SCREEN */