From dbc59e3a782ed65537b56b7d9df7ee82498a0bc4 Mon Sep 17 00:00:00 2001 From: Yoann Peronneau Date: Wed, 14 Jun 2006 00:43:00 +0000 Subject: [PATCH] * Tree playlist XSPF export Kids, don't try this at home... --- modules/gui/wxwidgets/dialogs/playlist.cpp | 13 +- modules/misc/playlist/xspf.c | 238 ++++++++++++--------- modules/misc/playlist/xspf.h | 3 +- 3 files changed, 146 insertions(+), 108 deletions(-) diff --git a/modules/gui/wxwidgets/dialogs/playlist.cpp b/modules/gui/wxwidgets/dialogs/playlist.cpp index 3971ab19b3..16918c5932 100644 --- a/modules/gui/wxwidgets/dialogs/playlist.cpp +++ b/modules/gui/wxwidgets/dialogs/playlist.cpp @@ -932,7 +932,7 @@ void Playlist::OnSave( wxCommandEvent& WXUNUSED(event) ) char *psz_desc; char *psz_filter; char *psz_module; - } formats[] = {{ _("M3U file"), "*.m3u", "export-m3u" }, + } formats[] = {//{ _("M3U file"), "*.m3u", "export-m3u" }, { _("XSPF playlist"), "*.xspf", "export-xspf"} }; @@ -959,10 +959,13 @@ void Playlist::OnSave( wxCommandEvent& WXUNUSED(event) ) { if( dialog.GetPath().mb_str() ) { - abort(); -// playlist_Export( p_playlist, dialog.GetPath().mb_str(), -// /* ROOT */ -// formats[dialog.GetFilterIndex()].psz_module ); + /* what root should we export? */ + if( p_playlist->p_root_category->i_children > 0 ) + { + playlist_Export( p_playlist, dialog.GetPath().mb_str(), + p_playlist->p_root_category->pp_children[0], + formats[dialog.GetFilterIndex()].psz_module ); + } } } diff --git a/modules/misc/playlist/xspf.c b/modules/misc/playlist/xspf.c index 9366518237..f056dcf8a7 100644 --- a/modules/misc/playlist/xspf.c +++ b/modules/misc/playlist/xspf.c @@ -1,5 +1,11 @@ /****************************************************************************** - * Copyright (C) 2006 Daniel Stränger + * xspf.c : XSPF playlist export functions + ****************************************************************************** + * Copyright (C) 2006 the VideoLAN team + * $Id$ + * + * Authors: Daniel Stränger + * Yoann Peronneau * * 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 @@ -39,87 +45,59 @@ int E_(xspf_export_playlist)( vlc_object_t *p_this ) const playlist_export_t *p_export = (playlist_export_t *)p_playlist->p_private; int i; - char *psz; char *psz_temp; playlist_item_t **pp_items = NULL; int i_size; - playlist_item_t *p_node; + playlist_item_t *p_node = p_export->p_root; + int i_count; - /* write XSPF XML header - since we don't use , - * we get by with version 0 */ + /* write XSPF XML header */ fprintf( p_export->p_file, "\n" ); fprintf( p_export->p_file, - "\n" ); + "\n" ); + + if( !p_node ) return VLC_SUCCESS; - /* save tho whole playlist or only the current node */ -#define p_item p_playlist->status.p_item - if ( p_item ) + pp_items = p_node->pp_children; + i_size = p_node->i_children; + + /* save name of the playlist node */ + psz_temp = convert_xml_special_chars( p_node->p_input->psz_name ); + if( *psz_temp ) { - if ( p_item->p_parent->p_input->i_type == ITEM_TYPE_PLAYLIST ) - { - /* set the current node and its children */ - p_node = p_item->p_parent; - pp_items = p_node->pp_children; - i_size = p_node->i_children; -#undef p_item - - /* save name of the playlist node */ - psz_temp = convert_xml_special_chars( p_node->p_input->psz_name ); - if ( *psz_temp ) - fprintf( p_export->p_file, "\t%s\n", - psz_temp ); - free( psz_temp ); - - /* save the creator of the playlist node */ - psz = p_node->p_input->p_meta->psz_artist ? - strdup( p_node->p_input->p_meta->psz_artist ): - strdup( "" ); - if ( psz && !*psz ) - { - free ( psz ); - psz = NULL; - } - - if ( !psz ) - psz = p_node->p_input->p_meta->psz_author ? - strdup( p_node->p_input->p_meta->psz_author ): - strdup( "" ); - - psz_temp = convert_xml_special_chars( psz ); - - if ( psz ) free( psz ); - if ( *psz_temp ) - fprintf( p_export->p_file, "\t%s\n", - psz_temp ); - free( psz_temp ); - - /* save location of the playlist node */ - psz = assertUTF8URI( p_export->psz_filename ); - if ( psz && *psz ) - { - fprintf( p_export->p_file, "\t%s\n", - psz ); - free( psz ); - } - } + fprintf( p_export->p_file, "\t%s\n", psz_temp ); } + free( psz_temp ); - /* prepare all the playlist children for export */ - if ( !pp_items ) + /* save location of the playlist node */ + psz_temp = assertUTF8URI( p_export->psz_filename ); + if( psz_temp && *psz_temp ) { - pp_items = p_playlist->pp_items; - i_size = p_playlist->i_size; + fprintf( p_export->p_file, "\t%s\n", psz_temp ); + free( psz_temp ); } - /* export all items */ + /* export all items in a flat format */ fprintf( p_export->p_file, "\t\n" ); - for ( i = 0; i < i_size; i++ ) + i_count = 0; + for( i = 0; i < p_node->i_children; i++ ) + { + xspf_export_item( p_node->pp_children[i], p_export->p_file, + &i_count ); + } + fprintf( p_export->p_file, "\t\n" ); + + /* export the tree structure in */ + fprintf( p_export->p_file, "\t\n" ); + i_count = 0; + for( i = 0; i < p_node->i_children; i++ ) { - xspf_export_item( pp_items[i], p_export->p_file ); + xspf_extension_item( p_node->pp_children[i], p_export->p_file, + &i_count ); } + fprintf( p_export->p_file, "\t\n" ); /* close the header elements */ - fprintf( p_export->p_file, "\t\n" ); fprintf( p_export->p_file, "\n" ); return VLC_SUCCESS; @@ -129,25 +107,23 @@ int E_(xspf_export_playlist)( vlc_object_t *p_this ) * \brief exports one item to file or traverse if item is a node * \param p_item playlist item to export * \param p_file file to write xml-converted item to + * \param p_i_count counter for track identifiers */ -static void xspf_export_item( playlist_item_t *p_item, FILE *p_file ) +static void xspf_export_item( playlist_item_t *p_item, FILE *p_file, + int *p_i_count ) { - int i; /**< iterator for all children if the current item is a node */ char *psz; char *psz_temp; - if ( !p_item ) - return; + if( !p_item ) return; - /** \todo only "flat" playlists supported at this time. - * extend to save the tree structure. - */ /* if we get a node here, we must traverse it */ - if ( p_item->i_children > 0 ) + if( p_item->i_children > 0 ) { - for ( i = 0; i < p_item->i_children; i++ ) + int i; + for( i = 0; i < p_item->i_children; i++ ) { - xspf_export_item( p_item->pp_children[i], p_file ); + xspf_export_item( p_item->pp_children[i], p_file, p_i_count ); } return; } @@ -155,8 +131,12 @@ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file ) /* leaves can be written directly */ fprintf( p_file, "\t\t\n" ); + /* print identifier and increase the counter */ + fprintf( p_file, "\t\t\t%d\n", *p_i_count ); + ( *p_i_count )++; + /* -> the location */ - if ( p_item->p_input->psz_uri && *p_item->p_input->psz_uri ) + if( p_item->p_input->psz_uri && *p_item->p_input->psz_uri ) { psz = assertUTF8URI( p_item->p_input->psz_uri ); fprintf( p_file, "\t\t\t%s\n", psz ); @@ -164,33 +144,42 @@ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file ) } /* -> the name/title (only if different from uri)*/ - if ( p_item->p_input->psz_name && - p_item->p_input->psz_uri && - strcmp( p_item->p_input->psz_uri, p_item->p_input->psz_name ) ) + if( p_item->p_input->psz_name && + p_item->p_input->psz_uri && + strcmp( p_item->p_input->psz_uri, p_item->p_input->psz_name ) ) { psz_temp = convert_xml_special_chars( p_item->p_input->psz_name ); - if ( *psz_temp ) + if( *psz_temp ) fprintf( p_file, "\t\t\t%s\n", psz_temp ); free( psz_temp ); } + if( p_item->p_input->p_meta == NULL ) + { + goto xspfexportitem_end; + } + /* -> the artist/creator */ - psz = p_item->p_input->p_meta->psz_artist ? + psz = p_item->p_input->p_meta->psz_artist ? strdup( p_item->p_input->p_meta->psz_artist ): strdup( "" ); - if ( psz && !*psz ) + if( psz && !*psz ) { - free ( psz ); + free( psz ); psz = NULL; } - if ( !psz ) - psz = p_item->p_input->p_meta->psz_author ? + if( !psz ) + { + psz = p_item->p_input->p_meta->psz_author ? strdup( p_item->p_input->p_meta->psz_author ): strdup( "" ); + } psz_temp = convert_xml_special_chars( psz ); - if ( psz ) free( psz ); - if ( *psz_temp ) + if( psz ) free( psz ); + if( *psz_temp ) + { fprintf( p_file, "\t\t\t%s\n", psz_temp ); + } free( psz_temp ); /* -> the album */ @@ -198,24 +187,29 @@ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file ) strdup( p_item->p_input->p_meta->psz_album ): strdup( "" ); psz_temp = convert_xml_special_chars( psz ); - if ( psz ) free( psz ); - if ( *psz_temp ) + if( psz ) free( psz ); + if( *psz_temp ) + { fprintf( p_file, "\t\t\t%s\n", psz_temp ); + } free( psz_temp ); /* -> the track number */ psz = p_item->p_input->p_meta->psz_tracknum ? strdup( p_item->p_input->p_meta->psz_tracknum ): strdup( "" ); - if ( psz ) + if( psz ) { - if ( *psz ) + if( *psz ) + { fprintf( p_file, "\t\t\t%i\n", atoi( psz ) ); + } free( psz ); } +xspfexportitem_end: /* -> the duration */ - if ( p_item->p_input->i_duration > 0 ) + if( p_item->p_input->i_duration > 0 ) { fprintf( p_file, "\t\t\t%ld\n", (long)(p_item->p_input->i_duration / 1000) ); @@ -226,6 +220,43 @@ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file ) return; } +/** + * \brief exports one item in extension to file and traverse if item is a node + * \param p_item playlist item to export + * \param p_file file to write xml-converted item to + * \param p_i_count counter for track identifiers + */ +static void xspf_extension_item( playlist_item_t *p_item, FILE *p_file, + int *p_i_count ) +{ + if( !p_item ) return; + + /* if we get a node here, we must traverse it */ + if( p_item->i_children > 0 ) + { + int i; + + fprintf( p_file, "\t\t\n" ); + fprintf( p_file, "\t\t\t%s\n", + p_item->p_input->psz_name ); + + for( i = 0; i < p_item->i_children; i++ ) + { + xspf_extension_item( p_item->pp_children[i], p_file, p_i_count ); + } + + fprintf( p_file, "\t\t\n" ); + return; + } + + + /* print leaf and increase the counter */ + fprintf( p_file, "\t\t\t\n", *p_i_count ); + ( *p_i_count )++; + + return; +} + /** * \param psz_name the location of the media ressource (e.g. local file, * device, network stream, etc.) @@ -239,7 +270,7 @@ static char *assertUTF8URI( char *psz_name ) char *psz_s = NULL, *psz_d = NULL; /**< src & dest pointers for URI conversion */ vlc_bool_t b_name_is_uri = VLC_FALSE; - if ( !psz_name || !*psz_name ) + if( !psz_name || !*psz_name ) return NULL; /* check that string is valid UTF-8 */ @@ -250,11 +281,11 @@ static char *assertUTF8URI( char *psz_name ) /* max. 3x for URI conversion (percent escaping) and 8 bytes for "file://" and NULL-termination */ psz_ret = (char *)malloc( sizeof(char)*strlen(psz_name)*6*3+8 ); - if ( !psz_ret ) + if( !psz_ret ) return NULL; /** \todo check for a valid scheme part preceding the colon */ - if ( strchr( psz_s, ':' ) ) + if( strchr( psz_s, ':' ) ) { psz_d = psz_ret; b_name_is_uri = VLC_TRUE; @@ -266,21 +297,24 @@ static char *assertUTF8URI( char *psz_name ) psz_d = psz_ret + 7; } - while ( *psz_s ) + while( *psz_s ) { /* percent-encode all non-ASCII and the XML special characters and the percent sign itself */ - if ( *psz_s & B10000000 || - *psz_s == '<' || - *psz_s == '>' || - *psz_s == '&' || - *psz_s == ' ' || - ( *psz_s == '%' && !b_name_is_uri ) ) + if( *psz_s & B10000000 || + *psz_s == '<' || + *psz_s == '>' || + *psz_s == '&' || + *psz_s == ' ' || + ( *psz_s == '%' && !b_name_is_uri ) ) { *psz_d++ = '%'; *psz_d++ = hexchars[(*psz_s >> 4) & B00001111]; *psz_d++ = hexchars[*psz_s & B00001111]; - } else + } + else + { *psz_d++ = *psz_s; + } psz_s++; } diff --git a/modules/misc/playlist/xspf.h b/modules/misc/playlist/xspf.h index e2773735b8..9fc108aede 100644 --- a/modules/misc/playlist/xspf.h +++ b/modules/misc/playlist/xspf.h @@ -33,5 +33,6 @@ const char hexchars[16] = "0123456789ABCDEF"; /* prototypes */ int E_(xspf_export_playlist)( vlc_object_t * ); -static void xspf_export_item( playlist_item_t *, FILE * ); +static void xspf_export_item( playlist_item_t *, FILE *, int * ); +static void xspf_extension_item( playlist_item_t *, FILE *, int * ); static char *assertUTF8URI( char * ); -- 2.39.2