Example #1
0
/**
 * @brief Update library if new files found or updated
 */
static void UpdateLibrary( monitoring_thread_t *p_mon )
{
    int i_rows, i_cols, i;
    char **pp_results;
    media_library_t *p_ml = p_mon->p_ml;

    struct stat s_stat;

    bool b_recursive = var_GetBool( p_mon, "ml-recursive-scan" );

    msg_Dbg( p_mon, "Scanning directories" );

    Query( p_ml, &pp_results, &i_rows, &i_cols,
              "SELECT id AS directory_id, uri AS directory_uri, "
              "timestamp AS directory_ts FROM directories" );
    msg_Dbg( p_mon, "%d directories to scan", i_rows );

    for( i = 1; i <= i_rows; i++ )
    {
        int id = atoi( pp_results[i*i_cols] );
        char *psz_dir = pp_results[i*i_cols+1];
        int timestamp = atoi( pp_results[i*i_cols+2] );

        if( vlc_stat( psz_dir, &s_stat ) == -1 )
        {
            int err = errno;
            if( err == ENOTDIR || err == ENOENT )
            {
                msg_Dbg( p_mon, "Removing `%s'", psz_dir );
                RemoveDirToMonitor( p_ml, psz_dir );
            }
            else
            {
                msg_Err( p_mon, "%s: %m", psz_dir );
                FreeSQLResult( p_ml, pp_results );
                return;
            }
            errno = err;
        }

        if( !S_ISDIR( s_stat.st_mode ) )
        {
            msg_Dbg( p_mon, "Removing `%s'", psz_dir );
            RemoveDirToMonitor( p_ml, psz_dir );
        }

        if( timestamp < s_stat.st_mtime )
        {
            msg_Dbg( p_mon, "Adding `%s'", psz_dir );
            ScanFiles( p_mon, id, b_recursive, NULL );
        }
    }
    FreeSQLResult( p_ml, pp_results );
}
Example #2
0
int FindAdv( media_library_t *p_ml, vlc_array_t *p_result_array,
             ml_select_e selected_type, const char* psz_lvalue, ml_ftree_t *tree )
{
    int i_ret = VLC_SUCCESS;
    char *psz_query;
    ml_result_type_e result_type;
    char **pp_results = NULL;
    int i_cols, i_rows;

    if( !p_result_array )
        return VLC_EGENERIC;

    i_ret = BuildSelect( p_ml, &psz_query, &result_type, psz_lvalue,
                         selected_type, tree );

    if( i_ret != VLC_SUCCESS )
        return i_ret;

    if( Query( p_ml, &pp_results, &i_rows, &i_cols, "%s", psz_query )
        != VLC_SUCCESS )
    {
        msg_Err( p_ml, "Error occurred while making the query to the database" );
        return VLC_EGENERIC;
    }

    i_ret = SQLToResultArray( p_ml, p_result_array, pp_results, i_rows, i_cols,
                              result_type );

    free( psz_query);
    FreeSQLResult( p_ml, pp_results );

    return i_ret;
}
Example #3
0
/**
 * @brief Remove a directory to monitor
 * @param p_ml A media library object
 * @param psz_dir the directory to remove
 * @return VLC_SUCCESS or VLC_EGENERIC
 */
