mediadirs.c 10.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*****************************************************************************
 * mediadirs.c:  Picture/Music/Video user directories as service discoveries
 *****************************************************************************
 * Copyright (C) 2009 the VideoLAN team
 * $Id$
 *
 * Authors: Erwan Tulou <erwan10 aT videolan DoT org>
 *
 * 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
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

/*****************************************************************************
 * Includes
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

32 33
#include <sys/stat.h>

34
#define VLC_MODULE_LICENSE VLC_LICENSE_GPL_2_PLUS
35 36 37
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_url.h>
38
#include <vlc_fs.h>
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
#include <vlc_services_discovery.h>

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/

enum type_e { Video = 0, Audio = 1, Picture = 2, Unknown = 3 };

static int  Open( vlc_object_t *, enum type_e );
static void Close( vlc_object_t * );

/* Main functions */
#define OPEN_MODULE( type )                        \
static int Open##type( vlc_object_t *p_this )      \
{                                                  \
    msg_Dbg( p_this, "Starting " #type );          \
    return Open( p_this, type );                   \
}

OPEN_MODULE( Video )
OPEN_MODULE( Audio )
OPEN_MODULE( Picture )

#undef OPEN_MODULE

64 65
static int vlc_sd_probe_Open( vlc_object_t * );

66 67 68 69
vlc_module_begin ()
    set_category( CAT_PLAYLIST )
    set_subcategory( SUBCAT_PLAYLIST_SD )

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
70
        set_shortname( N_("Video") )
71
        set_description( N_("My Videos") )
72
        set_capability( "services_discovery", 0 )
73 74 75 76
        set_callbacks( OpenVideo, Close )
        add_shortcut( "video_dir" )

    add_submodule ()
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
77
        set_shortname( N_("Audio") )
78
        set_description( N_("My Music") )
79
        set_capability( "services_discovery", 0 )
80 81 82 83
        set_callbacks( OpenAudio, Close )
        add_shortcut( "audio_dir" )

    add_submodule ()
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
84
        set_shortname( N_("Picture") )
85
        set_description( N_("My Pictures") )
86
        set_capability( "services_discovery", 0 )
87 88 89
        set_callbacks( OpenPicture, Close )
        add_shortcut( "picture_dir" )

90
    VLC_SD_PROBE_SUBMODULE
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
vlc_module_end ()


/*****************************************************************************
 * Local prototypes
 *****************************************************************************/

static void* Run( void* );

static void input_item_subitem_added( const vlc_event_t*, void* );
static int onNewFileAdded( vlc_object_t*, char const *,
                           vlc_value_t, vlc_value_t, void *);

static enum type_e fileType( services_discovery_t *p_sd, const char* psz_file );
static void formatSnapshotItem( input_item_t* );

struct services_discovery_sys_t
{
    vlc_thread_t thread;
    enum type_e i_type;

    char* psz_dir[2];
113
    const char* psz_var;
114 115 116 117 118 119 120 121
};

/*****************************************************************************
 * Open: initialize module
 *****************************************************************************/
static int Open( vlc_object_t *p_this, enum type_e i_type )
{
    services_discovery_t *p_sd = ( services_discovery_t* )p_this;
122
    services_discovery_sys_t *p_sys;
123 124 125 126 127 128 129 130 131 132 133 134

    p_sd->p_sys = p_sys = calloc( 1, sizeof( *p_sys) );
    if( !p_sys )
        return VLC_ENOMEM;

    p_sys->i_type = i_type;

    if( p_sys->i_type == Video )
    {
        p_sys->psz_dir[0] = config_GetUserDir( VLC_VIDEOS_DIR );
        p_sys->psz_dir[1] = var_CreateGetString( p_sd, "input-record-path" );

135
        p_sys->psz_var = "record-file";
136 137 138 139 140 141
    }
    else if( p_sys->i_type == Audio )
    {
        p_sys->psz_dir[0] = config_GetUserDir( VLC_MUSIC_DIR );
        p_sys->psz_dir[1] = var_CreateGetString( p_sd, "input-record-path" );

142
        p_sys->psz_var = "record-file";
143 144 145 146 147 148
    }
    else if( p_sys->i_type == Picture )
    {
        p_sys->psz_dir[0] = config_GetUserDir( VLC_PICTURES_DIR );
        p_sys->psz_dir[1] = var_CreateGetString( p_sd, "snapshot-path" );

149
        p_sys->psz_var = "snapshot-file";
150 151 152 153 154 155 156
    }
    else
    {
        free( p_sys );
        return VLC_EGENERIC;
    }

157
    var_AddCallback( p_sd->obj.libvlc, p_sys->psz_var, onNewFileAdded, p_sd );
158 159 160

    if( vlc_clone( &p_sys->thread, Run, p_sd, VLC_THREAD_PRIORITY_LOW ) )
    {
161
        var_DelCallback( p_sd->obj.libvlc, p_sys->psz_var, onNewFileAdded, p_sd );
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
        free( p_sys->psz_dir[1] );
        free( p_sys->psz_dir[0] );
        free( p_sys );
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}

/*****************************************************************************
 * Run:
 *****************************************************************************/
static void *Run( void *data )
{
    services_discovery_t *p_sd = data;
    services_discovery_sys_t *p_sys = p_sd->p_sys;

    int num_dir = sizeof( p_sys->psz_dir ) / sizeof( p_sys->psz_dir[0] );
    for( int i = 0; i < num_dir; i++ )
    {
        char* psz_dir = p_sys->psz_dir[i];

        /* make sure the directory exists */
        struct stat st;
        if( psz_dir == NULL            ||
187
            vlc_stat( psz_dir, &st )  ||
188 189 190
            !S_ISDIR( st.st_mode ) )
            continue;

191
        char* psz_uri = vlc_path2uri( psz_dir, "file" );
192

193
        input_item_t* p_root = input_item_New( psz_uri, NULL );
194 195 196 197
        if( p_sys->i_type == Picture )
            input_item_AddOption( p_root, "ignore-filetypes=ini,db,lnk,txt",
                                  VLC_INPUT_OPTION_TRUSTED );

198
        input_item_AddOption( p_root, "recursive=collapse",
199 200 201 202 203 204 205
                              VLC_INPUT_OPTION_TRUSTED );


        vlc_event_manager_t *p_em = &p_root->event_manager;
        vlc_event_attach( p_em, vlc_InputItemSubItemAdded,
                          input_item_subitem_added, p_sd );

206
        input_Read( p_sd, p_root );
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227

        vlc_event_detach( p_em, vlc_InputItemSubItemAdded,
                          input_item_subitem_added, p_sd );

        vlc_gc_decref( p_root );
        free( psz_uri );
    }

    return NULL;
}

/*****************************************************************************
 * Close:
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
    services_discovery_t *p_sd = (services_discovery_t *)p_this;
    services_discovery_sys_t *p_sys = p_sd->p_sys;

    vlc_join( p_sys->thread, NULL );

228
    var_DelCallback( p_sd->obj.libvlc, p_sys->psz_var, onNewFileAdded, p_sd );
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256

    free( p_sys->psz_dir[1] );
    free( p_sys->psz_dir[0] );
    free( p_sys );
}


/*****************************************************************************
 * Callbacks and helper functions
 *****************************************************************************/
static void input_item_subitem_added( const vlc_event_t * p_event,
                                      void * user_data )
{
    services_discovery_t *p_sd = user_data;
    services_discovery_sys_t *p_sys = p_sd->p_sys;

    /* retrieve new item */
    input_item_t *p_item = p_event->u.input_item_subitem_added.p_new_child;

    if( p_sys->i_type == Picture )
        formatSnapshotItem( p_item );

    services_discovery_AddItem( p_sd, p_item, NULL );
}

static int onNewFileAdded( vlc_object_t *p_this, char const *psz_var,
                     vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
257 258
    (void)p_this;

259
    services_discovery_t *p_sd = p_data;
260
    services_discovery_sys_t *p_sys = p_sd->p_sys;
261

262
    (void)psz_var; (void)oldval;
263 264 265 266
    char* psz_file = newval.psz_string;
    if( !psz_file || !*psz_file )
        return VLC_EGENERIC;

267
    char* psz_uri = vlc_path2uri( psz_file, "file" );
268
    input_item_t* p_item = input_item_New( psz_uri, NULL );
269

270
    if( p_sys->i_type == Picture )
271
    {
272 273 274 275
        if( fileType( p_sd, psz_file ) == Picture )
        {
            formatSnapshotItem( p_item );
            services_discovery_AddItem( p_sd, p_item, NULL );
276

277 278
            msg_Dbg( p_sd, "New snapshot added : %s", psz_file );
        }
279
    }
280
    else if( p_sys->i_type == Audio )
281
    {
282 283 284
        if( fileType( p_sd, psz_file ) == Audio )
        {
            services_discovery_AddItem( p_sd, p_item, NULL );
285

286 287
            msg_Dbg( p_sd, "New recorded audio added : %s", psz_file );
        }
288
    }
289
    else if( p_sys->i_type == Video )
290
    {
291 292 293 294
        if( fileType( p_sd, psz_file ) == Video ||
            fileType( p_sd, psz_file ) == Unknown )
        {
            services_discovery_AddItem( p_sd, p_item, NULL );
295

296 297
            msg_Dbg( p_sd, "New recorded video added : %s", psz_file );
        }
298 299 300 301 302 303 304 305 306 307 308 309 310
    }

    vlc_gc_decref( p_item );
    free( psz_uri );

    return VLC_SUCCESS;
}

void formatSnapshotItem( input_item_t *p_item )
{
    if( !p_item )
        return;

311 312
    char* psz_uri = input_item_GetURI( p_item );

313
    /* copy the snapshot mrl as a ArtURL */
Laurent Aimar's avatar
Laurent Aimar committed
314 315
    if( psz_uri )
        input_item_SetArtURL( p_item, psz_uri );
316

317
    free( psz_uri );
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
}


enum type_e fileType( services_discovery_t *p_sd, const char* psz_file )
{
    services_discovery_sys_t *p_sys = p_sd->p_sys;
    enum type_e i_ret = Unknown;

    char* psz_dir = strdup( psz_file );
    char* psz_tmp = strrchr( psz_dir, DIR_SEP_CHAR );
    if( psz_tmp )
        *psz_tmp = '\0';

    int num_dir = sizeof( p_sys->psz_dir ) / sizeof( p_sys->psz_dir[0] );
    for( int i = 0; i < num_dir; i++ )
    {
        char* psz_known_dir = p_sys->psz_dir[i];

        if( psz_known_dir && !strcmp( psz_dir, psz_known_dir ) )
            i_ret = p_sys->i_type;
    }

    free( psz_dir );
    return i_ret;
}
343 344 345 346 347

static int vlc_sd_probe_Open( vlc_object_t *obj )
{
    vlc_probe_t *probe = (vlc_probe_t *)obj;

348
    vlc_sd_probe_Add( probe, "video_dir{longname=\"My Videos\"}",
349
                      N_("My Videos"), SD_CAT_MYCOMPUTER );
350
    vlc_sd_probe_Add( probe, "audio_dir{longname=\"My Music\"}",
351
                      N_("My Music"), SD_CAT_MYCOMPUTER );
352
    vlc_sd_probe_Add( probe, "picture_dir{longname=\"My Pictures\"}",
353
                      N_("My Pictures"), SD_CAT_MYCOMPUTER );
354
    return VLC_PROBE_CONTINUE;
355
}