DCP: fixed include-guards
[vlc.git] / modules / services_discovery / mediadirs.c
1 /*****************************************************************************
2  * mediadirs.c:  Picture/Music/Video user directories as service discoveries
3  *****************************************************************************
4  * Copyright (C) 2009 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Erwan Tulou <erwan10 aT videolan DoT 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  * Includes
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <sys/stat.h>
33
34 #define VLC_MODULE_LICENSE VLC_LICENSE_GPL_2_PLUS
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_url.h>
38 #include <vlc_fs.h>
39 #include <vlc_services_discovery.h>
40
41 /*****************************************************************************
42  * Module descriptor
43  *****************************************************************************/
44
45 enum type_e { Video = 0, Audio = 1, Picture = 2, Unknown = 3 };
46
47 static int  Open( vlc_object_t *, enum type_e );
48 static void Close( vlc_object_t * );
49
50 /* Main functions */
51 #define OPEN_MODULE( type )                        \
52 static int Open##type( vlc_object_t *p_this )      \
53 {                                                  \
54     msg_Dbg( p_this, "Starting " #type );          \
55     return Open( p_this, type );                   \
56 }
57
58 OPEN_MODULE( Video )
59 OPEN_MODULE( Audio )
60 OPEN_MODULE( Picture )
61
62 #undef OPEN_MODULE
63
64 static int vlc_sd_probe_Open( vlc_object_t * );
65
66 vlc_module_begin ()
67     set_category( CAT_PLAYLIST )
68     set_subcategory( SUBCAT_PLAYLIST_SD )
69
70         set_shortname( N_("Video") )
71         set_description( N_("My Videos") )
72         set_capability( "services_discovery", 0 )
73         set_callbacks( OpenVideo, Close )
74         add_shortcut( "video_dir" )
75
76     add_submodule ()
77         set_shortname( N_("Audio") )
78         set_description( N_("My Music") )
79         set_capability( "services_discovery", 0 )
80         set_callbacks( OpenAudio, Close )
81         add_shortcut( "audio_dir" )
82
83     add_submodule ()
84         set_shortname( N_("Picture") )
85         set_description( N_("My Pictures") )
86         set_capability( "services_discovery", 0 )
87         set_callbacks( OpenPicture, Close )
88         add_shortcut( "picture_dir" )
89
90     VLC_SD_PROBE_SUBMODULE
91 vlc_module_end ()
92
93
94 /*****************************************************************************
95  * Local prototypes
96  *****************************************************************************/
97
98 static void* Run( void* );
99
100 static void input_item_subitem_added( const vlc_event_t*, void* );
101 static int onNewFileAdded( vlc_object_t*, char const *,
102                            vlc_value_t, vlc_value_t, void *);
103
104 static enum type_e fileType( services_discovery_t *p_sd, const char* psz_file );
105 static void formatSnapshotItem( input_item_t* );
106
107 struct services_discovery_sys_t
108 {
109     vlc_thread_t thread;
110     enum type_e i_type;
111
112     char* psz_dir[2];
113     const char* psz_var;
114 };
115
116 /*****************************************************************************
117  * Open: initialize module
118  *****************************************************************************/
119 static int Open( vlc_object_t *p_this, enum type_e i_type )
120 {
121     services_discovery_t *p_sd = ( services_discovery_t* )p_this;
122     services_discovery_sys_t *p_sys;
123
124     p_sd->p_sys = p_sys = calloc( 1, sizeof( *p_sys) );
125     if( !p_sys )
126         return VLC_ENOMEM;
127
128     p_sys->i_type = i_type;
129
130     if( p_sys->i_type == Video )
131     {
132         p_sys->psz_dir[0] = config_GetUserDir( VLC_VIDEOS_DIR );
133         p_sys->psz_dir[1] = var_CreateGetString( p_sd, "input-record-path" );
134
135         p_sys->psz_var = "record-file";
136     }
137     else if( p_sys->i_type == Audio )
138     {
139         p_sys->psz_dir[0] = config_GetUserDir( VLC_MUSIC_DIR );
140         p_sys->psz_dir[1] = var_CreateGetString( p_sd, "input-record-path" );
141
142         p_sys->psz_var = "record-file";
143     }
144     else if( p_sys->i_type == Picture )
145     {
146         p_sys->psz_dir[0] = config_GetUserDir( VLC_PICTURES_DIR );
147         p_sys->psz_dir[1] = var_CreateGetString( p_sd, "snapshot-path" );
148
149         p_sys->psz_var = "snapshot-file";
150     }
151     else
152     {
153         free( p_sys );
154         return VLC_EGENERIC;
155     }
156
157     var_AddCallback( p_sd->p_libvlc, p_sys->psz_var, onNewFileAdded, p_sd );
158
159     if( vlc_clone( &p_sys->thread, Run, p_sd, VLC_THREAD_PRIORITY_LOW ) )
160     {
161         var_DelCallback( p_sd->p_libvlc, p_sys->psz_var, onNewFileAdded, p_sd );
162         free( p_sys->psz_dir[1] );
163         free( p_sys->psz_dir[0] );
164         free( p_sys );
165         return VLC_EGENERIC;
166     }
167
168     return VLC_SUCCESS;
169 }
170
171 /*****************************************************************************
172  * Run:
173  *****************************************************************************/
174 static void *Run( void *data )
175 {
176     services_discovery_t *p_sd = data;
177     services_discovery_sys_t *p_sys = p_sd->p_sys;
178
179     int canc = vlc_savecancel();
180
181     int num_dir = sizeof( p_sys->psz_dir ) / sizeof( p_sys->psz_dir[0] );
182     for( int i = 0; i < num_dir; i++ )
183     {
184         char* psz_dir = p_sys->psz_dir[i];
185
186         /* make sure the directory exists */
187         struct stat st;
188         if( psz_dir == NULL            ||
189             vlc_stat( psz_dir, &st )  ||
190             !S_ISDIR( st.st_mode ) )
191             continue;
192
193         char* psz_uri = vlc_path2uri( psz_dir, "file" );
194
195         input_item_t* p_root = input_item_New( psz_uri, NULL );
196         if( p_sys->i_type == Picture )
197             input_item_AddOption( p_root, "ignore-filetypes=ini,db,lnk,txt",
198                                   VLC_INPUT_OPTION_TRUSTED );
199
200         input_item_AddOption( p_root, "recursive=collapse",
201                               VLC_INPUT_OPTION_TRUSTED );
202
203
204         vlc_event_manager_t *p_em = &p_root->event_manager;
205         vlc_event_attach( p_em, vlc_InputItemSubItemAdded,
206                           input_item_subitem_added, p_sd );
207
208         input_Read( p_sd, p_root );
209
210         vlc_event_detach( p_em, vlc_InputItemSubItemAdded,
211                           input_item_subitem_added, p_sd );
212
213         vlc_gc_decref( p_root );
214         free( psz_uri );
215     }
216
217     vlc_restorecancel(canc);
218     return NULL;
219 }
220
221 /*****************************************************************************
222  * Close:
223  *****************************************************************************/
224 static void Close( vlc_object_t *p_this )
225 {
226     services_discovery_t *p_sd = (services_discovery_t *)p_this;
227     services_discovery_sys_t *p_sys = p_sd->p_sys;
228
229     vlc_cancel( p_sys->thread );
230     vlc_join( p_sys->thread, NULL );
231
232     var_DelCallback( p_sd->p_libvlc, p_sys->psz_var, onNewFileAdded, p_sd );
233
234     free( p_sys->psz_dir[1] );
235     free( p_sys->psz_dir[0] );
236     free( p_sys );
237 }
238
239
240 /*****************************************************************************
241  * Callbacks and helper functions
242  *****************************************************************************/
243 static void input_item_subitem_added( const vlc_event_t * p_event,
244                                       void * user_data )
245 {
246     services_discovery_t *p_sd = user_data;
247     services_discovery_sys_t *p_sys = p_sd->p_sys;
248
249     /* retrieve new item */
250     input_item_t *p_item = p_event->u.input_item_subitem_added.p_new_child;
251
252     if( p_sys->i_type == Picture )
253         formatSnapshotItem( p_item );
254
255     services_discovery_AddItem( p_sd, p_item, NULL );
256 }
257
258 static int onNewFileAdded( vlc_object_t *p_this, char const *psz_var,
259                      vlc_value_t oldval, vlc_value_t newval, void *p_data )
260 {
261     (void)p_this;
262
263     services_discovery_t *p_sd = p_data;
264     services_discovery_sys_t *p_sys = p_sd->p_sys;
265
266     (void)psz_var; (void)oldval;
267     char* psz_file = newval.psz_string;
268     if( !psz_file || !*psz_file )
269         return VLC_EGENERIC;
270
271     char* psz_uri = vlc_path2uri( psz_file, "file" );
272     input_item_t* p_item = input_item_New( psz_uri, NULL );
273
274     if( p_sys->i_type == Picture )
275     {
276         if( fileType( p_sd, psz_file ) == Picture )
277         {
278             formatSnapshotItem( p_item );
279             services_discovery_AddItem( p_sd, p_item, NULL );
280
281             msg_Dbg( p_sd, "New snapshot added : %s", psz_file );
282         }
283     }
284     else if( p_sys->i_type == Audio )
285     {
286         if( fileType( p_sd, psz_file ) == Audio )
287         {
288             services_discovery_AddItem( p_sd, p_item, NULL );
289
290             msg_Dbg( p_sd, "New recorded audio added : %s", psz_file );
291         }
292     }
293     else if( p_sys->i_type == Video )
294     {
295         if( fileType( p_sd, psz_file ) == Video ||
296             fileType( p_sd, psz_file ) == Unknown )
297         {
298             services_discovery_AddItem( p_sd, p_item, NULL );
299
300             msg_Dbg( p_sd, "New recorded video added : %s", psz_file );
301         }
302     }
303
304     vlc_gc_decref( p_item );
305     free( psz_uri );
306
307     return VLC_SUCCESS;
308 }
309
310 void formatSnapshotItem( input_item_t *p_item )
311 {
312     if( !p_item )
313         return;
314
315     char* psz_uri = input_item_GetURI( p_item );
316
317     /* copy the snapshot mrl as a ArtURL */
318     if( psz_uri )
319         input_item_SetArtURL( p_item, psz_uri );
320
321     free( psz_uri );
322 }
323
324
325 enum type_e fileType( services_discovery_t *p_sd, const char* psz_file )
326 {
327     services_discovery_sys_t *p_sys = p_sd->p_sys;
328     enum type_e i_ret = Unknown;
329
330     char* psz_dir = strdup( psz_file );
331     char* psz_tmp = strrchr( psz_dir, DIR_SEP_CHAR );
332     if( psz_tmp )
333         *psz_tmp = '\0';
334
335     int num_dir = sizeof( p_sys->psz_dir ) / sizeof( p_sys->psz_dir[0] );
336     for( int i = 0; i < num_dir; i++ )
337     {
338         char* psz_known_dir = p_sys->psz_dir[i];
339
340         if( psz_known_dir && !strcmp( psz_dir, psz_known_dir ) )
341             i_ret = p_sys->i_type;
342     }
343
344     free( psz_dir );
345     return i_ret;
346 }
347
348 static int vlc_sd_probe_Open( vlc_object_t *obj )
349 {
350     vlc_probe_t *probe = (vlc_probe_t *)obj;
351
352     vlc_sd_probe_Add( probe, "video_dir{longname=\"My Videos\"}",
353                       N_("My Videos"), SD_CAT_MYCOMPUTER );
354     vlc_sd_probe_Add( probe, "audio_dir{longname=\"My Music\"}",
355                       N_("My Music"), SD_CAT_MYCOMPUTER );
356     vlc_sd_probe_Add( probe, "picture_dir{longname=\"My Pictures\"}",
357                       N_("My Pictures"), SD_CAT_MYCOMPUTER );
358     return VLC_PROBE_CONTINUE;
359 }