int RemoveDirToMonitor( media_library_t *p_ml, const char *psz_dir )
{
    assert( p_ml );

    char **pp_results = NULL;
    int i_cols = 0, i_rows = 0, i_ret = VLC_SUCCESS;
    int i;

    bool b_recursive = var_CreateGetBool( p_ml, "ml-recursive-scan" );

    if( b_recursive )
    {
        i_ret = Query( p_ml, &pp_results, &i_rows, &i_cols,
                          "SELECT media.id FROM media JOIN directories ON "
                          "(media.directory_id = directories.id) WHERE "
                          "directories.uri LIKE '%q%%'",
                          psz_dir );
        if( i_ret != VLC_SUCCESS )
        {
            msg_Err( p_ml, "Error occured while making a query to the database" );
            return i_ret;
        }
        QuerySimple( p_ml, "DELETE FROM directories WHERE uri LIKE '%q%%'",
                        psz_dir );
    }
    else
    {
        i_ret = Query( p_ml, &pp_results, &i_rows, &i_cols,
                          "SELECT media.id FROM media JOIN directories ON "
                          "(media.directory_id = directories.id) WHERE "
                          "directories.uri = %Q",
                          psz_dir );
        if( i_ret != VLC_SUCCESS )
        {
            msg_Err( p_ml, "Error occured while making a query to the database" );
            return i_ret;
        }
        QuerySimple( p_ml, "DELETE FROM directories WHERE uri = %Q",
                        psz_dir );
    }

    vlc_array_t *p_where = vlc_array_new();
    for( i = 1; i <= i_rows; i++ )
    {
        int id = atoi( pp_results[i*i_cols] );
        ml_element_t* p_find = ( ml_element_t * ) calloc( 1, sizeof( ml_element_t ) );
        p_find->criteria = ML_ID;
        p_find->value.i = id;
        vlc_array_append( p_where, p_find );
    }
    Delete( p_ml, p_where );

    FreeSQLResult( p_ml, pp_results );
    for( i = 0; i < vlc_array_count( p_where ); i++ )
    {
        free( vlc_array_item_at_index( p_where, i ) );
    }
    vlc_array_destroy( p_where );
    return VLC_SUCCESS;
}
Example #4
0
/**
 * @brief Generic update in Media Library database
 *
 * @param p_ml the media library object
 * @param selected_type the type of the element we're selecting
 * @param where the list of ids or uri to change
 * @param changes list of changes to make in the entries
 * @return VLC_SUCCESS or VLC_EGENERIC
 * @note This function is transactional
 */
int Update( media_library_t *p_ml, ml_select_e selected_type,
        const char* psz_lvalue, ml_ftree_t *where, vlc_array_t *changes )
{
    int i_ret = VLC_EGENERIC;
    char *psz_query = NULL;
    char *psz_id_query = NULL;
    char **pp_results = NULL;
    int i_rows = 0, i_cols = 0;

    i_ret = BuildUpdate( p_ml, &psz_query, &psz_id_query,
                         psz_lvalue, selected_type, where, changes );

    if( i_ret != VLC_SUCCESS )
    {
        msg_Err(p_ml,"Failed to generate update query" );
        return i_ret;
    }
    i_ret = VLC_EGENERIC;

    Begin( p_ml );
    if( QuerySimple( p_ml, "%s", psz_query ) != VLC_SUCCESS )
    {
        msg_Err( p_ml, "Couldn't run the generated update query successfully" );
        goto quitdelete;
    }

    /* Get the updated IDs to send events! */
    if( Query( p_ml, &pp_results, &i_rows, &i_cols, psz_id_query )
            != VLC_SUCCESS )
        goto quitdelete;

    i_ret = VLC_SUCCESS;
quitdelete:
    if( i_ret != VLC_SUCCESS )
        Rollback( p_ml );
    else
    {
        Commit( p_ml );
        if( i_rows > 0 )
        {
            for( int i = 0; i < i_rows; i++ )
            {
                var_SetInteger( p_ml, "media-meta-change",
                        atoi( pp_results[i*i_cols] ) );
            }
        }
    }
    FreeSQLResult( p_ml, pp_results );
    free( psz_id_query );
    free( psz_query );
    return i_ret;
}
Example #5
0
/**
 * @brief Get the list of the monitored directories
 * @param p_ml A media library object
 * @param p_array An initialized array where the list will be put in
 * @return VLC_SUCCESS or VLC_EGENERIC
 */
int ListMonitoredDirs( media_library_t *p_ml, vlc_array_t *p_array )
{
    char **pp_results;
    int i_cols, i_rows;
    int i;

    if( Query( p_ml, &pp_results, &i_rows, &i_cols,
            "SELECT uri AS directory_uri FROM directories WHERE recursive=0" )
        != VLC_SUCCESS )
        return VLC_EGENERIC;

    for( i = 1; i <= i_rows; i++ )
    {
        vlc_array_append( p_array, strdup( pp_results[i] ) );
    }
    FreeSQLResult( p_ml, pp_results );

    return VLC_SUCCESS;
}
Example #6
0
/**
 * @brief Scan files in a particular directory
 */
