Code

Display stream names in the list window.
[ncmpc.git] / src / mpc.c
1 /* 
2  * $Id$
3  *
4  * (c) 2004 by Kalle Wallin <kaw@linux.se>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <time.h>
25 #include <string.h>
26 #include <glib.h>
28 #include "config.h"
29 #include "ncmpc.h"
30 #include "support.h"
31 #include "libmpdclient.h"
32 #include "mpc.h"
33 #include "options.h"
35 #define MAX_SONG_LENGTH 1024
37 int 
38 mpc_close(mpd_client_t *c)
39 {
40   if( c->connection )
41     mpd_closeConnection(c->connection);
42   if( c->cwd )
43     g_free( c->cwd );
44   
45   return 0;
46 }
48 mpd_client_t *
49 mpc_connect(char *host, int port, char *password)
50 {
51   mpd_Connection *connection;
52   mpd_client_t *c;
54   connection =  mpd_newConnection(host, port, 10);
55   if( connection==NULL )
56     {
57       fprintf(stderr, "mpd_newConnection to %s:%d failed!\n", host, port);
58       exit(EXIT_FAILURE);
59     }
60   
61   c = g_malloc(sizeof(mpd_client_t));
62   memset(c, 0, sizeof(mpd_client_t));
63   c->connection = connection;
64   c->cwd = g_strdup("");
66   if( password )
67     {
68       mpd_sendPasswordCommand(connection, password);
69       mpd_finishCommand(connection);
70     }
72   return c;
73 }
75 int
76 mpc_reconnect(mpd_client_t *c, char *host, int port, char *password)
77 {
78   mpd_Connection *connection;
80   connection =  mpd_newConnection(host, port, 10);
81   if( connection==NULL )
82     return -1;
83   if( connection->error )
84     {
85       mpd_closeConnection(connection);
86       return -1;
87     }
88   
89   c->connection = connection;
91   if( password )
92     {
93       mpd_sendPasswordCommand(connection, password);
94       mpd_finishCommand(connection);
95     }
97   return 0;
98 }
101 int
102 mpc_error(mpd_client_t *c)
104   if( c == NULL || c->connection == NULL )
105     return 1;
106   if( c->connection->error )
107     return c->connection->error;
109   return 0;
112 char *
113 mpc_error_str(mpd_client_t *c)
115   if( c == NULL || c->connection == NULL )
116     return "Not connected";
118   if( c->connection && c->connection->errorStr )
119     return c->connection->errorStr;
121   return NULL;
126 int
127 mpc_free_playlist(mpd_client_t *c)
129   GList *list;
131   if( c==NULL || c->playlist==NULL )
132     return -1;
134   list=g_list_first(c->playlist);
136   while( list!=NULL )
137     {
138       mpd_Song *song = (mpd_Song *) list->data;
140       mpd_freeSong(song);
141       list=list->next;
142     }
143   g_list_free(c->playlist);
144   c->playlist=NULL;
145   c->playlist_length=0;
147   c->song_id = -1;
148   c->song = NULL;
150   return 0;
153 int 
154 mpc_get_playlist(mpd_client_t *c)
156   mpd_InfoEntity *entity;
158   D(fprintf(stderr, "mpc_get_playlist() [%lld]\n", c->status->playlist));
160   if( mpc_error(c) )
161     return -1;
163   if( c->playlist )
164     mpc_free_playlist(c);
166   c->playlist_length=0;
167   mpd_sendPlaylistInfoCommand(c->connection,-1);
168   if( mpc_error(c) )
169     return -1;
170   while( (entity=mpd_getNextInfoEntity(c->connection)) ) 
171     {
172       if(entity->type==MPD_INFO_ENTITY_TYPE_SONG) 
173         {
174           mpd_Song *song = mpd_songDup(entity->info.song);
176           c->playlist = g_list_append(c->playlist, (gpointer) song);
177           c->playlist_length++;
178         }
179       mpd_freeInfoEntity(entity);
180     }
181   mpd_finishCommand(c->connection);
182   c->playlist_id = c->status->playlist;
183   c->playlist_updated = 1;
184   c->song_id = -1;
185   c->song = NULL;
187   mpc_filelist_set_selected(c);
189   return 0;
192 int 
193 mpc_update_playlist(mpd_client_t *c)
195   mpd_InfoEntity *entity;
197   D(fprintf(stderr, "mpc_update_playlist() [%lld]\n", c->status->playlist));
199   if( mpc_error(c) )
200     return -1;
202   mpd_sendPlChangesCommand(c->connection, c->playlist_id);
203   if( mpc_error(c) )
204     return -1;
205   if( (entity=mpd_getNextInfoEntity(c->connection)) == NULL )
206     return mpc_get_playlist(c);
207   while( entity ) 
208     {
209       if(entity->type==MPD_INFO_ENTITY_TYPE_SONG) 
210         {
211           mpd_Song *song;
212           GList *item;
214           if( (song=mpd_songDup(entity->info.song)) == NULL )
215             return mpc_get_playlist(c);
217           item =  g_list_nth(c->playlist, song->num);
218           if( item && item->data)
219             {
220               mpd_freeSong((mpd_Song *) item->data);
221               item->data = song;
222               if( c->song_id == song->num )
223                 c->song = song;
224               D(fprintf(stderr, "Changing num %d to %s\n",
225                         song->num, mpc_get_song_name(song)));
226             }
227           else
228             {
229               D(fprintf(stderr, "Adding num %d - %s\n",
230                         song->num, mpc_get_song_name(song)));
231               c->playlist = g_list_append(c->playlist, 
232                                           (gpointer) song);
233               c->playlist_length++;
234             }
235         }
236       mpd_freeInfoEntity(entity);
237       entity=mpd_getNextInfoEntity(c->connection);
238     }
239   mpd_finishCommand(c->connection);
241   c->playlist_id = c->status->playlist;
242   c->playlist_updated = 1;
243   mpc_filelist_set_selected(c);
245   return 0;
248 int
249 mpc_playlist_get_song_index(mpd_client_t *c, char *filename)
251   GList *list = c->playlist;
252   int i=0;
254   while( list )
255     {
256       mpd_Song *song = (mpd_Song *) list->data;
257       if( strcmp(song->file, filename ) == 0 )  
258         return i;
259       list=list->next;
260       i++;
261     }
262   return -1;
265 mpd_Song *
266 mpc_playlist_get_song(mpd_client_t *c, int n)
268   return (mpd_Song *) g_list_nth_data(c->playlist, n);
272 char *
273 mpc_get_song_name(mpd_Song *song)
275   static char buf[MAX_SONG_LENGTH];
276   char *name;
277   
278   if( song->title )
279     {
280       if( song->artist )
281         {
282           snprintf(buf, MAX_SONG_LENGTH, "%s - %s", song->artist, song->title);
283           name = utf8_to_locale(buf);
284           strncpy(buf, name, MAX_SONG_LENGTH);
285           g_free(name);
286           return buf;
287         }
288       else
289         {
290           name = utf8_to_locale(song->title);
291           strncpy(buf, name, MAX_SONG_LENGTH);
292           g_free(name);
293           return buf;
294         }
295     }
296   name = utf8_to_locale(basename(song->file));
297   strncpy(buf, name, MAX_SONG_LENGTH);
298   g_free(name);
299   return buf;
302 char *
303 mpc_get_song_name2(mpd_Song *song)
305   static char buf[MAX_SONG_LENGTH];
306   char *name;
307   
308   if( song->name )
309     {
310       name = utf8_to_locale(song->name);
311       strncpy(buf, name, MAX_SONG_LENGTH);
312       g_free(name);
313       return buf;
314     }
316   if( song->title )
317     {      
318       if( song->artist )
319         {
320           snprintf(buf, MAX_SONG_LENGTH, "%s - %s", song->artist, song->title);
321           name = utf8_to_locale(buf);
322           strncpy(buf, name, MAX_SONG_LENGTH);
323           g_free(name);
324           return buf;
325         }
326       else
327         {
328           name = utf8_to_locale(song->title);
329           strncpy(buf, name, MAX_SONG_LENGTH);
330           g_free(name);
331           return buf;
332         }
333     }
334   name = utf8_to_locale(basename(song->file));
335   strncpy(buf, name, MAX_SONG_LENGTH);
336   g_free(name);
337   return buf;
340 #if 0
341 size_t
342 strfsong(char *s, size_t max, const char *format, mpd_Song *song)
344   size_t i, len, format_len;
345   char prev;
347   void sappend(char *utfstr) {
348     char *tmp = utf8_to_locale(utfstr);
349     size_t tmplen = strlen(tmp);
350     if( i+tmplen < max )
351       strcat(s, tmp);
352     else
353       strncat(s, tmp, max-i);
354     i = strlen(s);
355     g_free(tmp);
356   }
358   i = 0;
359   len = 0;
360   format_len = strlen(format);
361   memset(s, 0, max);
362   while(i<format_len && len<max)
363     {
364       if( i>0 && format[i-1]=='%' )
365         {
366           char *tmp;
367           size_t tmplen;
369           switch(format[i])
370             {
371             case '%':
372               s[len++] = format[i];
373               break;
374             case 'a':
375               sappend(song->artist);
376               break;
377             case 't':
378               sappend(song->title);
379               break;
380             case 'n':
381               sappend(song->name);
382               break;
383             case 'f':
384               sappend(song->file);
385               break;
386             }
387         }
388       else if( format[i]!='%' )
389         {
390           s[len] = format[i++];
391         }
392       len++;
393     }
395   return len;
397 #endif
400 int 
401 mpc_update(mpd_client_t *c)
403   if( mpc_error(c) )
404     return -1;
406   if( c->status )
407     {
408       mpd_freeStatus(c->status);
409     }
411   c->status = mpd_getStatus(c->connection);
412   if( mpc_error(c) )
413     return -1;
415   if( c->playlist_id!=c->status->playlist )
416     {
417       if( c->playlist_length<2 )
418         mpc_get_playlist(c);
419       else
420         mpc_update_playlist(c);
421     }
422   
423   if( !c->song || c->status->song != c->song_id )
424     {
425       c->song = mpc_playlist_get_song(c, c->status->song);
426       c->song_id = c->status->song;
427       c->song_updated = 1;
428     }
430   return 0;
438 int
439 mpc_free_filelist(mpd_client_t *c)
441   GList *list;
443   if( c==NULL || c->filelist==NULL )
444     return -1;
446   list=g_list_first(c->filelist);
448   while( list!=NULL )
449     {
450       filelist_entry_t *entry = list->data;
452       if( entry->entity )
453         mpd_freeInfoEntity(entry->entity);
454       g_free(entry);
455       list=list->next;
456     }
457   g_list_free(c->filelist);
458   c->filelist=NULL;
459   c->filelist_length=0;
461   return 0;
466 int 
467 mpc_update_filelist(mpd_client_t *c)
469   mpd_InfoEntity *entity;
471   if( mpc_error(c) )
472     return -1;
474   if( c->filelist )
475     mpc_free_filelist(c);
477   c->filelist_length=0;
479   //  mpd_sendListallCommand(conn,"");
480   mpd_sendLsInfoCommand(c->connection, c->cwd);
482   if( c->cwd && c->cwd[0] )
483     {
484       /* add a dummy entry for ./.. */
485       filelist_entry_t *entry = g_malloc(sizeof(filelist_entry_t));
486       memset(entry, 0, sizeof(filelist_entry_t));
487       entry->entity = NULL;
488       c->filelist = g_list_append(c->filelist, (gpointer) entry);
489       c->filelist_length++;
490     }
492   while( (entity=mpd_getNextInfoEntity(c->connection)) ) 
493     {
494       filelist_entry_t *entry = g_malloc(sizeof(filelist_entry_t));
495       
496       memset(entry, 0, sizeof(filelist_entry_t));
497       entry->entity = entity;
498       c->filelist = g_list_append(c->filelist, (gpointer) entry);
499       c->filelist_length++;
500     }
501   
502   c->filelist_updated = 1;
504   mpd_finishCommand(c->connection);
506   mpc_filelist_set_selected(c);
508   return 0;
511 int 
512 mpc_filelist_set_selected(mpd_client_t *c)
514   GList *list = c->filelist;
516   while( list )
517     {
518       filelist_entry_t *entry = list->data;
519       mpd_InfoEntity *entity = entry->entity ;      
520       
521       if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG )
522         {
523           mpd_Song *song = entity->info.song;
525           if( mpc_playlist_get_song_index(c, song->file) >= 0 )
526             entry->selected = 1;
527           else
528             entry->selected = 0;
529         }
531       list=list->next;
532     }
533   return 0;