Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

b4s.c

00001 /*****************************************************************************
00002  * b4s.c : B4S playlist format import
00003  *****************************************************************************
00004  * Copyright (C) 2005 the VideoLAN team
00005  * $Id: b4s.c 12836 2005-10-15 13:23:08Z sigmunau $
00006  *
00007  * Authors: Sigmund Augdal Helberg <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 /*****************************************************************************
00025  * Preamble
00026  *****************************************************************************/
00027 #include <stdlib.h>                                      /* malloc(), free() */
00028 #include <ctype.h>                                              /* isspace() */
00029 
00030 #include <vlc/vlc.h>
00031 #include <vlc/input.h>
00032 #include <vlc/intf.h>
00033 
00034 #include <errno.h>                                                 /* ENOMEM */
00035 #include "playlist.h"
00036 #include "vlc_xml.h"
00037 
00038 struct demux_sys_t
00039 {
00040     char *psz_prefix;
00041     playlist_t *p_playlist;
00042     xml_t *p_xml;
00043     xml_reader_t *p_xml_reader;
00044     int b_shout;
00045 };
00046 
00047 /*****************************************************************************
00048  * Local prototypes
00049  *****************************************************************************/
00050 static int Demux( demux_t *p_demux);
00051 static int Control( demux_t *p_demux, int i_query, va_list args );
00052 static char *GetNextToken(char *psz_cur_string);
00053 static int IsWhitespace( char *psz_string );
00054 static void ShoutcastAdd( playlist_t *p_playlist, playlist_item_t* p_genre,
00055                           playlist_item_t *p_bitrate, playlist_item_t *p_item,
00056                           char *psz_genre, char *psz_bitrate );
00057 
00058 /*****************************************************************************
00059  * Import_B4S: main import function
00060  *****************************************************************************/
00061 int E_(Import_B4S)( vlc_object_t *p_this )
00062 {
00063     demux_t *p_demux = (demux_t *)p_this;
00064     demux_sys_t *p_sys;
00065 
00066     char    *psz_ext;
00067 
00068     psz_ext = strrchr ( p_demux->psz_path, '.' );
00069 
00070     if( ( psz_ext && !strcasecmp( psz_ext, ".b4s") ) ||
00071         ( p_demux->psz_demux && !strcmp(p_demux->psz_demux, "b4s-open") ) ||
00072         ( p_demux->psz_demux && !strcmp(p_demux->psz_demux, "shout-b4s") ) )
00073     {
00074         ;
00075     }
00076     else
00077     {
00078         return VLC_EGENERIC;
00079     }
00080     msg_Dbg( p_demux, "using b4s playlist import");
00081 
00082     p_demux->pf_control = Control;
00083     p_demux->pf_demux = Demux;
00084     p_demux->p_sys = p_sys = malloc( sizeof(demux_sys_t) );
00085     if( p_sys == NULL )
00086     {
00087         msg_Err( p_demux, "Out of memory" );
00088         return VLC_ENOMEM;
00089     }
00090     p_sys->b_shout = p_demux->psz_demux &&
00091         !strcmp(p_demux->psz_demux, "shout-b4s");
00092     p_sys->psz_prefix = E_(FindPrefix)( p_demux );
00093     p_sys->p_playlist = NULL;
00094     p_sys->p_xml = NULL;
00095     p_sys->p_xml_reader = NULL;
00096 
00097     return VLC_SUCCESS;
00098 }
00099 
00100 /*****************************************************************************
00101  * Deactivate: frees unused data
00102  *****************************************************************************/
00103 void E_(Close_B4S)( vlc_object_t *p_this )
00104 {
00105     demux_t *p_demux = (demux_t *)p_this;
00106     demux_sys_t *p_sys = p_demux->p_sys;
00107 
00108     if( p_sys->psz_prefix ) free( p_sys->psz_prefix );
00109     if( p_sys->p_playlist ) vlc_object_release( p_sys->p_playlist );
00110     if( p_sys->p_xml_reader ) xml_ReaderDelete( p_sys->p_xml, p_sys->p_xml_reader );
00111     if( p_sys->p_xml ) xml_Delete( p_sys->p_xml );
00112     free( p_sys );
00113 }
00114 
00115 static int Demux( demux_t *p_demux )
00116 {
00117     demux_sys_t *p_sys = p_demux->p_sys;
00118     playlist_t *p_playlist;
00119     playlist_item_t *p_item, *p_current;
00120     playlist_item_t *p_bitrate = NULL, *p_genre = NULL;
00121 
00122     vlc_bool_t b_play;
00123     int i_ret;
00124 
00125     xml_t *p_xml;
00126     xml_reader_t *p_xml_reader;
00127     char *psz_elname = NULL;
00128     int i_type, b_shoutcast;
00129     char *psz_mrl = NULL, *psz_name = NULL, *psz_genre = NULL;
00130     char *psz_now = NULL, *psz_listeners = NULL, *psz_bitrate = NULL;
00131 
00132 
00133     b_shoutcast = p_sys->b_shout;
00134 
00135     p_playlist = (playlist_t *) vlc_object_find( p_demux, VLC_OBJECT_PLAYLIST,
00136                                                  FIND_PARENT );
00137     if( !p_playlist )
00138     {
00139         msg_Err( p_demux, "can't find playlist" );
00140         return -1;
00141     }
00142     p_sys->p_playlist = p_playlist;
00143 
00144     b_play = E_(FindItem)( p_demux, p_playlist, &p_current );
00145 
00146     playlist_ItemToNode( p_playlist, p_current );
00147     p_current->input.i_type = ITEM_TYPE_PLAYLIST;
00148     if( b_shoutcast )
00149     {
00150         p_genre = playlist_NodeCreate( p_playlist, p_current->pp_parents[0]->i_view, "Genre", p_current );
00151         playlist_CopyParents( p_current, p_genre );
00152 
00153         p_bitrate = playlist_NodeCreate( p_playlist, p_current->pp_parents[0]->i_view, "Bitrate", p_current );
00154         playlist_CopyParents( p_current, p_bitrate );
00155     }
00156 
00157     p_xml = p_sys->p_xml = xml_Create( p_demux );
00158     if( !p_xml ) return -1;
00159 
00160     psz_elname = stream_ReadLine( p_demux->s );
00161     if( psz_elname ) free( psz_elname );
00162     psz_elname = 0;
00163 
00164     p_xml_reader = xml_ReaderCreate( p_xml, p_demux->s );
00165     if( !p_xml_reader ) return -1;
00166     p_sys->p_xml_reader = p_xml_reader;
00167 
00168     /* xml */
00169     /* check root node */
00170     if( xml_ReaderRead( p_xml_reader ) != 1 )
00171     {
00172         msg_Err( p_demux, "invalid file (no root node)" );
00173         return -1;
00174     }
00175 
00176     if( xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM ||
00177         ( psz_elname = xml_ReaderName( p_xml_reader ) ) == NULL ||
00178         strcmp( psz_elname, "WinampXML" ) )
00179     {
00180         msg_Err( p_demux, "invalid root node %i, %s",
00181                  xml_ReaderNodeType( p_xml_reader ), psz_elname );
00182         if( psz_elname ) free( psz_elname );
00183         return -1;
00184     }
00185     free( psz_elname );
00186 
00187     /* root node should not have any attributes, and should only
00188      * contain the "playlist node */
00189 
00190     /* Skip until 1st child node */
00191     while( (i_ret = xml_ReaderRead( p_xml_reader )) == 1 &&
00192            xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM );
00193     if( i_ret != 1 )
00194     {
00195         msg_Err( p_demux, "invalid file (no child node)" );
00196         return -1;
00197     }
00198 
00199     if( ( psz_elname = xml_ReaderName( p_xml_reader ) ) == NULL ||
00200         strcmp( psz_elname, "playlist" ) )
00201     {
00202         msg_Err( p_demux, "invalid child node %s", psz_elname );
00203         if( psz_elname ) free( psz_elname );
00204         return -1;
00205     }
00206     free( psz_elname ); psz_elname = 0;
00207 
00208     // Read the attributes
00209     while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
00210     {
00211         char *psz_name = xml_ReaderName( p_xml_reader );
00212         char *psz_value = xml_ReaderValue( p_xml_reader );
00213         if( !psz_name || !psz_value ) return -1;
00214         if( !strcmp( psz_name, "num_entries" ) )
00215         {
00216             msg_Dbg( p_demux, "playlist has %d entries", atoi(psz_value) );
00217         }
00218         else if( !strcmp( psz_name, "label" ) )
00219         {
00220             playlist_ItemSetName( p_current, psz_value );
00221         }
00222         else
00223         {
00224             msg_Warn( p_demux, "stray attribute %s with value %s in element"
00225                       " 'playlist'", psz_name, psz_value );
00226         }
00227         free( psz_name );
00228         free( psz_value );
00229     }
00230 
00231     while( (i_ret = xml_ReaderRead( p_xml_reader )) == 1 )
00232     {
00233         // Get the node type
00234         i_type = xml_ReaderNodeType( p_xml_reader );
00235         switch( i_type )
00236         {
00237             // Error
00238             case -1:
00239                 return -1;
00240                 break;
00241 
00242             case XML_READER_STARTELEM:
00243             {
00244                 // Read the element name
00245                 if( psz_elname ) free( psz_elname );
00246                 psz_elname = xml_ReaderName( p_xml_reader );
00247                 if( !psz_elname ) return -1;
00248 
00249 
00250                 // Read the attributes
00251                 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
00252                 {
00253                     char *psz_name = xml_ReaderName( p_xml_reader );
00254                     char *psz_value = xml_ReaderValue( p_xml_reader );
00255                     if( !psz_name || !psz_value ) return -1;
00256                     if( !strcmp( psz_elname, "entry" ) &&
00257                         !strcmp( psz_name, "Playstring" ) )
00258                     {
00259                         psz_mrl = strdup( psz_value );
00260                     }
00261                     else
00262                     {
00263                         msg_Warn( p_demux, "unexpected attribure %s in element %s",
00264                                   psz_name, psz_elname );
00265                     }
00266                     free( psz_name );
00267                     free( psz_value );
00268                 }
00269                 break;
00270             }
00271             case XML_READER_TEXT:
00272             {
00273                 char *psz_text = xml_ReaderValue( p_xml_reader );
00274                 if( IsWhitespace( psz_text ) )
00275                 {
00276                     free( psz_text );
00277                     break;
00278                 }
00279                 if( !strcmp( psz_elname, "Name" ) )
00280                 {
00281                     psz_name = strdup( psz_text );
00282                 }
00283                 else if( !strcmp( psz_elname, "Genre" ) )
00284                 {
00285                     psz_genre = strdup( psz_text );
00286                 }
00287                 else if( !strcmp( psz_elname, "Nowplaying" ) )
00288                 {
00289                     psz_now = strdup( psz_text );
00290                 }
00291                 else if( !strcmp( psz_elname, "Listeners" ) )
00292                 {
00293                     psz_listeners = strdup( psz_text );
00294                 }
00295                 else if( !strcmp( psz_elname, "Bitrate" ) )
00296                 {
00297                     psz_bitrate = strdup( psz_text );
00298                 }
00299                 else if( !strcmp( psz_elname, "" ) )
00300                 {
00301                     ;
00302                 }
00303                 else
00304                 {
00305                     msg_Warn( p_demux, "unexpected text in element '%s'",
00306                               psz_elname );
00307                 }
00308                 free( psz_text );
00309                 break;
00310             }
00311             // End element
00312             case XML_READER_ENDELEM:
00313             {
00314                 // Read the element name
00315                 free( psz_elname );
00316                 psz_elname = xml_ReaderName( p_xml_reader );
00317                 if( !psz_elname ) return -1;
00318                 if( !strcmp( psz_elname, "entry" ) )
00319                 {
00320                     p_item = playlist_ItemNew( p_playlist, psz_mrl, psz_name );
00321                     if( psz_now )
00322                     {
00323                         vlc_input_item_AddInfo( &(p_item->input),
00324                                                 _("Meta-information"),
00325                                                 _( VLC_META_NOW_PLAYING ),
00326                                                 "%s",
00327                                                 psz_now );
00328                     }
00329                     if( psz_genre )
00330                     {
00331                         vlc_input_item_AddInfo( &p_item->input,
00332                                                 _("Meta-information"),
00333                                                 _( VLC_META_GENRE ),
00334                                                 "%s",
00335                                                 psz_genre );
00336                     }
00337                     if( psz_listeners )
00338                     {
00339                         vlc_input_item_AddInfo( &p_item->input,
00340                                                 _("Meta-information"),
00341                                                 _( "Listeners" ),
00342                                                 "%s",
00343                                                 psz_listeners );
00344                     }
00345                     if( psz_bitrate )
00346                     {
00347                         vlc_input_item_AddInfo( &p_item->input,
00348                                                 _("Meta-information"),
00349                                                 _( "Bitrate" ),
00350                                                 "%s",
00351                                                 psz_bitrate );
00352                     }
00353                     playlist_NodeAddItem( p_playlist, p_item,
00354                                           p_current->pp_parents[0]->i_view,
00355                                           p_current, PLAYLIST_APPEND,
00356                                           PLAYLIST_END );
00357 
00358                     /* We need to declare the parents of the node as the
00359                      *                  * same of the parent's ones */
00360                     playlist_CopyParents( p_current, p_item );
00361 
00362                     vlc_input_item_CopyOptions( &p_current->input,
00363                                                 &p_item->input );
00364                     if( b_shoutcast )
00365                     {
00366                         char *psz_genreToken;
00367                         char *psz_otherToken;
00368                         int i = 0;
00369 
00370                         psz_genreToken = psz_genre;
00371 
00372                         /* split up the combined genre string form
00373                         shoutcast and add the individual genres */
00374                         while ( psz_genreToken &&
00375                           ( psz_otherToken = GetNextToken(psz_genreToken )))
00376                         {
00377                             if( strlen(psz_genreToken)>2 )
00378                             /* We dont want genres below 2 letters,
00379                             this gets rid of alot of junk*/
00380                             {
00381                                 /* lowercase everything */
00382                                 for( i=0; psz_genreToken[i]!=0; i++ )
00383                                     psz_genreToken[i] =
00384                                         tolower(psz_genreToken[i]);
00385                 /* Make first letter uppercase, purely cosmetical */
00386                                 psz_genreToken[0] =
00387                                     toupper( psz_genreToken[0] );
00388                                 ShoutcastAdd( p_playlist, p_genre,
00389                                               p_bitrate, p_item,
00390                                               psz_genreToken, psz_bitrate );
00391 
00392                                 psz_genreToken = psz_otherToken;
00393                             }
00394                         }
00395                     }
00396 
00397 #define FREE(a) if( a ) free( a ); a = NULL;
00398                     FREE( psz_name );
00399                     FREE( psz_mrl );
00400                     FREE( psz_genre );
00401                     FREE( psz_bitrate );
00402                     FREE( psz_listeners );
00403                     FREE( psz_now );
00404 #undef FREE
00405                 }
00406                 free( psz_elname );
00407                 psz_elname = strdup("");
00408 
00409                 break;
00410             }
00411         }
00412     }
00413 
00414     if( i_ret != 0 )
00415     {
00416         msg_Warn( p_demux, "error while parsing data" );
00417     }
00418     if( b_shoutcast )
00419     {
00420         vlc_mutex_lock( &p_playlist->object_lock );
00421         playlist_NodeSort( p_playlist, p_bitrate, SORT_TITLE_NUMERIC, ORDER_NORMAL );
00422         vlc_mutex_unlock( &p_playlist->object_lock );
00423     }
00424 
00425     /* Go back and play the playlist */
00426     if( b_play && p_playlist->status.p_item &&
00427         p_playlist->status.p_item->i_children > 0 )
00428     {
00429         playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
00430                           p_playlist->status.i_view,
00431                           p_playlist->status.p_item,
00432                           p_playlist->status.p_item->pp_children[0] );
00433     }
00434     
00435     vlc_object_release( p_playlist );
00436     p_sys->p_playlist = NULL;
00437     return VLC_SUCCESS;
00438 }
00439 
00440 static int Control( demux_t *p_demux, int i_query, va_list args )
00441 {
00442     return VLC_EGENERIC;
00443 }
00444 
00455 static char *GetNextToken(char *psz_cur_string) {
00456     while (*psz_cur_string && !isspace(*psz_cur_string))
00457         psz_cur_string++;
00458     if (!*psz_cur_string)
00459         return NULL;
00460     *psz_cur_string++ = '\0';
00461     while (*psz_cur_string && isspace(*psz_cur_string))
00462         psz_cur_string++;
00463     return psz_cur_string;
00464 }
00465 
00466 static int IsWhitespace( char *psz_string )
00467 {
00468     while( *psz_string )
00469     {
00470         if( *psz_string != ' ' && *psz_string != '\t' && *psz_string != '\r' &&
00471             *psz_string != '\n' )
00472         {
00473             return VLC_FALSE;
00474         }
00475         psz_string++;
00476     }
00477     return VLC_TRUE;
00478 }
00479 
00480 static void ShoutcastAdd( playlist_t *p_playlist, playlist_item_t* p_genre,
00481                           playlist_item_t *p_bitrate, playlist_item_t *p_item,
00482                           char *psz_genre, char *psz_bitrate )
00483 {
00484     playlist_item_t *p_parent;
00485     if( psz_bitrate )
00486     {
00487         playlist_item_t *p_copy = playlist_ItemCopy(p_playlist,p_item);
00488         p_parent = playlist_ChildSearchName( p_bitrate, psz_bitrate );
00489         if( !p_parent )
00490         {
00491             p_parent = playlist_NodeCreate( p_playlist, p_genre->pp_parents[0]->i_view, psz_bitrate,
00492                                             p_bitrate );
00493             playlist_CopyParents( p_bitrate, p_parent );
00494         }
00495         playlist_NodeAddItem( p_playlist, p_copy, p_parent->pp_parents[0]->i_view, p_parent, PLAYLIST_APPEND, PLAYLIST_END  );
00496         playlist_CopyParents( p_parent, p_copy );
00497 
00498     }
00499 
00500     if( psz_genre )
00501     {
00502         playlist_item_t *p_copy = playlist_ItemCopy(p_playlist,p_item);
00503         p_parent = playlist_ChildSearchName( p_genre, psz_genre );
00504         if( !p_parent )
00505         {
00506             p_parent = playlist_NodeCreate( p_playlist, p_genre->pp_parents[0]->i_view, psz_genre,
00507                                             p_genre );
00508             playlist_CopyParents( p_genre, p_parent );
00509         }
00510         playlist_NodeAddItem( p_playlist, p_copy, p_parent->pp_parents[0]->i_view, p_parent, PLAYLIST_APPEND, PLAYLIST_END );
00511         playlist_CopyParents( p_parent, p_copy );
00512     }
00513 }

Generated on Tue Dec 20 10:14:35 2005 for vlc-0.8.4a by  doxygen 1.4.2