static void ScanFiles( monitoring_thread_t *p_mon, int i_dir_id,
                       bool b_recursive, stat_list_t *stparent )
{
    int i_rows, i_cols, i_dir_content, i, i_mon_rows, i_mon_cols;
    char **ppsz_monitored_files;
    char **pp_results, *psz_dir;
    char **pp_dir_content;
    bool *pb_processed;
    input_item_t *p_input;
    struct stat s_stat;
    media_library_t *p_ml = (media_library_t *)p_mon->p_ml;

    Query( p_ml, &pp_results, &i_rows, &i_cols,
              "SELECT uri AS directory_uri FROM directories WHERE id = '%d'",
              i_dir_id );
    if( i_rows < 1 )
    {
        msg_Dbg( p_mon, "query returned no directory for dir_id: %d (%s:%d)",
                 i_dir_id, __FILE__, __LINE__ );
        return;
    }
    psz_dir = strdup( pp_results[1] );
    FreeSQLResult( p_ml, pp_results );

    struct stat_list_t stself;

    if( vlc_stat( psz_dir, &stself.st ) == -1 )
    {
        msg_Err( p_ml, "Cannot stat `%s': %m", psz_dir );
        free( psz_dir );
        return;
    }
#ifndef WIN32
    for( stat_list_t *stats = stparent; stats != NULL; stats = stats->parent )
    {
        if( ( stself.st.st_ino == stats->st.st_ino ) &&
            ( stself.st.st_dev == stats->st.st_dev ) )
        {
            msg_Warn( p_ml, "Ignoring infinitely recursive directory `%s'",
                      psz_dir );
            free( psz_dir );
            return;
        }
    }
#else
    /* Windows has st_dev (driver letter - 'A'), but it zeroes st_ino,
     * so that the test above will always incorrectly succeed.
     * Besides, Windows does not have dirfd(). */
#endif
    stself.parent = stparent;

    QuerySimple( p_ml, "UPDATE directories SET timestamp=%d WHERE id = %d",
                    stself.st.st_mtime, i_dir_id );
    Query( p_ml, &ppsz_monitored_files, &i_mon_rows, &i_mon_cols,
              "SELECT id AS media_id, timestamp AS media_ts, uri AS media_uri "
              "FROM media WHERE directory_id = %d",
              i_dir_id );
    pb_processed = malloc(sizeof(bool) * i_mon_rows);
    for( i = 0; i < i_mon_rows ; i++)
        pb_processed[i] = false;

    i_dir_content = vlc_scandir( psz_dir, &pp_dir_content, NULL, Sort );
    if( i_dir_content == -1 )
    {
        msg_Err( p_mon, "Cannot read `%s': %m", psz_dir );
        free( pb_processed );
        free( psz_dir );
        return;
    }
    else if( i_dir_content == 0 )
    {
        msg_Dbg( p_mon, "Nothing in directory `%s'", psz_dir );
        free( pb_processed );
        free( psz_dir );
        return;
    }

    for( i = 0; i < i_dir_content; i++ )
    {
        const char *psz_entry = pp_dir_content[i];

        if( psz_entry[0] != '.' )
        {
            /* 7 is the size of "file://" */
            char psz_uri[strlen(psz_dir) + strlen(psz_entry) + 2 + 7];
            sprintf( psz_uri, "%s/%s", psz_dir, psz_entry );

            if( vlc_stat( psz_uri, &s_stat ) == -1 )
            {
                msg_Err( p_mon, "%s: %m", psz_uri );
                free( pb_processed );
                free( psz_dir );
                return;
            }

            if( S_ISREG( s_stat.st_mode ) )
            {
                const char *psz_dot = strrchr( psz_uri, '.' );
                if( psz_dot++ && *psz_dot )
                {
                    int i_is_media = 0;
                    for( int a = 0; ppsz_MediaExtensions[a]; a++ )
                    {
                        if( !strcasecmp( psz_dot, ppsz_MediaExtensions[a] ) )
                        {
                            i_is_media = 1;
                            break;
                        }
                    }
                    if( !i_is_media )
                    {
                        msg_Dbg( p_mon, "ignoring file %s", psz_uri );
                        continue;
                    }
                }

                char * psz_tmp = encode_URI_component( psz_uri );
                char * psz_encoded_uri = ( char * )calloc( strlen( psz_tmp ) + 9, 1 );
                strcpy( psz_encoded_uri, "file:///" );
                strcat( psz_encoded_uri, psz_tmp );
                free( psz_tmp );

                /* Check if given media is already in DB and it has been updated */
                bool b_skip = false;
                bool b_update = false;
                int j = 1;
                for( j = 1; j <= i_mon_rows; j++ )
                {
                    if( strcasecmp( ppsz_monitored_files[ j * i_mon_cols + 2 ],
                                    psz_encoded_uri ) != 0 )
                        continue;
                    b_update = true;
                    pb_processed[ j - 1 ] = true;
                    if( atoi( ppsz_monitored_files[ j * i_mon_cols + 1 ] )
                        < s_stat.st_mtime )
                    {
                        b_skip = false;
                        break;
                    }
                    else
                    {
                        b_skip = true;
                        break;
                    }
                }
                msg_Dbg( p_ml , "Checking if %s is in DB. Found: %d", psz_encoded_uri,
                         b_skip? 1 : 0 );
                if( b_skip )
                    continue;

                p_input = input_item_New( psz_encoded_uri, psz_entry );

                playlist_t* p_pl = pl_Get( p_mon );
                preparsed_item_t* p_itemobject;
                p_itemobject = malloc( sizeof( preparsed_item_t ) );
                p_itemobject->i_dir_id = i_dir_id;
                p_itemobject->psz_uri = psz_encoded_uri;
                p_itemobject->i_mtime = s_stat.st_mtime;
                p_itemobject->p_mon = p_mon;
                p_itemobject->b_update = b_update;
                p_itemobject->i_update_id = b_update ?
                    atoi( ppsz_monitored_files[ j * i_mon_cols + 0 ] ) : 0 ;

                vlc_event_manager_t *p_em = &p_input->event_manager;
                vlc_event_attach( p_em, vlc_InputItemPreparsedChanged,
                      PreparseComplete, p_itemobject );
                playlist_PreparseEnqueue( p_pl, p_input );
            }
            else if( S_ISDIR( s_stat.st_mode ) && b_recursive )
            {
                Query( p_ml, &pp_results, &i_rows, &i_cols,
                        "SELECT id AS directory_id FROM directories "
                        "WHERE uri=%Q", psz_uri );
                FreeSQLResult( p_ml, pp_results );

                if( i_rows <= 0 )
                {
                    msg_Dbg( p_mon, "New directory `%s' in dir of id %d",
                             psz_uri, i_dir_id );
                    QuerySimple( p_ml,
                                    "INSERT INTO directories (uri, timestamp, "
                                    "recursive) VALUES(%Q, 0, 1)", psz_uri );

                    // We get the id of the directory we've just added
                    Query( p_ml, &pp_results, &i_rows, &i_cols,
                    "SELECT id AS directory_id FROM directories WHERE uri=%Q",
                              psz_uri );
                    if( i_rows <= 0 )
                    {
                        msg_Err( p_mon, "Directory `%s' was not sucessfully"
                                " added to the database", psz_uri );
                        FreeSQLResult( p_ml, pp_results );
                        continue;
                    }

                    ScanFiles( p_mon, atoi( pp_results[1] ), b_recursive,
                               &stself );
                    FreeSQLResult( p_ml, pp_results );
                }
            }
        }
    }

    vlc_array_t* delete_ids = vlc_array_new();
    for( i = 0; i < i_mon_rows; i++ )
    {
       if( !pb_processed[i] )
        {
            /* This file doesn't exist anymore. Let's...urm...delete it. */
            ml_element_t* find = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) );
            find->criteria = ML_ID;
            find->value.i = atoi( ppsz_monitored_files[ (i + 1) * i_mon_cols ] );
            vlc_array_append( delete_ids, find );
       }
    }

    /* Delete the unfound media */
    if( Delete( p_ml, delete_ids ) != VLC_SUCCESS )
        msg_Dbg( p_ml, "Something went wrong in multi delete" );

    for( i = 0; i < vlc_array_count( delete_ids ); i++ )
    {
       free( vlc_array_item_at_index( delete_ids, i ) );
    }
    vlc_array_destroy( delete_ids );

    FreeSQLResult( p_ml, ppsz_monitored_files );
    for( i = 0; i < i_dir_content; i++ )
        free( pp_dir_content[i] );
    free( pp_dir_content );
    free( psz_dir );
    free( pb_processed );
}
Example #7
0
/**
 * @brief Generic DELETE function for many medias
 * Delete a media and all its referencies which don't point
 * an anything else.
 *
 * @param p_ml This media_library_t object
 * @param p_array list of ids to delete
 * @return VLC_SUCCESS or VLC_EGENERIC
 * TODO: Expand to delete media/artist/album given any params
 */
