mediadirs.c 10.9 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
vlc_module_end ()


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

static void* Run( void* );

100
static void input_subnode_added( const vlc_event_t*, void* );
101 102 103 104 105 106 107 108 109 110 111 112
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
    const char *desc;
124 125 126 127 128 129 130 131 132

    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 )
    {
133
        desc = N_("My Videos");
134 135 136
        p_sys->psz_dir[0] = config_GetUserDir( VLC_VIDEOS_DIR );
        p_sys->psz_dir[1] = var_CreateGetString( p_sd, "input-record-path" );

137
        p_sys->psz_var = "record-file";
138 139 140
    }
    else if( p_sys->i_type == Audio )
    {
141
        desc = N_("My Music");
142 143 144
        p_sys->psz_dir[0] = config_GetUserDir( VLC_MUSIC_DIR );
        p_sys->psz_dir[1] = var_CreateGetString( p_sd, "input-record-path" );

145
        p_sys->psz_var = "record-file";
146 147 148
    }
    else if( p_sys->i_type == Picture )
    {
149
        desc = N_("My Pictures");
150 151 152
        p_sys->psz_dir[0] = config_GetUserDir( VLC_PICTURES_DIR );
        p_sys->psz_dir[1] = var_CreateGetString( p_sd, "snapshot-path" );

153
        p_sys->psz_var = "snapshot-file";
154 155 156 157 158 159 160
    }
    else
    {
        free( p_sys );
        return VLC_EGENERIC;
    }

161 162
    p_sd->description = vlc_gettext(desc);

163
    var_AddCallback( p_sd->obj.libvlc, p_sys->psz_var, onNewFileAdded, p_sd );
164 165 166

    if( vlc_clone( &p_sys->thread, Run, p_sd, VLC_THREAD_PRIORITY_LOW ) )
    {
167
        var_DelCallback( p_sd->obj.libvlc, p_sys->psz_var, onNewFileAdded, p_sd );
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
        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            ||
193
            vlc_stat( psz_dir, &st )  ||
194 195 196
            !S_ISDIR( st.st_mode ) )
            continue;

197
        char* psz_uri = vlc_path2uri( psz_dir, "file" );
198

199
        input_item_t* p_root = input_item_New( psz_uri, NULL );
200 201
        if( p_sys->i_type == Picture )
            input_item_AddOption( p_root, "ignore-filetypes=ini,db,lnk,txt",
202
                                  VLC_INPUT_OPTION_TRUSTED|VLC_INPUT_OPTION_UNIQUE );
203

204
        input_item_AddOption( p_root, "recursive=collapse",
205
                              VLC_INPUT_OPTION_TRUSTED|VLC_INPUT_OPTION_UNIQUE );
206 207 208


        vlc_event_manager_t *p_em = &p_root->event_manager;
209 210
        vlc_event_attach( p_em, vlc_InputItemSubItemTreeAdded,
                          input_subnode_added, p_sd );
211

212
        input_Read( p_sd, p_root );
213

214 215
        vlc_event_detach( p_em, vlc_InputItemSubItemTreeAdded,
                          input_subnode_added, p_sd );
216

217
        input_item_Release( p_root );
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
        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 );

234
    var_DelCallback( p_sd->obj.libvlc, p_sys->psz_var, onNewFileAdded, p_sd );
235 236 237 238 239 240 241 242 243 244

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


/*****************************************************************************
 * Callbacks and helper functions
 *****************************************************************************/
245
static void input_subnode_added( const vlc_event_t *p_event, void *user_data )
246 247 248
{
    services_discovery_t *p_sd = user_data;
    services_discovery_sys_t *p_sys = p_sd->p_sys;
249
    input_item_node_t *root = p_event->u.input_item_subitem_tree_added.p_root;
250

251 252 253 254
    for( int i = 0; i < root->i_children; i++ )
    {
        input_item_node_t *child = root->pp_children[i];
        input_item_t *item = child->p_item;
255

256 257
        if( p_sys->i_type == Picture )
            formatSnapshotItem( item );
258

259 260
        services_discovery_AddItem( p_sd, item );
    }
261 262 263 264 265
}

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

268
    services_discovery_t *p_sd = p_data;
269
    services_discovery_sys_t *p_sys = p_sd->p_sys;
270

271
    (void)psz_var; (void)oldval;
272 273 274 275
    char* psz_file = newval.psz_string;
    if( !psz_file || !*psz_file )
        return VLC_EGENERIC;

276
    char* psz_uri = vlc_path2uri( psz_file, "file" );
277
    input_item_t* p_item = input_item_New( psz_uri, NULL );
278

279
    if( p_sys->i_type == Picture )
280
    {
281 282 283
        if( fileType( p_sd, psz_file ) == Picture )
        {
            formatSnapshotItem( p_item );
284
            services_discovery_AddItem( p_sd, p_item );
285

286 287
            msg_Dbg( p_sd, "New snapshot added : %s", psz_file );
        }
288
    }
289
    else if( p_sys->i_type == Audio )
290
    {
291 292
        if( fileType( p_sd, psz_file ) == Audio )
        {
293
            services_discovery_AddItem( p_sd, p_item );
294

295 296
            msg_Dbg( p_sd, "New recorded audio added : %s", psz_file );
        }
297
    }
298
    else if( p_sys->i_type == Video )
299
    {
300 301 302
        if( fileType( p_sd, psz_file ) == Video ||
            fileType( p_sd, psz_file ) == Unknown )
        {
303
            services_discovery_AddItem( p_sd, p_item );
304

305 306
            msg_Dbg( p_sd, "New recorded video added : %s", psz_file );
        }
307 308
    }

309
    input_item_Release( p_item );
310 311 312 313 314 315 316 317 318 319
    free( psz_uri );

    return VLC_SUCCESS;
}

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

320 321
    char* psz_uri = input_item_GetURI( p_item );

322
    /* copy the snapshot mrl as a ArtURL */
Laurent Aimar's avatar
Laurent Aimar committed
323 324
    if( psz_uri )
        input_item_SetArtURL( p_item, psz_uri );
325

326
    free( psz_uri );
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
}


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;
}
352 353 354 355 356

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

357 358 359 360
    vlc_sd_probe_Add( probe, "video_dir", N_("My Videos"), SD_CAT_MYCOMPUTER );
    vlc_sd_probe_Add( probe, "audio_dir", N_("My Music"), SD_CAT_MYCOMPUTER );
    vlc_sd_probe_Add( probe, "picture_dir", N_("My Pictures"),
                      SD_CAT_MYCOMPUTER );
361
    return VLC_PROBE_CONTINUE;
362
}