1 /*****************************************************************************
2  * m3u.c : M3U playlist export module
3  *****************************************************************************
4  * Copyright (C) 2004-2009 the VideoLAN team
5  * $Id: 6a31f1463d1bb3147c113307178bc8ca0514c00d $
6  *
7  * Authors: Clément Stenac <zorglub@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23 
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31 
32 #include <vlc_common.h>
33 #include <vlc_playlist.h>
34 #include <vlc_input.h>
35 #include <vlc_meta.h>
36 #include <vlc_charset.h>
37 #include <vlc_url.h>
38 
39 #include <assert.h>
40 
41 /*****************************************************************************
42  * Local prototypes
43  *****************************************************************************/
44 int Export_M3U ( vlc_object_t * );
45 int Export_M3U8( vlc_object_t * );
46 
47 /*****************************************************************************
48  * Export_M3U: main export function
49  *****************************************************************************/
DoChildren(playlist_export_t * p_export,playlist_item_t * p_root,int (* pf_fprintf)(FILE *,const char *,...))50 static void DoChildren( playlist_export_t *p_export, playlist_item_t *p_root,
51                         int (*pf_fprintf) (FILE *, const char *, ...) )
52 {
53     size_t prefix_len = -1;
54     if( likely(p_export->base_url != NULL) )
55     {
56         const char *p = strrchr( p_export->base_url, '/' );
57         assert(p != NULL);
58         prefix_len = (p + 1) - p_export->base_url;
59     }
60 
61     /* Write header */
62     fputs( "#EXTM3U\n", p_export->p_file );
63 
64     /* Go through the playlist and add items */
65     for( int i = 0; i< p_root->i_children ; i++)
66     {
67         playlist_item_t *p_current = p_root->pp_children[i];
68         assert( p_current );
69 
70         if( p_current->i_children >= 0 )
71         {
72             DoChildren( p_export, p_current, pf_fprintf );
73             continue;
74         }
75 
76         /* General info */
77 
78         char *psz_uri = input_item_GetURI( p_current->p_input );
79 
80         assert( psz_uri );
81 
82         char *psz_name = input_item_GetName( p_current->p_input );
83         if( psz_name && strcmp( psz_uri, psz_name ) )
84         {
85             char *psz_artist = input_item_GetArtist( p_current->p_input );
86             if( psz_artist == NULL ) psz_artist = strdup( "" );
87             mtime_t i_duration = input_item_GetDuration( p_current->p_input );
88             if( psz_artist && *psz_artist )
89             {
90                 /* write EXTINF with artist */
91                 pf_fprintf( p_export->p_file, "#EXTINF:%"PRIu64",%s - %s\n",
92                             i_duration / CLOCK_FREQ, psz_artist, psz_name);
93             }
94             else
95             {
96                 /* write EXTINF without artist */
97                 pf_fprintf( p_export->p_file, "#EXTINF:%"PRIu64",%s\n",
98                             i_duration / CLOCK_FREQ, psz_name);
99             }
100             free( psz_artist );
101         }
102         free( psz_name );
103 
104         /* VLC specific options */
105         vlc_mutex_lock( &p_current->p_input->lock );
106         for( int j = 0; j < p_current->p_input->i_options; j++ )
107         {
108             pf_fprintf( p_export->p_file, "#EXTVLCOPT:%s\n",
109                         p_current->p_input->ppsz_options[j][0] == ':' ?
110                         p_current->p_input->ppsz_options[j] + 1 :
111                         p_current->p_input->ppsz_options[j] );
112         }
113         vlc_mutex_unlock( &p_current->p_input->lock );
114 
115         /* We cannot really know if relative or absolute URL is better. As a
116          * heuristic, we write a relative URL if the item is in the same
117          * directory as the playlist, or a sub-directory thereof. */
118         size_t skip = 0;
119         if( likely(prefix_len != (size_t)-1)
120          && !strncmp( p_export->base_url, psz_uri, prefix_len ) )
121             skip = prefix_len;
122 
123         fprintf( p_export->p_file, "%s\n", psz_uri + skip );
124         free( psz_uri );
125     }
126 }
127 
Export_M3U(vlc_object_t * p_this)128 int Export_M3U( vlc_object_t *p_this )
129 {
130     playlist_export_t *p_export = (playlist_export_t *)p_this;
131 
132     msg_Dbg( p_export, "saving using M3U format");
133 
134     DoChildren( p_export, p_export->p_root, utf8_fprintf );
135     return VLC_SUCCESS;
136 }
137 
Export_M3U8(vlc_object_t * p_this)138 int Export_M3U8( vlc_object_t *p_this )
139 {
140     playlist_export_t *p_export = (playlist_export_t *)p_this;
141 
142     msg_Dbg( p_export, "saving using M3U8 format");
143 
144     DoChildren( p_export, p_export->p_root, fprintf );
145     return VLC_SUCCESS;
146 }
147