int Delete( media_library_t *p_ml, vlc_array_t *p_array )
{
    char *psz_idlist = NULL, *psz_tmp = NULL;
    int i_return = VLC_ENOMEM;

    int i_rows = 0, i_cols = 0;
    char **pp_results = NULL;

    if( vlc_array_count( p_array ) <= 0 )
    {
        i_return = VLC_SUCCESS;
        goto quit_delete_final;
    }
    for( int i = 0; i < vlc_array_count( p_array ); i++ )
    {
        ml_element_t* find = ( ml_element_t * )
            vlc_array_item_at_index( p_array, i );
        assert( find->criteria == ML_ID );
        if( !psz_idlist )
        {
            if( asprintf( &psz_tmp, "( %d", find->value.i ) == -1)
            {
                goto quit_delete_final;
            }
        }
        else
        {
            if( asprintf( &psz_tmp, "%s, %d", psz_idlist,
                    find->value.i ) == -1)
            {
                goto quit_delete_final;
            }
        }
        free( psz_idlist );
        psz_idlist = psz_tmp;
        psz_tmp = NULL;
    }
    free( psz_tmp );
    if( asprintf( &psz_tmp, "%s )", psz_idlist ? psz_idlist : "(" ) == -1 )
    {
        goto quit_delete_final;
    }
    psz_idlist = psz_tmp;
    psz_tmp = NULL;

    msg_Dbg( p_ml, "Multi Delete id list: %s", psz_idlist );

    /**
     * Below ensures you are emitting media-deleted only
     * for existant media
     */
    Begin( p_ml );
    i_return = Query( p_ml, &pp_results, &i_rows, &i_cols,
            "SELECT id FROM media WHERE id IN %s", psz_idlist );
    if( i_return != VLC_SUCCESS )
        goto quit;

    i_return = QuerySimple( p_ml,
            "DELETE FROM media WHERE media.id IN %s", psz_idlist );
    if( i_return != VLC_SUCCESS )
        goto quit;

    i_return = QuerySimple( p_ml,
            "DELETE FROM extra WHERE extra.id IN %s", psz_idlist );
    if( i_return != VLC_SUCCESS )
        goto quit;

quit:
    if( i_return == VLC_SUCCESS )
    {
        Commit( p_ml );
        /* Emit delete on var media-deleted */
        for( int i = 1; i <= i_rows; i++ )
        {
            var_SetInteger( p_ml, "media-deleted", atoi( pp_results[i*i_cols] ) );
        }
    }
    else
        Rollback( p_ml );
quit_delete_final:
    FreeSQLResult( p_ml, pp_results );
    free( psz_tmp );
    free( psz_idlist );
    return i_return;
}