Big pile of non-sensical and unmaintained code.
AS_IF([test "${enable_media_library}" = "yes"], [
AC_DEFINE([MEDIA_LIBRARY], 1, [Define if you want to use the VLC media library])
VLC_ADD_CPPFLAGS([qt4],"-DMEDIA_LIBRARY")
- VLC_ADD_PLUGIN([media_library])
dnl
dnl SQLite
modules/lua/Makefile
modules/meta_engine/Makefile
modules/misc/Makefile
- modules/media_library/Makefile
modules/mux/Makefile
modules/notify/Makefile
modules/packetizer/Makefile
* magnify: zoom video filter
* marq: Overlays a marquee on the video
* mash: OpenMash based decoder
- * media_library: a sql based media library
* mediacodec: Android Jelly Bean MediaCodec decoder module
* mediadirs: Picture/Music/Video user directories as service discoveries
* minimal_macosx: a minimal Mac OS X GUI, using the FrameWork
gui \
meta_engine \
misc \
- media_library \
notify \
packetizer \
services_discovery \
+++ /dev/null
-SOURCES_media_library = sql_media_library.c \
- sql_media_library.h \
- sql_monitor.c \
- sql_search.c \
- sql_add.c \
- sql_update.c \
- sql_delete.c \
- item_list.c \
- item_list.h \
- ml_watch.c \
- media_pool.c
+++ /dev/null
-/*****************************************************************************
- * item_list.c: An input_item_t+media_id couple list for the media library
- *****************************************************************************
- * Copyright (C) 2008-2010 the VideoLAN Team and AUTHORS
- * $Id$
- *
- * Authors: Antoine Lejeune <phytos@videolan.org>
- * Jean-Philippe André <jpeg@videolan.org>
- * Rémi Duraffort <ivoire@videolan.org>
- * Adrien Maglo <magsoft@videolan.org>
- * Srikanth Raju <srikiraju at gmail dot com>
- *
- * 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.
- *****************************************************************************/
-
-#include "sql_media_library.h"
-#include "item_list.h"
-
-/**
- * @short item hash list for the media library monitoring system
- */
-
-/**
- * @brief Add an item to the head of the list
- * @param p_ml
- * @param p_media media object. ID must be non zero and valid
- * @param p_item input item to add, MUST NOT be NULL
- * @param locked flag set if the list is locked. do not use
- * @return VLC_SUCCESS or VLC_EGENERIC
- */
-int __item_list_add( watch_thread_t *p_wt, ml_media_t* p_media, input_item_t *p_item,
- bool locked )
-{
- if( !locked )
- vlc_mutex_lock( &p_wt->list_mutex );
- ml_LockMedia( p_media );
- assert( p_media->i_id );
- /* Ensure duplication does not occur */
- il_foreachlist( p_wt->p_hlist[ item_hash( p_item ) ], p_elt )
- {
- if( p_elt->p_item->i_id == p_item->i_id )
- {
- ml_UnlockMedia( p_media );
- if( !locked )
- vlc_mutex_unlock( &p_wt->list_mutex );
- return VLC_EGENERIC;
- }
- }
-
- item_list_t *p_new = ( item_list_t* ) calloc( 1, sizeof( item_list_t ) );
- if( !p_new )
- {
- ml_UnlockMedia( p_media );
- if( !locked )
- vlc_mutex_unlock( &p_wt->list_mutex );
- return VLC_ENOMEM;
- }
- p_new->p_next = p_wt->p_hlist[ item_hash( p_item ) ];
- p_new->i_refs = 1;
- p_new->i_media_id = p_media->i_id;
- p_new->p_media = p_media;
- p_new->p_item = p_item;
- p_wt->p_hlist[ item_hash( p_item ) ] = p_new;
- ml_UnlockMedia( p_media );
- if( !locked )
- vlc_mutex_unlock( &p_wt->list_mutex );
- return VLC_SUCCESS;
-}
-
-/**
- * @brief Delete an item from the list
- * @param p_ml this media library
- * @param i_media_id media library's media ID
- */
-item_list_t* item_list_delMedia( watch_thread_t *p_wt, int i_media_id )
-{
- vlc_mutex_lock( &p_wt->list_mutex );
- item_list_t *p_prev = NULL;
- il_foreachhashlist( p_wt->p_hlist, p_elt, ixx )
- {
- if( p_elt->i_media_id == i_media_id )
- {
- if( p_prev )
- p_prev->p_next = p_elt->p_next;
- else
- p_wt->p_hlist[ixx] = p_elt->p_next;
- p_elt->p_next = NULL;
- vlc_mutex_unlock( &p_wt->list_mutex );
- return p_elt;
- }
- else
- {
- p_prev = p_elt;
- }
- }
- vlc_mutex_unlock( &p_wt->list_mutex );
- return NULL;
-}
-
-/**
- * @brief Delete an item from the list and return the single element
- * @param p_ml this media library
- * @param p_item item to delete
- * @return The element from the list containing p_item
- */
-item_list_t* item_list_delItem( watch_thread_t *p_wt, input_item_t *p_item, bool locked )
-{
- if( !locked )
- vlc_mutex_lock( &p_wt->list_mutex );
- item_list_t *p_prev = NULL;
- il_foreachlist( p_wt->p_hlist[ item_hash( p_item ) ], p_elt )
- {
- if( p_elt->p_item == p_item )
- {
- if( p_prev )
- p_prev->p_next = p_elt->p_next;
- else
- p_wt->p_hlist[ item_hash( p_item ) ] = p_elt->p_next;
- p_elt->p_next = NULL;
- if( !locked )
- vlc_mutex_unlock( &p_wt->list_mutex );
- return p_elt;
- }
- else
- {
- p_prev = p_elt;
- }
- }
- if( !locked )
- vlc_mutex_unlock( &p_wt->list_mutex );
- return NULL;
-}
-
-/**
- * @brief Find an input item
- * @param p_ml this media library
- * @param i_media_id item to find and gc_incref
- * @return input item if found, NULL if not found
- */
-input_item_t* item_list_itemOfMediaId( watch_thread_t *p_wt, int i_media_id )
-{
- item_list_t* p_tmp = item_list_listitemOfMediaId( p_wt, i_media_id );
- if( p_tmp )
- return p_tmp->p_item;
- else
- return NULL;
-}
-
-/**
- * @brief Find an item list item
- * @param p_ml this media library
- * @param i_media_id item to find and gc_incref
- * @return input item if found, NULL if not found
- */
-item_list_t* item_list_listitemOfMediaId( watch_thread_t *p_wt, int i_media_id )
-{
- vlc_mutex_lock( &p_wt->list_mutex );
- il_foreachhashlist( p_wt->p_hlist, p_elt, ixx )
- {
- if( p_elt->i_media_id == i_media_id )
- {
- p_elt->i_age = 0;
- vlc_mutex_unlock( &p_wt->list_mutex );
- return p_elt;
- }
- }
- vlc_mutex_unlock( &p_wt->list_mutex );
- return NULL;
-}
-
-/**
- * @brief Find a media
- * @param p_ml this media library
- * @param i_media_id item to find and gc_incref
- * @return media if found. NULL otherwise
- */
-ml_media_t* item_list_mediaOfMediaId( watch_thread_t *p_wt, int i_media_id )
-{
- item_list_t* p_tmp = item_list_listitemOfMediaId( p_wt, i_media_id );
- if( p_tmp )
- return p_tmp->p_media;
- else
- return NULL;
-}
-
-/**
- * @brief Find a media ID by its input_item
- * @param p_ml this media library
- * @param p_item item to find
- * @return media_id found, or VLC_EGENERIC
- */
-int item_list_mediaIdOfItem( watch_thread_t *p_wt, input_item_t *p_item )
-{
- vlc_mutex_lock( &p_wt->list_mutex );
- il_foreachlist( p_wt->p_hlist[ item_hash( p_item ) ], p_elt )
- {
- if( p_elt->p_item == p_item )
- {
- if( p_elt->i_media_id <= 0 )
- /* TODO! */
- p_elt->i_age = 0;
- vlc_mutex_unlock( &p_wt->list_mutex );
- return p_elt->i_media_id;
- }
- }
- vlc_mutex_unlock( &p_wt->list_mutex );
- return VLC_EGENERIC;
-}
-
-/**
- * @brief Find a media by its input_item
- * @param p_ml this media library
- * @param p_item item to find
- * @return media found, or VLC_EGENERIC
- */
-ml_media_t* item_list_mediaOfItem( watch_thread_t *p_wt, input_item_t* p_item,
- bool locked )
-{
- if( !locked )
- vlc_mutex_lock( &p_wt->list_mutex );
- il_foreachlist( p_wt->p_hlist[ item_hash( p_item ) ], p_elt )
- {
- if( p_elt->p_item == p_item )
- {
- p_wt->p_hlist[ item_hash( p_item ) ] = p_elt->p_next;
- p_elt->p_next = NULL;
- if( !locked )
- vlc_mutex_unlock( &p_wt->list_mutex );
- return p_elt->p_media;
- }
- }
- if( !locked )
- vlc_mutex_unlock( &p_wt->list_mutex );
- return NULL;
-}
-/**
- * @brief Flag an item as updated
- * @param p_ml this media library
- * @param p_item item to find and flag
- * @param b_played raise play count or not, update last play
- * @return media_id found, or VLC_EGENERIC
- */
-int item_list_updateInput( watch_thread_t *p_wt, input_item_t *p_item,
- bool b_played )
-{
- vlc_mutex_lock( &p_wt->list_mutex );
- il_foreachlist( p_wt->p_hlist[ item_hash( p_item ) ], p_elt )
- {
- if( p_elt->p_item == p_item )
- {
- /* Item found, flag and return */
- p_elt->i_age = 0;
- p_elt->i_update |= b_played ? 3 : 1;
- vlc_mutex_unlock( &p_wt->list_mutex );
- return p_elt->i_media_id;
- }
- }
- vlc_mutex_unlock( &p_wt->list_mutex );
- return VLC_EGENERIC;
-}
-
-/**
- * @brief Free every item in the item list.
- * @param p_wt Watch thread
- * @note All decref of objects must be handled by watch system
- */
-void item_list_destroy( watch_thread_t* p_wt )
-{
- vlc_mutex_lock( &p_wt->list_mutex );
- for( int i = 0; i < ML_ITEMLIST_HASH_LENGTH ; i++ )
- {
- for( item_list_t* p_elt = p_wt->p_hlist[i] ; p_elt; p_elt = p_wt->p_hlist[i] )
- {
- p_wt->p_hlist[i] = p_elt->p_next;
- free( p_elt );
- }
- }
- vlc_mutex_unlock( &p_wt->list_mutex );
-}
+++ /dev/null
-/*****************************************************************************
- * item_list.h : Item list data structure for Watching system
- *****************************************************************************
- * Copyright (C) 2008-2010 the VideoLAN team and AUTHORS
- * $Id$
- *
- * Authors: Srikanth Raju <srikiraju at gmail dot com>
- *
- * 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.
- *****************************************************************************/
-
-#ifndef ML_ITEM_LIST_H
-#define ML_ITEM_LIST_H
-
-#include <vlc_input.h>
-#include <vlc_arrays.h>
-
-struct watch_thread_t;
-typedef struct watch_thread_t watch_thread_t;
-typedef struct item_list_t item_list_t;
-
-/**
- * Definition of item_list_t
- */
-struct item_list_t {
- input_item_t *p_item; /**< Input item */
- ml_media_t *p_media; /**< Media item */
- item_list_t *p_next; /**< Next element in the list */
- int i_media_id; /**< Media id */
- int i_age; /**< Time spent in this list without activity */
- int i_refs; /**< Number of important refs */
- int i_update; /**< Flag set when the input item is updated:
- 0: no update,
- 1: meta update,
- 2: increment play count,
- 3: both */
-};
-
-#define ML_ITEMLIST_HASH_LENGTH 40
-
-#define il_foreachhashlist( a, b, c ) \
- for( int c = 0 ; c < ML_ITEMLIST_HASH_LENGTH ; c++ ) \
- for( item_list_t* b = a[c]; b; b = b->p_next )
-
-#define il_foreachlist( a, b ) for( item_list_t* b = a ; b; b = b->p_next )
-
-#define item_list_add( a, b, c ) __item_list_add( a, b, c, false )
-
-int __item_list_add( watch_thread_t *p_wt, ml_media_t* p_media,
- input_item_t *p_item, bool );
-item_list_t* item_list_delMedia( watch_thread_t *p_wt, int i_media_id );
-item_list_t* item_list_delItem( watch_thread_t *p_wt, input_item_t *p_item, bool );
-item_list_t* item_list_listitemOfMediaId( watch_thread_t *p_wt, int i_media_id );
-input_item_t* item_list_itemOfMediaId( watch_thread_t *p_wt, int i_media_id );
-ml_media_t* item_list_mediaOfMediaId( watch_thread_t *p_wt, int i_media_id );
-ml_media_t* item_list_mediaOfItem( watch_thread_t *p_wt, input_item_t* p_item, bool );
-int item_list_mediaIdOfItem( watch_thread_t *p_wt, input_item_t *p_item );
-int item_list_updateInput( watch_thread_t *p_wt, input_item_t *p_item,
- bool b_play_count );
-void item_list_destroy( watch_thread_t* p_wt );
-
-/**
- * @brief Simple hash function
- * @param item_id Hash Key
- * @return Hash index
- */
-static inline int item_hash( input_item_t* p_item )
-{
- return DictHash( p_item->psz_uri, ML_ITEMLIST_HASH_LENGTH );
-}
-
-#endif /* ML_ITEM_LIST_H */
+++ /dev/null
-/*****************************************************************************
- * media_pool.c : Media pool for watching system
- *****************************************************************************
- * Copyright (C) 2009-2010 the VideoLAN team and AUTHORS
- * $Id$
- *
- * Authors: Srikanth Raju <srikiraju at gmail dot com>
- *
- * 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.
- *****************************************************************************/
-
-#include "sql_media_library.h"
-
-#define mp_foreachlist( a, b ) for( ml_poolobject_t* b = a; b; b = b->p_next )
-
-static inline int mediapool_hash( int media_id )
-{
- return media_id % ML_MEDIAPOOL_HASH_LENGTH;
-}
-
-/**
- * @brief Get a media from the pool
- * @param p_ml ML object
- * @param media_id The media id of the object to get
- * @return the found media or NULL if not found
- */
-ml_media_t* pool_GetMedia( media_library_t* p_ml, int media_id )
-{
- vlc_mutex_lock( &p_ml->p_sys->pool_mutex );
- ml_media_t* p_media = NULL;
- mp_foreachlist( p_ml->p_sys->p_mediapool[ mediapool_hash( media_id ) ], p_item )
- {
- if( p_item->p_media->i_id == media_id )
- {
- p_media = p_item->p_media;
- break;
- }
- }
- if( p_media )
- ml_gc_incref( p_media );
- vlc_mutex_unlock( &p_ml->p_sys->pool_mutex );
- return p_media;
-}
-
-/**
- * @brief Insert a media into the media pool
- * @param p_ml ML object
- * @param p_media Media object to insert
- * @return VLC_SUCCESS or VLC_EGENERIC
- */
-int pool_InsertMedia( media_library_t* p_ml, ml_media_t* p_media, bool locked )
-{
- if( !locked )
- ml_LockMedia( p_media );
- assert( p_media );
- assert( p_media->i_id > 0 );
- if( p_media->ml_gc_data.pool )
- {
- msg_Dbg( p_ml, "Already in pool! %s %d", p_media->psz_uri, p_media->i_id );
- ml_UnlockMedia( p_media );
- return VLC_EGENERIC;
- }
- p_media->ml_gc_data.pool = true;
- int i_ret = VLC_SUCCESS;
- vlc_mutex_lock( &p_ml->p_sys->pool_mutex );
- mp_foreachlist( p_ml->p_sys->p_mediapool[ (mediapool_hash(p_media->i_id)) ], p_item )
- {
- if( p_media == p_item->p_media )
- {
- i_ret = VLC_EGENERIC;
- break;
- }
- else if( p_media->i_id == p_item->p_media->i_id )
- {
- i_ret = VLC_EGENERIC;
- msg_Warn( p_ml, "A media of the same id was found, but in different objects!" );
- break;
- }
- }
- if( i_ret == VLC_SUCCESS )
- {
- ml_poolobject_t* p_new = ( ml_poolobject_t * ) calloc( 1, sizeof( ml_poolobject_t* ) );
- if( !p_new )
- i_ret = VLC_EGENERIC;
- else
- {
- ml_gc_incref( p_media );
- p_new->p_media = p_media;
- p_new->p_next = p_ml->p_sys->p_mediapool[ ( mediapool_hash( p_media->i_id ) ) ];
- p_ml->p_sys->p_mediapool[ ( mediapool_hash( p_media->i_id ) ) ] = p_new;
- }
- }
- vlc_mutex_unlock( &p_ml->p_sys->pool_mutex );
- if( !locked )
- ml_UnlockMedia( p_media );
- return i_ret;
-}
-
-/**
- * @brief Perform a single garbage collection scan on the media pool
- * @param p_ml The ML object
- * @note Scans all media and removes any medias not held by any other objects.
- */
-void pool_GC( media_library_t* p_ml )
-{
- vlc_mutex_lock( &p_ml->p_sys->pool_mutex );
- ml_poolobject_t* p_prev = NULL;
- ml_media_t* p_media = NULL;
- for( int i_idx = 0; i_idx < ML_MEDIAPOOL_HASH_LENGTH; i_idx++ )
- {
- p_prev = NULL;
- for( ml_poolobject_t* p_item = p_ml->p_sys->p_mediapool[ i_idx ];
- p_item != NULL; p_item = p_item->p_next )
- {
- p_media = p_item->p_media;
- int refs;
- refs = p_media->ml_gc_data.refs;
- if( refs == 1 )
- {
- if( p_prev == NULL )
- p_ml->p_sys->p_mediapool[i_idx] = p_item->p_next;
- else
- p_prev->p_next = p_item->p_next;
- p_media->ml_gc_data.pool = false;
- ml_gc_decref( p_item->p_media );//This should destroy the object
- free( p_item );
- }
- p_prev = p_item;
- }
- }
- vlc_mutex_unlock( &p_ml->p_sys->pool_mutex );
-}
+++ /dev/null
-/*****************************************************************************
- * ml_watch.c: SQL-based media library: Medias watching system
- *****************************************************************************
- * Copyright (C) 2008-2010 the VideoLAN team and AUTHORS
- * $Id$
- *
- * Authors: Antoine Lejeune <phytos@videolan.org>
- * Jean-Philippe André <jpeg@videolan.org>
- * Rémi Duraffort <ivoire@videolan.org>
- * Adrien Maglo <magsoft@videolan.org>
- * Srikanth Raju <srikiraju at gmail dot com>
- *
- * 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.
- *****************************************************************************/
-
-#include "sql_media_library.h"
-#include "item_list.h"
-#include <vlc_events.h>
-
-static void watch_ItemChange( const vlc_event_t *, void * );
-static int watch_PlaylistItemCurrent( vlc_object_t *p_this, char const *psz_var,
- vlc_value_t oldval, vlc_value_t newval,
- void *data );
-static int watch_PlaylistItemAppend( vlc_object_t *p_this, char const *psz_var,
- vlc_value_t oldval, vlc_value_t newval,
- void *data );
-static int watch_PlaylistItemDeleted( vlc_object_t *p_this, char const *psz_var,
- vlc_value_t oldval, vlc_value_t newval,
- void *data );
-static void watch_loop( media_library_t *p_ml, bool b_force );
-static void watch_Thread_Cleanup( void* p_object );
-static int watch_update_Item( media_library_t *p_ml, int i_media_id,
- input_item_t *p_item, bool b_raise_count, bool locked );
-static void watch_ProcessAppendQueue( media_library_t* p_ml );
-
-/**
- * @brief Watching thread
- */
-static void* watch_Thread( void *obj )
-{
- watch_thread_t *p_watch = ( watch_thread_t* )obj;
- media_library_t *p_ml = p_watch->p_ml;
- int i_ret = 0;
-
- vlc_mutex_lock( &p_watch->lock );
- vlc_cleanup_push( watch_Thread_Cleanup, p_ml );
- for( ;; )
- {
- watch_loop( p_ml, !i_ret );
- i_ret = vlc_cond_timedwait( &p_watch->cond, &p_watch->lock,
- mdate() + 1000000 * THREAD_SLEEP_DELAY );
- }
- vlc_cleanup_run();
- return NULL;
-}
-
-/**
- * @brief Callback for thread exit
- */
-static void watch_Thread_Cleanup( void* p_object )
-{
- media_library_t* p_ml = ( media_library_t* )p_object;
- watch_loop( p_ml, true );
- vlc_mutex_unlock( &p_ml->p_sys->p_watch->lock );
-}
-/**
- * @brief Init watching system
- * @return Error if the object or the thread could not be created
- */
-int watch_Init( media_library_t *p_ml )
-{
- /* init and launch watching thread */
- p_ml->p_sys->p_watch = calloc( 1, sizeof(*p_ml->p_sys->p_watch) );
- if( !p_ml->p_sys->p_watch )
- return VLC_ENOMEM;
-
- watch_thread_t* p_wt = p_ml->p_sys->p_watch;
- vlc_mutex_init( &p_wt->list_mutex );
- p_wt->p_ml = p_ml;
-
- vlc_cond_init( &p_wt->cond );
- vlc_mutex_init( &p_wt->lock );
-
- /* Initialise item append queue */
- vlc_mutex_init( &p_wt->item_append_queue_lock );
- p_wt->item_append_queue = NULL;
- p_wt->item_append_queue_count = 0;
-
- if( vlc_clone( &p_wt->thread, watch_Thread, p_wt, VLC_THREAD_PRIORITY_LOW ) )
- {
- msg_Dbg( p_ml, "unable to launch the auto-updating thread" );
- free( p_wt );
- return VLC_EGENERIC;
- }
-
- /* Wait on playlist events
- * playlist-item-append -> entry to playlist
- * activity -> to ensure that we catch played item only!
- * playlist-item-deleted -> exit from playlist
- * item-change -> Currently not required, as we monitor input_item events
- */
- playlist_t *p_pl = pl_Get( p_ml );
- var_AddCallback( p_pl, "activity", watch_PlaylistItemCurrent, p_ml );
- var_AddCallback( p_pl, "playlist-item-append", watch_PlaylistItemAppend, p_ml );
- var_AddCallback( p_pl, "playlist-item-deleted", watch_PlaylistItemDeleted, p_ml );
-
- return VLC_SUCCESS;
-}
-
-/**
- * @brief Add the input to the watch system
- * @param p_ml The Media Library Object
- * @param p_item Item to be watched
- * @param p_media Corresponding media item to sync with
- * @param locked Status of item list lock
- * @return VLC_SUCCESS or error code
- */
-int __watch_add_Item( media_library_t *p_ml, input_item_t *p_item,
- ml_media_t* p_media, bool locked )
-{
- vlc_gc_incref( p_item );
- ml_gc_incref( p_media );
- int i_ret = __item_list_add( p_ml->p_sys->p_watch, p_media, p_item, locked );
- if( i_ret != VLC_SUCCESS )
- return i_ret;
- vlc_event_manager_t *p_em = &p_item->event_manager;
- vlc_event_attach( p_em, vlc_InputItemMetaChanged, watch_ItemChange, p_ml );
- vlc_event_attach( p_em, vlc_InputItemNameChanged, watch_ItemChange, p_ml );
- vlc_event_attach( p_em, vlc_InputItemInfoChanged, watch_ItemChange, p_ml );
- /*
- Note: vlc_InputItemDurationChanged is disabled because
- it is triggered too often, even without consequent changes
- */
- return VLC_SUCCESS;
-}
-
-
-/**
- * @brief Detach event manager
- * @param p_ml The Media Library Object
- */
-static void detachItemEvents( media_library_t *p_ml, input_item_t *p_item )
-{
- vlc_event_manager_t *p_em = &p_item->event_manager;
- vlc_event_detach( p_em, vlc_InputItemMetaChanged, watch_ItemChange, p_ml );
- vlc_event_detach( p_em, vlc_InputItemNameChanged, watch_ItemChange, p_ml );
- vlc_event_detach( p_em, vlc_InputItemInfoChanged, watch_ItemChange, p_ml );
-}
-
-
-/**
- * @brief Close the watching system
- * @param p_ml The Media Library Object
- */
-void watch_Close( media_library_t *p_ml )
-{
- playlist_t *p_pl = pl_Get( p_ml );
- var_DelCallback( p_pl, "playlist-item-deleted", watch_PlaylistItemDeleted, p_ml );
- var_DelCallback( p_pl, "playlist-item-append", watch_PlaylistItemAppend, p_ml );
- var_DelCallback( p_pl, "activity", watch_PlaylistItemCurrent, p_ml );
-
- /* Flush item list */
- il_foreachhashlist( p_ml->p_sys->p_watch->p_hlist, p_elt, ixx )
- {
- detachItemEvents( p_ml, p_elt->p_item );
- ml_gc_decref( p_elt->p_media );
- vlc_gc_decref( p_elt->p_item );
- }
- item_list_destroy( p_ml->p_sys->p_watch );
-
- /* Stop the watch thread and join in */
- vlc_cancel( p_ml->p_sys->p_watch->thread );
- vlc_join( p_ml->p_sys->p_watch->thread, NULL );
-
- /* Clear up other stuff */
- vlc_mutex_destroy( &p_ml->p_sys->p_watch->lock );
- vlc_cond_destroy( &p_ml->p_sys->p_watch->cond );
- vlc_mutex_destroy( &p_ml->p_sys->p_watch->list_mutex );
- free( p_ml->p_sys->p_watch );
-
- free( p_ml->p_sys->p_watch->item_append_queue );
- vlc_mutex_destroy( &p_ml->p_sys->p_watch->item_append_queue_lock );
- p_ml->p_sys->p_watch = NULL;
-}
-
-/**
- * @brief Del item that is currently being watched
- * @param p_ml The Media Library Object
- * @param p_item Item to stop watching
- * @param locked Lock state of item list
- */
-int __watch_del_Item( media_library_t* p_ml, input_item_t* p_item, bool locked )
-{
- assert( p_item );
- item_list_t* p_tmp = item_list_delItem( p_ml->p_sys->p_watch, p_item, locked );
- if( p_tmp == NULL )
- return VLC_EGENERIC;
- detachItemEvents( p_ml, p_tmp->p_item );
- vlc_gc_decref( p_tmp->p_item );
- ml_gc_decref( p_tmp->p_media );
- free( p_tmp );
- return VLC_SUCCESS;
-}
-
-/**
- * @brief Del media from watching by ID
- * @param p_ml The Media Library Object
- * @param i_media_id Media ID
- */
-int watch_del_MediaById( media_library_t* p_ml, int i_media_id )
-{
- assert( i_media_id > 0 );
- item_list_t* p_elt = item_list_delMedia( p_ml->p_sys->p_watch, i_media_id );
- if( p_elt == NULL )
- return VLC_EGENERIC;
- detachItemEvents( p_ml, p_elt->p_item );
- vlc_gc_decref( p_elt->p_item );
- ml_gc_decref( p_elt->p_media );
- free( p_elt );
- return VLC_SUCCESS;
-}
-
-/**
- * @brief Get item using media id, if exists in item list
- * @param p_ml The Media Library Object
- * @param i_media_id Media ID
- */
-input_item_t* watch_get_itemOfMediaId( media_library_t *p_ml, int i_media_id )
-{
- input_item_t* p_tmp = item_list_itemOfMediaId( p_ml->p_sys->p_watch, i_media_id );
- if( p_tmp == NULL )
- return NULL;
- vlc_gc_incref( p_tmp );
- return p_tmp;
-}
-
-/**
- * @brief Get media using media id, if exists in item list
- * @param p_ml The Media Library Object
- * @param i_media_id Media ID
- */
-ml_media_t* watch_get_mediaOfMediaId( media_library_t* p_ml, int i_media_id )
-{
- ml_media_t* p_tmp = item_list_mediaOfMediaId( p_ml->p_sys->p_watch, i_media_id );
- if( p_tmp == NULL )
- return NULL;
- ml_gc_incref( p_tmp );
- return p_tmp;
-}
-
-/**
- * @brief Get mediaid of existing item
- * @param p_ml The Media Library Object
- * @param p_item Pointer to input item
- */
-int watch_get_mediaIdOfItem( media_library_t *p_ml, input_item_t *p_item )
-{
- return item_list_mediaIdOfItem( p_ml->p_sys->p_watch, p_item );
-}
-
-/**
- * @brief Updates a media each time it is changed (name, info or meta)
- */
-static void watch_ItemChange( const vlc_event_t *event, void *data )
-{
- input_item_t *p_item = ( input_item_t* ) event->p_obj;
- media_library_t *p_ml = ( media_library_t* ) data;
- /* Note: we don't add items to the item_list, but normally there should
- not be any item at this point that is not in the list. */
- if( item_list_updateInput( p_ml->p_sys->p_watch, p_item, false ) <= 0 )
- {
-#ifndef NDEBUG
- msg_Dbg( p_ml, "Couldn't update in watch_ItemChange(): (%s:%d)",
- __FILE__, __LINE__ );
-#endif
- }
-
- /*
- if( event->type == vlc_InputItemMetaChanged )
- {
- int id = item_list_mediaIdOfItem( p_ml->p_sys->p_watch, p_item );
- if( !id ) return;
-
- * Tell the world what happened *
- var_SetInteger( p_ml, "media-meta-change", id );
- }
- */
-}
-
-/**
- * @brief Callback when item is added to playlist
- */
-static int watch_PlaylistItemAppend( vlc_object_t *p_this, char const *psz_var,
- vlc_value_t oldval, vlc_value_t newval,
- void *data )
-{
- VLC_UNUSED( oldval );
- VLC_UNUSED( p_this );
- VLC_UNUSED( psz_var );
- media_library_t* p_ml = ( media_library_t* ) data;
- playlist_t* p_playlist = pl_Get( p_ml );
- playlist_add_t* p_add;
- p_add = ( playlist_add_t* ) newval.p_address;
- playlist_item_t* p_pitem = playlist_ItemGetById( p_playlist, p_add->i_item );
- input_item_t* p_item = p_pitem->p_input;
- watch_thread_t* p_wt = p_ml->p_sys->p_watch;
-
- vlc_mutex_lock( &p_wt->list_mutex );
- /* Check if we are already watching this item */
- il_foreachlist( p_wt->p_hlist[ item_hash( p_item ) ], p_elt )
- {
- if( p_elt->p_item->i_id == p_item->i_id )
- {
- p_elt->i_refs++;
- vlc_mutex_unlock( &p_wt->list_mutex );
- goto quit_playlistitemappend;
- }
- }
- vlc_mutex_unlock( &p_wt->list_mutex );
-
- /* Add the the append queue */
- vlc_mutex_lock( &p_wt->item_append_queue_lock );
- p_wt->item_append_queue_count++;
- p_wt->item_append_queue = realloc( p_wt->item_append_queue,
- sizeof( input_item_t* ) * p_wt->item_append_queue_count );
- vlc_gc_incref( p_item );
- p_wt->item_append_queue[ p_wt->item_append_queue_count - 1 ] = p_item;
- vlc_mutex_unlock( &p_wt->item_append_queue_lock );
-quit_playlistitemappend:
- return VLC_SUCCESS;
-}
-
-/**
- * @brief Callback when item is deleted from playlist
- */
-static int watch_PlaylistItemDeleted( vlc_object_t *p_this, char const *psz_var,
- vlc_value_t oldval, vlc_value_t newval,
- void *data )
-{
- VLC_UNUSED( oldval );
- VLC_UNUSED( p_this );
- VLC_UNUSED( psz_var );
- media_library_t* p_ml = ( media_library_t* ) data;
- playlist_t* p_playlist = pl_Get( p_ml );
-
- /* Luckily this works, because the item isn't deleted from PL, yet */
- playlist_item_t* p_pitem = playlist_ItemGetById( p_playlist, newval.i_int );
- input_item_t* p_item = p_pitem->p_input;
-
- /* Find the new item and decrement its ref */
- il_foreachlist( p_ml->p_sys->p_watch->p_hlist[ item_hash( p_item ) ], p_elt )
- {
- if( p_elt->p_item->i_id == p_item->i_id )
- {
- p_elt->i_refs--;
- break;
- }
- }
-
- return VLC_SUCCESS;
-}
-/**
- * @brief Callback when watched input item starts playing
- * @note This will update playcount mainly
- * TODO: Increment playcount on playing 50%(configurable)
- */
-static int watch_PlaylistItemCurrent( vlc_object_t *p_this, char const *psz_var,
- vlc_value_t oldval, vlc_value_t newval,
- void *data )
-{
- (void)p_this;
- (void)oldval;
- (void)newval;
- media_library_t *p_ml = ( media_library_t* ) data;
- input_item_t *p_item = NULL;
-
- /* Get current input */
- input_thread_t *p_input = pl_CurrentInput( p_ml );
- p_item = p_input ? input_GetItem( p_input ) : NULL;
-
- if( p_input )
- vlc_object_release( p_input );
-
- if( !p_item )
- return VLC_EGENERIC;
-
- if( item_list_updateInput( p_ml->p_sys->p_watch, p_item, true ) == 0 )
- {
-#ifndef NDEBUG
- msg_Dbg( p_ml, "couldn't in watch_PlaylistItemCurrent(): (%s:%d)",
- __FILE__, __LINE__ );
-#endif
- }
-
- return VLC_SUCCESS;
-}
-
-/**
- * @brief Update information in the DB for an input item
- *
- * @param p_ml this media library instance
- * @param i_media_id may be 0 (but not recommended)
- * @param p_item input item that was updated
- * @param b_raise_count increment the played count
- * @return result of UpdateMedia()
- */
-static int watch_update_Item( media_library_t *p_ml,
- int i_media_id, input_item_t *p_item,
- bool b_raise_count, bool locked )
-{
-#ifndef NDEBUG
- msg_Dbg( p_ml, "automatically updating media %d", i_media_id );
-#endif
- ml_media_t* p_media = item_list_mediaOfItem( p_ml->p_sys->p_watch, p_item, locked );
- CopyInputItemToMedia( p_media, p_item );
- ml_LockMedia( p_media );
- p_media->i_played_count += b_raise_count ? 1 : 0;
- ml_UnlockMedia( p_media );
- int i_ret = UpdateMedia( p_ml, p_media );
-
- /* Add the poster to the album */
- ml_LockMedia( p_media );
- if( p_media->i_album_id && p_media->psz_cover )
- {
- SetArtCover( p_ml, p_media->i_album_id, p_media->psz_cover );
- }
- ml_UnlockMedia( p_media );
-
- return i_ret;
-}
-
-/**
- * @brief Signals the watch system to update all medias
- */
-void watch_Force_Update( media_library_t* p_ml )
-{
- vlc_mutex_lock( &p_ml->p_sys->p_watch->lock );
- vlc_cond_signal( &p_ml->p_sys->p_watch->cond );
- vlc_mutex_unlock( &p_ml->p_sys->p_watch->lock );
-}
-
-/**
- * @brief Loop on the item_list: old objects collector and automatic updater
- *
- * This function is *not* a garbage collector. It actually decrefs items
- * when they are too old. ITEM_GC_MAX_AGE is the maximum 'time' an item
- * can stay in the list. After that, it is gc_decref'ed but not removed
- * from this list. If you try to get it after that, either the input item
- * is still alive, then you get it, or you'll have
- *
- * The update of an item is done when its age is >= ITEM_LOOP_UPDATE
- * (0 could lead to a too early update)
- *
- * A thread should call this function every N seconds
- *
- * @param p_ml the media library instance
- */
-static void watch_loop( media_library_t *p_ml, bool b_force )
-{
- /* Do the garbage collection */
- pool_GC( p_ml );
-
- /* Process the append queue */
- watch_ProcessAppendQueue( p_ml );
-
- /* Do the item update if necessary */
- vlc_mutex_lock( &p_ml->p_sys->p_watch->list_mutex );
- item_list_t *p_prev = NULL;
- il_foreachhashlist( p_ml->p_sys->p_watch->p_hlist, p_elt, ixx )
- {
- if( ( p_elt->i_update && p_elt->i_age >= ITEM_LOOP_UPDATE )
- || b_force )
- {
- /* This is the automatic delayed update */
- watch_update_Item( p_ml, p_elt->i_media_id, p_elt->p_item,
- ( p_elt->i_update & 2 ) ? true : false, true );
- /* The item gets older */
- p_prev = p_elt;
- p_elt->i_age++;
- p_elt->i_update = false;
- }
- else if( p_elt->i_refs == 0 )
- {
- if( p_elt->i_update )
- watch_update_Item( p_ml, p_elt->i_media_id, p_elt->p_item,
- ( p_elt->i_update & 2 ) ? true : false, true );
- __watch_del_Item( p_ml, p_elt->p_item, true );
- /* TODO: Do something about below crazy hack */
- if( p_prev != NULL )
- p_elt = p_prev;
- else
- {
- ixx--;
- break;
- }
- }
- else
- {
- p_prev = p_elt;
- p_elt->i_age++;
- }
- }
- vlc_mutex_unlock( &p_ml->p_sys->p_watch->list_mutex );
-}
-
-/**
- * This function goes through a queue of input_items and checks
- * if they are present in ML. All the items we wish to add in the
- * watch Queue
- */
-static void watch_ProcessAppendQueue( media_library_t* p_ml )
-{
- watch_thread_t* p_wt = p_ml->p_sys->p_watch;
- vlc_mutex_lock( &p_wt->item_append_queue_lock );
- bool b_add = var_CreateGetBool( p_ml, "ml-auto-add" );
- for( int i = 0; i < p_wt->item_append_queue_count; i++ )
- {
- input_item_t* p_item = p_wt->item_append_queue[i];
- ml_media_t* p_media = NULL;
- /* Is this item in ML? */
- int i_media_id = GetMediaIdOfURI( p_ml, p_item->psz_uri );
- int i_ret = 0;
- if( i_media_id <= 0 )
- {
- if( b_add )
- {
- i_ret = AddInputItem( p_ml, p_item );
- /* FIXME: Need to skip? */
- if( i_ret != VLC_SUCCESS )
- continue;
- i_media_id = GetMediaIdOfURI( p_ml, p_item->psz_uri );
- }
- else
- continue;
- }
- vlc_mutex_lock( &p_wt->list_mutex );
- p_media = media_New( p_ml, i_media_id, ML_MEDIA, true );
- if( p_media == NULL )
- {
- vlc_mutex_unlock( &p_wt->list_mutex );
- continue;
- }
- /* If duplicate, then it just continues */
- i_ret = __watch_add_Item( p_ml, p_item, p_media, true );
- if( i_ret != VLC_SUCCESS )
- {
- ml_gc_decref( p_media );
- vlc_mutex_unlock( &p_wt->list_mutex );
- continue;
- }
-
- /* Find the new item and increment its ref */
- il_foreachlist( p_wt->p_hlist[ item_hash( p_item ) ], p_elt )
- {
- if( p_elt->p_item->i_id == p_item->i_id )
- {
- p_elt->i_refs++;
- break;
- }
- }
- vlc_mutex_unlock( &p_wt->list_mutex );
- ml_gc_decref( p_media );
- }
- p_wt->item_append_queue_count = 0;
- FREENULL( p_wt->item_append_queue );
- vlc_mutex_unlock( &p_wt->item_append_queue_lock );
-}
+++ /dev/null
-/*****************************************************************************
- * sql_add.c: SQL-based media library
- *****************************************************************************
- * Copyright (C) 2008-2010 the VideoLAN Team and AUTHORS
- * $Id$
- *
- * Authors: Antoine Lejeune <phytos@videolan.org>
- * Jean-Philippe André <jpeg@videolan.org>
- * Rémi Duraffort <ivoire@videolan.org>
- * Adrien Maglo <magsoft@videolan.org>
- * Srikanth Raju <srikiraju at gmail dot com>
- *
- * 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.
- *****************************************************************************/
-
-#include "sql_media_library.h"
-
-/*****************************************************************************
- * ADD FUNCTIONS
- *****************************************************************************/
-
-/**
- * @brief Add element to ML based on a ml_media_t (media ID ignored)
- * @param p_ml This media_library_t object
- * @param p_media media item to add in the DB. The media_id is ignored
- * @return VLC_SUCCESS or VLC_EGENERIC
- * @note This function is threadsafe
- */
-int AddMedia( media_library_t *p_ml, ml_media_t *p_media )
-{
- int i_ret = VLC_SUCCESS;
- int i_album_artist = 0;
-
- Begin( p_ml );
- ml_LockMedia( p_media );
- assert( p_media->i_id == 0 );
- /* Add any people */
- ml_person_t* person = p_media->p_people;
- while( person )
- {
- if( person->i_id <= 0 )
- {
- if( person->psz_name )
- {
- person->i_id = ml_GetInt( p_ml, ML_PEOPLE_ID, person->psz_role,
- ML_PEOPLE, person->psz_role,
- person->psz_name );
- if( person->i_id <= 0 )
- {
- /* Create person */
- AddPeople( p_ml, person->psz_name, person->psz_role );
- person->i_id = ml_GetInt( p_ml, ML_PEOPLE_ID, person->psz_role,
- ML_PEOPLE, person->psz_role,
- person->psz_name );
- }
-
- }
- }
- if( strcmp( person->psz_role, ML_PERSON_ALBUM_ARTIST ) == 0 )
- i_album_artist = person->i_id;
- person = person->p_next;
- }
-
- /* Album id */
- if( p_media->i_album_id <= 0 )
- {
- if( p_media->psz_album )
- {
- /* TODO:Solidly incorporate Album artist */
- int i_album_id = ml_GetAlbumId( p_ml, p_media->psz_album );
- if( i_album_id <= 0 )
- {
- /* Create album */
- i_ret = AddAlbum( p_ml, p_media->psz_album, p_media->psz_cover,
- i_album_artist );
- if( i_ret != VLC_SUCCESS )
- return i_ret;
- i_album_id = ml_GetAlbumId( p_ml, p_media->psz_album );
- if( i_album_id <= 0 )
- return i_ret;
- }
- p_media->i_album_id = i_album_id;
- }
- }
-
-
- if( !p_media->psz_uri || !*p_media->psz_uri )
- {
- msg_Dbg( p_ml, "cannot add a media without uri (%s)", __func__ );
- return VLC_EGENERIC;
- }
-
- i_ret = QuerySimple( p_ml,
- "INSERT INTO media ( uri, title, original_title, genre, type, "
- "comment, cover, preview, year, track, disc, album_id, vote, score, "
- "duration, first_played, played_count, last_played, "
- "skipped_count, last_skipped, import_time, filesize ) "
- "VALUES ( %Q, %Q, %Q, %Q, '%d',%Q, %Q, %Q, '%d', '%d', '%d', '%d',"
- "'%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d' )",
- p_media->psz_uri,
- p_media->psz_title,
- p_media->psz_orig_title,
- p_media->psz_genre,
- (int)p_media->i_type,
- p_media->psz_comment,
- p_media->psz_cover,
- p_media->psz_preview,
- (int)p_media->i_year,
- (int)p_media->i_track_number,
- (int)p_media->i_disc_number,
- (int)p_media->i_album_id,
- (int)p_media->i_vote,
- (int)p_media->i_score,
- (int)p_media->i_duration,
- (int)p_media->i_first_played,
- (int)p_media->i_played_count,
- (int)p_media->i_last_played,
- (int)p_media->i_skipped_count,
- (int)p_media->i_last_skipped,
- (int)p_media->i_import_time,
- (int)p_media->i_filesize );
- if( i_ret != VLC_SUCCESS )
- goto quit_addmedia;
-
- int id = GetMediaIdOfURI( p_ml, p_media->psz_uri );
- if( id <= 0 )
- {
- i_ret = VLC_EGENERIC;
- goto quit_addmedia;
- }
-
- p_media->i_id = id;
- person = p_media->p_people;
- if( !person )
- {
- /* If there is no person, set it to "Unknown", ie. people_id=0 */
- i_ret = QuerySimple( p_ml, "INSERT into media_to_people ( media_id, "
- "people_id ) VALUES ( %d, %d )",
- id, 0 );
- if( i_ret != VLC_SUCCESS )
- goto quit_addmedia;
- } else {
- while( person )
- {
- i_ret = QuerySimple( p_ml, "INSERT into media_to_people ( media_id, "
- "people_id ) VALUES ( %d, %d )",
- id, person->i_id );
- if( i_ret != VLC_SUCCESS )
- goto quit_addmedia;
- person = person->p_next;
- }
- }
-
- i_ret = QuerySimple( p_ml, "INSERT into extra ( id, extra, language, bitrate, "
- "samplerate, bpm ) VALUES ( '%d', %Q, %Q, '%d', '%d', '%d' )",
- id, p_media->psz_extra, p_media->psz_language,
- p_media->i_bitrate, p_media->i_samplerate, p_media->i_bpm );
- if( i_ret != VLC_SUCCESS )
- goto quit_addmedia;
- i_ret = pool_InsertMedia( p_ml, p_media, true );
-
-quit_addmedia:
- if( i_ret == VLC_SUCCESS )
- {
- Commit( p_ml );
- }
- else
- Rollback( p_ml );
- ml_UnlockMedia( p_media );
- if( i_ret == VLC_SUCCESS )
- var_SetInteger( p_ml, "media-added", id );
- return i_ret;
-}
-
-
-/**
- * @brief Add generic album to ML
- *
- * @param p_ml this Media Library
- * @param psz_title album title, cannot be null
- * @param psz_cover album cover, can be null
- * @return VLC_SUCCESS or a VLC error code
- *
- * This will add a new in the album table, without checking if album is
- * already present (or another album with same title)
- */
-int AddAlbum( media_library_t *p_ml, const char *psz_title,
- const char *psz_cover, const int i_album_artist )
-{
- assert( p_ml );
-
- if( !psz_title || !*psz_title )
- {
- msg_Warn( p_ml, "tried to add an album without title" );
- return VLC_EGENERIC;
- }
- msg_Dbg( p_ml, "New album: '%s'", psz_title );
-
- int i_ret = QuerySimple( p_ml,
- "INSERT INTO album ( title, cover, album_artist_id ) "
- "VALUES ( %Q, %Q, '%d' )",
- psz_title , psz_cover, i_album_artist );
-
- return i_ret;
-}
-
-
-/**
- * @brief Add generic people to ML
- *
- * @param p_ml this Media Library
- * @param psz_title name
- * @param i_role role: 1 for artist, 2 for publisher
- * @return VLC_SUCCESS or a VLC error code
- *
- * This will add a new in the album table, without checking if album is
- * already present (or another album with same title)
- */
-int AddPeople( media_library_t *p_ml, const char *psz_name,
- const char* psz_role )
-{
- assert( p_ml );
- assert( psz_role && *psz_role );
-
- if( !psz_name || !*psz_name )
- {
- msg_Warn( p_ml, "tried to add an artist without name" );
- return VLC_EGENERIC;
- }
- msg_Dbg( p_ml, "New people: (%s) '%s'", psz_role, psz_name );
-
- int i_ret = QuerySimple( p_ml,
- "INSERT INTO people ( name, role ) "
- "VALUES ( %Q, %Q )",
- psz_name, psz_role );
-
- return i_ret;
-}
-
-/**
- * @brief Add element to ML based on an Input Item
- * @param p_ml This media_library_t object
- * @param p_input input item to add
- * @return VLC_SUCCESS or VLC_EGENERIC
- */
-int AddInputItem( media_library_t *p_ml, input_item_t *p_input )
-{
- assert( p_ml );
- if( !p_input || !p_input->psz_uri )
- return VLC_EGENERIC;
- int i_ret = VLC_SUCCESS;
-
- vlc_gc_incref( p_input );
-
- /* Check input item is not already in the ML */
- i_ret = GetMediaIdOfInputItem( p_ml, p_input );
- if( i_ret > 0 )
- {
- msg_Dbg( p_ml, "Item already in Media Library (id: %d)", i_ret );
- vlc_gc_decref( p_input );
- return VLC_SUCCESS;
- }
-
- ml_media_t* p_media = media_New( p_ml, 0, ML_MEDIA, false );
-
- /* Add media to the database */
- CopyInputItemToMedia( p_media, p_input );
- i_ret = AddMedia( p_ml, p_media );
- if( i_ret == VLC_SUCCESS )
- watch_add_Item( p_ml, p_input, p_media );
- ml_gc_decref( p_media );
- vlc_gc_decref( p_input );
- return i_ret;
-}
-
-
-/**
- * @brief Add element to ML based on a Playlist Item
- *
- * @param p_ml the media library object
- * @param p_playlist_item playlist_item to add
- * @return VLC_SUCCESS or VLC_EGENERIC
- */
-int AddPlaylistItem( media_library_t *p_ml, playlist_item_t *p_playlist_item )
-{
- if( !p_playlist_item )
- return VLC_EGENERIC;
-
- return AddInputItem( p_ml, p_playlist_item->p_input );
-}
-
+++ /dev/null
-/*****************************************************************************
- * sql_delete.c: SQL-based media library: all database delete functions
- *****************************************************************************
- * Copyright (C) 2008-2010 The VideoLAN Team and AUTHORS
- * $Id$
- *
- * Authors: Antoine Lejeune <phytos@videolan.org>
- * Jean-Philippe André <jpeg@videolan.org>
- * Rémi Duraffort <ivoire@videolan.org>
- * Adrien Maglo <magsoft@videolan.org>
- * Srikanth Raju <srikiraju at gmail dot com>
- *
- * 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.
- *****************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "sql_media_library.h"
-
-
-/**
- * @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;
-}
+++ /dev/null
-/*****************************************************************************
- * sql_media_library.c: SQL-based media library
- *****************************************************************************
- * Copyright (C) 2008-2010 the VideoLAN Team and AUTHORS
- * $Id$
- *
- * Authors: Antoine Lejeune <phytos@videolan.org>
- * Jean-Philippe André <jpeg@videolan.org>
- * Rémi Duraffort <ivoire@videolan.org>
- * Adrien Maglo <magsoft@videolan.org>
- * Srikanth Raju <srikiraju at gmail dot com>
- *
- * 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.
- *****************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "sql_media_library.h"
-
-static const char* ppsz_AudioExtensions[] = { EXTENSIONS_AUDIO_CSV, NULL };
-static const char* ppsz_VideoExtensions[] = { EXTENSIONS_VIDEO_CSV, NULL };
-
-#define MEDIA_LIBRARY_PATH_TEXT N_( "Filename of the SQLite database" )
-#define MEDIA_LIBRARY_PATH_LONGTEXT N_( "Path to the file containing " \
- "the SQLite database" )
-
-#define IGNORE_TEXT N_( "Ignored extensions in the media library" )
-#define IGNORE_LONGTEXT N_( "Files with these extensions will not be added to"\
- " the media library when scanning directories." )
-
-#define RECURSIVE_TEXT N_( "Subdirectory recursive scanning" )
-#define RECURSIVE_LONGTEXT N_( "When scanning a directory, scan also all its"\
- " subdirectories." )
-
-
-
-/*****************************************************************************
- * Static functions
- *****************************************************************************/
-
-/* Module entry point and exit point */
-static int load( vlc_object_t* );
-static void unload( vlc_object_t* );
-
-static int CreateInputItemFromMedia( input_item_t **pp_item,
- ml_media_t *p_media );
-
-
-struct ml_table_elt
-{
- int column_id;
- const char* column_name;
-};
-
-static int compare_ml_elts( const void *a, const void *b )
-{
- return strcmp( ( (struct ml_table_elt* )a )->column_name,
- ( ( struct ml_table_elt* )b )->column_name );
-}
-
-static const struct ml_table_elt ml_table_map[]=
-{
- { ML_ALBUM_COVER, "album_cover" },
- { ML_ALBUM_ID, "album_id" },
- { ML_ALBUM, "album_title" },
- { ML_COMMENT, "comment" },
- { ML_COVER, "cover" },
- { ML_DIRECTORY, "directory_id" },
- { ML_DISC_NUMBER, "disc" },
- { ML_DURATION, "duration" },
- { ML_EXTRA, "extra" },
- { ML_FILESIZE, "filesize" },
- { ML_FIRST_PLAYED, "first_played" },
- { ML_GENRE, "genre" },
- { ML_ID, "id" },
- { ML_IMPORT_TIME, "import_time" },
- { ML_LANGUAGE, "language" },
- { ML_LAST_PLAYED, "last_played" },
- { ML_LAST_SKIPPED, "last_skipped" },
- { ML_ORIGINAL_TITLE, "original_title" },
- { ML_PEOPLE_ID, "people_id" },
- { ML_PEOPLE, "people_name" },
- { ML_PEOPLE_ROLE, "people_role" },
- { ML_PLAYED_COUNT, "played_count" },
- { ML_PREVIEW, "preview" },
- { ML_SCORE, "score" },
- { ML_SKIPPED_COUNT, "skipped_count" },
- { ML_TITLE, "title" },
- { ML_TRACK_NUMBER, "track" },
- { ML_TYPE, "type" },
- { ML_URI, "uri" },
- { ML_VOTE, "vote" },
- { ML_YEAR, "year" }
-};
-
-/*****************************************************************************
- * Module description
- *****************************************************************************/
-vlc_module_begin()
- set_shortname( "Media Library" )
- set_description( _( "Media Library based on a SQL based database" ) )
- set_capability( "media-library", 1 )
- set_callbacks( load, unload )
- set_category( CAT_ADVANCED )
- set_subcategory( SUBCAT_ADVANCED_MISC )
- add_string( "ml-filename", "vlc-media-library.db",
- MEDIA_LIBRARY_PATH_TEXT, MEDIA_LIBRARY_PATH_LONGTEXT, false )
- add_string( "ml-username", "", N_( "Username for the database" ),
- N_( "Username for the database" ), false )
- add_string( "ml-password", "", N_( "Password for the database" ),
- N_( "Password for the database" ), false )
- add_integer( "ml-port", 0,
- N_( "Port for the database" ), N_("Port for the database"), false )
- add_bool( "ml-recursive-scan", true, RECURSIVE_TEXT,
- RECURSIVE_LONGTEXT, false )
- add_bool( "ml-auto-add", true, N_("Auto add new medias"),
- N_( "Automatically add new medias to ML" ), false )
- add_bool( "ml-synchronous", true, N_("Use transactions"),
- N_( "Disabling transactions saves I/O but can corrupt database in case of crash" ), false )
-vlc_module_end()
-
-
-/**
- * @brief Load module
- * @param obj Parent object
- */
-static int load( vlc_object_t *obj )
-{
- msg_Dbg( obj, "loading media library module" );
-
- media_library_t *p_ml = ( media_library_t * ) obj;
- p_ml->p_sys = ( media_library_sys_t* )
- calloc( 1, sizeof( media_library_sys_t ) );
- if( !p_ml->p_sys )
- return VLC_ENOMEM;
-
- p_ml->functions.pf_Find = FindVa;
- p_ml->functions.pf_FindAdv = FindAdv;
- p_ml->functions.pf_Control = Control;
- p_ml->functions.pf_InputItemFromMedia = GetInputItemFromMedia;
- p_ml->functions.pf_Update = Update;
- p_ml->functions.pf_Delete = Delete;
- p_ml->functions.pf_GetMedia = GetMedia;
-
- vlc_mutex_init( &p_ml->p_sys->lock );
-
- /* Initialise Sql module */
- if ( InitDatabase( p_ml ) != VLC_SUCCESS )
- {
- vlc_mutex_destroy( &p_ml->p_sys->lock );
- free( p_ml->p_sys );
- return VLC_EGENERIC;
- }
-
- /* Initialise the media pool */
- ARRAY_INIT( p_ml->p_sys->mediapool );
- vlc_mutex_init( &p_ml->p_sys->pool_mutex );
-
- /* Create variables system */
- var_Create( p_ml, "media-added", VLC_VAR_INTEGER );
- var_Create( p_ml, "media-deleted", VLC_VAR_INTEGER );
- var_Create( p_ml, "media-meta-change", VLC_VAR_INTEGER );
-
- /* Launching the directory monitoring thread */
- monitoring_thread_t *p_mon =
- vlc_object_create( p_ml, sizeof( monitoring_thread_t ) );
- if( !p_mon )
- {
- vlc_mutex_destroy( &p_ml->p_sys->lock );
- sql_Destroy( p_ml->p_sys->p_sql );
- free( p_ml->p_sys );
- return VLC_ENOMEM;
- }
- p_ml->p_sys->p_mon = p_mon;
-
- p_mon->p_ml = p_ml;
-
- if( vlc_clone( &p_mon->thread, RunMonitoringThread, p_mon,
- VLC_THREAD_PRIORITY_LOW ) )
- {
- msg_Err( p_ml, "cannot spawn the media library monitoring thread" );
- vlc_mutex_destroy( &p_ml->p_sys->lock );
- sql_Destroy( p_ml->p_sys->p_sql );
- free( p_ml->p_sys );
- vlc_object_release( p_mon );
- return VLC_EGENERIC;
- }
- /* Starting the watching system (starts a thread) */
- watch_Init( p_ml );
-
- msg_Dbg( p_ml, "Media library module loaded successfully" );
-
- return VLC_SUCCESS;
-}
-
-
-/**
- * @brief Unload module
- *
- * @param obj the media library object
- * @return Nothing
- */
-static void unload( vlc_object_t *obj )
-{
- media_library_t *p_ml = ( media_library_t* ) obj;
-
- /* Stopping the watching system */
- watch_Close( p_ml );
-
- /* Stop the monitoring thread */
- vlc_cancel( p_ml->p_sys->p_mon->thread );
- vlc_join( p_ml->p_sys->p_mon->thread, NULL );
- vlc_object_release( p_ml->p_sys->p_mon );
-
- /* Destroy the variable */
- var_Destroy( p_ml, "media-meta-change" );
- var_Destroy( p_ml, "media-deleted" );
- var_Destroy( p_ml, "media-added" );
-
- /* Empty the media pool */
- ml_media_t* item;
- FOREACH_ARRAY( item, p_ml->p_sys->mediapool )
- ml_gc_decref( item );
- FOREACH_END()
- vlc_mutex_destroy( &p_ml->p_sys->pool_mutex );
-
- sql_Destroy( p_ml->p_sys->p_sql );
-
- vlc_mutex_destroy( &p_ml->p_sys->lock );
-
- free( p_ml->p_sys );
-}
-
-/**
- * @brief Get results of an SQL-Query on the database (please : free the result)
- *
- * @param p_ml the media library object
- * @param ppp_res char *** in which to store the table of results (allocated)
- * @param pi_rows resulting row number in table
- * @param pi_cols resulting column number in table
- * @param psz_fmt query command with printf-like format enabled
- * @param va_args format the command
- * @return VLC_SUCCESS or a VLC error code
- */
-int Query( media_library_t *p_ml,
- char ***ppp_res, int *pi_rows, int *pi_cols,
- const char *psz_fmt, ... )
-{
- va_list argp;
- va_start( argp, psz_fmt );
-
- int i_ret = QueryVa( p_ml, ppp_res, pi_rows, pi_cols, psz_fmt, argp );
-
- va_end( argp );
- return i_ret;
-}
-
-/**
- * @brief Get results of an SQL-Query on the database (please : free the result)
- *
- * @param p_ml the media library object
- * @param ppp_res char *** in which to store the table of results (allocated)
- * @param pi_rows resulting row number in table
- * @param pi_cols resulting column number in table
- * @param psz_fmt query command with printf-like format enabled
- * @param va_args format the command
- * @return VLC_SUCCESS or a VLC error code
- */
-int QueryVa( media_library_t *p_ml, char ***ppp_res,
- int *pi_rows, int *pi_cols, const char *psz_fmt,
- va_list argp )
-{
- assert( p_ml );
- if( !ppp_res || !psz_fmt ) return VLC_EGENERIC;
-
- char *psz_query = sql_VPrintf( p_ml->p_sys->p_sql, psz_fmt, argp );
- if( !psz_query )
- return VLC_ENOMEM;
-
- int i_ret = sql_Query( p_ml->p_sys->p_sql, psz_query,
- ppp_res, pi_rows, pi_cols );
-
- free( psz_query );
- return i_ret;
-}
-
-/**
- * @brief Do a SQL-query without any data coming back
- *
- * @param p_ml the media library object
- * @param psz_fmt query command with printf-like format enabled
- * @param va_args format the command
- * @return VLC_SUCCESS or a VLC error code
- */
-int QuerySimple( media_library_t *p_ml,
- const char *psz_fmt, ... )
-{
- va_list argp;
- va_start( argp, psz_fmt );
-
- int i_ret = QuerySimpleVa( p_ml, psz_fmt, argp );
-
- va_end( argp );
- return i_ret;
-}
-
-/**
- * @brief Do a SQL-query without any data coming back
- *
- * @param p_ml the media library object
- * @param psz_fmt query command with printf-like format enabled
- * @param argp format the command
- * @return VLC_SUCCESS or a VLC error code
- */
-int QuerySimpleVa( media_library_t *p_ml,
- const char *psz_fmt, va_list argp )
-{
- assert( p_ml );
-
- int i_ret = VLC_SUCCESS;
- int i_rows, i_cols;
- char **pp_results = NULL;
-
- i_ret = QueryVa( p_ml, &pp_results, &i_rows, &i_cols, psz_fmt, argp );
-
- FreeSQLResult( p_ml, pp_results );
- va_end( argp );
-
- return i_ret;
-}
-
-/**
- * @brief Transforms a string to a ml_result_t, with given type and id (as psz)
- *
- * @param res the result of the function
- * @param psz string to transform into a result
- * @param psz_id id as a string
- * @param result_type type of the result
- * @return ID or a VLC error code
- */
-int StringToResult( ml_result_t *p_result, const char *psz,
- const char *psz_id, ml_result_type_e result_type )
-{
- memset( &p_result->value, 0, sizeof( p_result->value ) );
-
- p_result->id = psz_id ? atoi( psz_id ) : 0;
- p_result->type = result_type;
-
- switch( result_type )
- {
- case ML_TYPE_INT:
- p_result->value.i = psz ? atoi( psz ) : 0;
- break;
-
- case ML_TYPE_TIME:
- p_result->value.time = psz ? ( mtime_t ) atoi( psz )
- : ( mtime_t ) 0LL;
- break;
-
- case ML_TYPE_PSZ:
- p_result->value.psz = psz ? strdup( psz ) : NULL;
- break;
-
- case ML_TYPE_MEDIA:
- default:
- /* This is an error */
- return VLC_EGENERIC;
- }
-
- return p_result->id;
-}
-
-
-/**
- * @brief fills an ml_result_array_t with result of an SQL query
- *
- * @param p_ml the media library object
- * @param p_media ml_result_array_t object to fill
- * @param pp_results result of sql query
- * @param i_rows row number
- * @param i_cols column number
- * @param result_type type of the result
- * @return VLC_SUCCESS or a VLC error code
- **/
-int SQLToResultArray( media_library_t *p_ml, vlc_array_t *p_result_array,
- char **pp_results, int i_rows, int i_cols,
- ml_result_type_e result_type )
-{
- assert( p_ml );
- if( !p_result_array )
- return VLC_EGENERIC;
- if( i_cols == 0 ) /* No result */
- return VLC_SUCCESS;
- if( i_cols < 0 )
- {
- msg_Err( p_ml, "negative number of columns in result ?" );
- return VLC_EGENERIC;
- }
-
- if( i_cols == 1 )
- {
- for( int i = 1; i <= i_rows; i++ )
- {
- ml_result_t *res = ( ml_result_t* )
- calloc( 1, sizeof( ml_result_t ) );
- if( !res )
- return VLC_ENOMEM;
- StringToResult( res, pp_results[ i ], NULL, result_type );
- vlc_array_append( p_result_array, res );
- }
- }
- /* FIXME?: Assuming all double column results are id - result pairs */
- else if( ( i_cols == 2 ) )
- {
- for( int i = 1; i <= i_rows; i++ )
- {
- ml_result_t *res = ( ml_result_t* )
- calloc( 1, sizeof( ml_result_t ) );
- if( !res )
- return VLC_ENOMEM;
- StringToResult( res, pp_results[ i * 2 + 1], pp_results[ i * 2 ],
- result_type );
- vlc_array_append( p_result_array, res );
- }
- }
- else if( result_type == ML_TYPE_MEDIA )
- {
- return SQLToMediaArray( p_ml, p_result_array,
- pp_results, i_rows, i_cols );
- }
- else
- {
- msg_Err( p_ml, "unable to convert SQL result to a ml_result_t array" );
- return VLC_EGENERIC;
- }
- return VLC_SUCCESS;
-}
-
-
-/**
- * @brief fills a vlc_array_t with results of an SQL query
- * medias in ml_result_t
- *
- * @param p_ml the media library object
- * @param p_array array to fill with ml_media_t elements (might be initialized)
- * @param pp_results result of sql query
- * @param i_rows row number
- * @param i_cols column number
- * @return VLC_SUCCESS or a VLC error code
- * Warning: this returns VLC_EGENERIC if i_rows == 0 (empty result)
- **/
-int SQLToMediaArray( media_library_t *p_ml, vlc_array_t *p_result_array,
- char **pp_results, int i_rows, int i_cols )
-{
- int i_ret = VLC_SUCCESS;
- assert( p_ml );
-
- #define res( i, j ) ( pp_results[ i * i_cols + j ] )
- #define atoinull( a ) ( (a) ? atoi( a ) : 0 )
- #define strdupnull( a ) ( (a) ? strdup( a ) : NULL )
-
- if( i_rows == 0 )
- return VLC_EGENERIC;
-
- if( !p_result_array || !pp_results || i_rows < 0 || i_cols <= 0 )
- {
- msg_Warn( p_ml, "bad arguments (%s:%d)", __FILE__, __LINE__ );
- return VLC_EGENERIC;
- }
-
- vlc_array_t* p_intermediate_array = vlc_array_new();
-
- /* Analyze first row */
- int *indexes = ( int* ) calloc( i_cols + 1, sizeof( int ) );
- if( !indexes )
- {
- vlc_array_destroy( p_intermediate_array );
- return VLC_ENOMEM;
- }
-
- const int count = sizeof( ml_table_map )/ sizeof( struct ml_table_elt );
- for( int col = 0; col < i_cols; col++ )
- {
- struct ml_table_elt key, *result = NULL;
- key.column_name = res( 0, col );
- result = bsearch( &key, ml_table_map, count,
- sizeof( struct ml_table_elt ), compare_ml_elts );
-
- if( !result )
- msg_Warn( p_ml, "unknown column: %s", res( 0, col ) );
- else
- indexes[col] = result->column_id;
- }
-
- /* Read rows 1 to i_rows */
- ml_media_t *p_media = NULL;
- ml_result_t *p_result = NULL;
-
- for( int row = 1; ( row <= i_rows ) && ( i_ret == VLC_SUCCESS ); row++ )
- {
- p_media = media_New( p_ml, 0, ML_MEDIA, false );
- if( !p_media )
- {
- free( indexes );
- i_ret = VLC_ENOMEM;
- goto quit_sqlmediaarray;
- }
- p_result = ( ml_result_t * ) calloc( 1, sizeof( ml_result_t ) );
- if( !p_result )
- {
- ml_gc_decref( p_media );
- free( indexes );
- i_ret = VLC_ENOMEM;
- goto quit_sqlmediaarray;
- }
-
- char* psz_append_pname = NULL;
- char* psz_append_prole = NULL;
- int i_append_pid = 0;
-
-#define SWITCH_INT( key, value ) case key: \
- p_media-> value = atoinull( res( row, col ) );
-#define SWITCH_PSZ( key, value ) case key: \
- p_media-> value = strdupnull( res( row, col ) );
-
- ml_LockMedia( p_media );
- for( int col = 0; ( col < i_cols ) && ( i_ret == VLC_SUCCESS ); col++ )
- {
- switch( indexes[ col ] )
- {
- SWITCH_INT( ML_ALBUM_ID, i_album_id );
- SWITCH_PSZ( ML_ALBUM, psz_album );
- SWITCH_PSZ( ML_COMMENT, psz_comment );
- SWITCH_INT( ML_DISC_NUMBER, i_disc_number );
- SWITCH_INT( ML_DURATION, i_duration );
- SWITCH_PSZ( ML_EXTRA, psz_extra );
- SWITCH_INT( ML_FILESIZE, i_filesize );
- SWITCH_INT( ML_FIRST_PLAYED, i_first_played );
- SWITCH_PSZ( ML_GENRE, psz_genre);
- SWITCH_INT( ML_IMPORT_TIME, i_import_time );
- SWITCH_PSZ( ML_LANGUAGE, psz_language );
- SWITCH_INT( ML_LAST_PLAYED, i_last_played );
- SWITCH_INT( ML_LAST_SKIPPED, i_last_skipped );
- SWITCH_PSZ( ML_ORIGINAL_TITLE, psz_orig_title );
- SWITCH_INT( ML_PLAYED_COUNT, i_played_count );
- SWITCH_PSZ( ML_PREVIEW, psz_preview );
- SWITCH_INT( ML_SCORE, i_score );
- SWITCH_INT( ML_SKIPPED_COUNT, i_skipped_count );
- SWITCH_PSZ( ML_TITLE, psz_title );
- SWITCH_INT( ML_TRACK_NUMBER, i_track_number );
- SWITCH_INT( ML_TYPE, i_type );
- SWITCH_INT( ML_VOTE, i_vote);
- SWITCH_INT( ML_YEAR, i_year );
- case ML_ALBUM_COVER:
- /* See ML_COVER */
- // Discard attachment://
- if( !p_media->psz_cover || !*p_media->psz_cover
- || !strncmp( p_media->psz_cover, "attachment://", 13 ) )
- {
- free( p_media->psz_cover );
- p_media->psz_cover = strdupnull( res( row, col ) );
- }
- break;
- case ML_PEOPLE:
- psz_append_pname = strdupnull( res( row, col ) );
- break;
- case ML_PEOPLE_ID:
- i_append_pid = atoinull( res( row, col ) );
- break;
- case ML_PEOPLE_ROLE:
- psz_append_prole = strdupnull( res( row, col ) );
- break;
- case ML_COVER:
- /* See ML_ALBUM_COVER */
- if( !p_media->psz_cover || !*p_media->psz_cover
- || !strncmp( p_media->psz_cover, "attachment://", 13 ) )
- {
- free( p_media->psz_cover );
- p_media->psz_cover = strdupnull( res( row, col ) );
- }
- break;
- case ML_ID:
- p_media->i_id = atoinull( res( row, col ) );
- if( p_media->i_id <= 0 )
- msg_Warn( p_ml, "entry with id null or inferior to zero" );
- break;
- case ML_URI:
- p_media->psz_uri = strdupnull( res( row, col ) );
- if( !p_media->psz_uri )
- msg_Warn( p_ml, "entry without uri" );
- break;
- case ML_DIRECTORY:
- break; // The column directory_id is'nt part of the media model
- default:
- msg_Warn( p_ml, "unknown element, row %d column %d (of %d) - %s - %s",
- row, col, i_cols, res( 0 , col ), res( row, col ) );
- break;
- }
- }
-
-#undef SWITCH_INT
-#undef SWITCH_PSZ
- int i_appendrow;
- ml_result_t* p_append = NULL;
- for( i_appendrow = 0; i_appendrow < vlc_array_count( p_intermediate_array ); i_appendrow++ )
- {
- p_append = ( ml_result_t* )
- vlc_array_item_at_index( p_intermediate_array, i_appendrow );
- if( p_append->id == p_media->i_id )
- break;
- }
- if( i_appendrow == vlc_array_count( p_intermediate_array ) )
- {
- p_result->id = p_media->i_id;
- p_result->type = ML_TYPE_MEDIA;
- p_result->value.p_media = p_media;
- if( psz_append_pname && i_append_pid && psz_append_prole )
- ml_CreateAppendPersonAdv( &(p_result->value.p_media->p_people),
- psz_append_prole, psz_append_pname, i_append_pid );
- vlc_array_append( p_intermediate_array, p_result );
- ml_UnlockMedia( p_media );
- }
- else /* This is a repeat row and the people need to be put together */
- {
- free( p_result );
- ml_LockMedia( p_append->value.p_media );
- if( psz_append_pname && i_append_pid && psz_append_prole )
- ml_CreateAppendPersonAdv( &(p_append->value.p_media->p_people),
- psz_append_prole, psz_append_pname, i_append_pid );
- ml_UnlockMedia( p_append->value.p_media );
- ml_UnlockMedia( p_media );
- ml_gc_decref( p_media );
- }
- FREENULL( psz_append_prole );
- FREENULL( psz_append_pname );
- i_append_pid = 0;
- }
- p_media = NULL;
- free( indexes );
-
- /* Now check if these medias are already on the pool, and sync */
- for( int i = 0; i < vlc_array_count( p_intermediate_array ); i++ )
- {
- p_result =
- ( ml_result_t* )vlc_array_item_at_index( p_intermediate_array, i );
- p_media = p_result->value.p_media;
- ml_media_t* p_poolmedia = pool_GetMedia( p_ml, p_result->id );
- /* TODO: Pool_syncMedia might be cleaner? */
-
- p_result = ( ml_result_t* ) calloc( 1, sizeof( ml_result_t * ) );
- if( !p_result )
- goto quit_sqlmediaarray;
- if( p_poolmedia )
- {
- /* TODO: This might cause some weird stuff to occur w/ GC? */
- ml_CopyMedia( p_poolmedia, p_media );
- p_result->id = p_poolmedia->i_id;
- p_result->type = ML_TYPE_MEDIA;
- p_result->value.p_media = p_poolmedia;
- vlc_array_append( p_result_array, p_result );
- }
- else
- {
- i_ret = pool_InsertMedia( p_ml, p_media, false );
- if( i_ret == VLC_SUCCESS )
- {
- ml_gc_incref( p_media );
- p_result->id = p_media->i_id;
- p_result->type = ML_TYPE_MEDIA;
- p_result->value.p_media = p_media;
- vlc_array_append( p_result_array, p_result );
- }
- }
- }
-
- #undef strdupnull
- #undef atoinull
- #undef res
-quit_sqlmediaarray:
- for( int k = 0; k < vlc_array_count( p_intermediate_array ); k++ )
- {
- ml_result_t* temp = ((ml_result_t*)vlc_array_item_at_index( p_intermediate_array, k ));
- ml_FreeResult( temp );
- }
- vlc_array_destroy( p_intermediate_array );
- return i_ret;
-}
-
-
-/**
- * @brief Returns (unique) ID of media with specified URI
- *
- * @param p_ml the media library object
- * @param psz_uri URI to look for
- * @return i_id: (first) ID found, VLC_EGENERIC in case of error
- * NOTE: Normally, there should not be more than one ID with one URI
- */
-int GetMediaIdOfURI( media_library_t *p_ml, const char *psz_uri )
-{
- int i_ret = VLC_EGENERIC;
- vlc_array_t *p_array = vlc_array_new();
- i_ret = Find( p_ml, p_array, ML_ID, ML_URI, psz_uri, ML_LIMIT, 1, ML_END );
- if( ( i_ret == VLC_SUCCESS )
- && ( vlc_array_count( p_array ) > 0 )
- && vlc_array_item_at_index( p_array, 0 ) )
- {
- i_ret = ( (ml_result_t*)vlc_array_item_at_index( p_array, 0 ) )
- ->value.i;
- }
- else
- {
- i_ret = VLC_EGENERIC;
- }
- vlc_array_destroy( p_array );
- return i_ret;
-}
-
-
-/**
- * @brief Control function for media library
- *
- * @param p_ml Media library handle
- * @param i_query query type
- * @param args query arguments
- * @return VLC_SUCCESS if ok
- */
-int Control( media_library_t *p_ml, int i_query, va_list args )
-{
- switch( i_query )
- {
- case ML_ADD_INPUT_ITEM:
- {
- input_item_t *p_item = (input_item_t *)va_arg( args, input_item_t * );
- return AddInputItem( p_ml, p_item );
- }
-
- case ML_ADD_PLAYLIST_ITEM:
- {
- playlist_item_t *p_item = (playlist_item_t *)va_arg( args, playlist_item_t * );
- return AddPlaylistItem( p_ml, p_item );
- }
-
- case ML_ADD_MONITORED:
- {
- char *psz_dir = (char *)va_arg( args, char * );
- return AddDirToMonitor( p_ml, psz_dir );
- }
-
- case ML_GET_MONITORED:
- {
- vlc_array_t *p_array = (vlc_array_t *)va_arg( args, vlc_array_t * );
- return ListMonitoredDirs( p_ml, p_array );
- }
-
- case ML_DEL_MONITORED:
- {
- char *psz_dir = (char *)va_arg( args, char * );
- return RemoveDirToMonitor( p_ml, psz_dir );
- }
-
- default:
- return VLC_EGENERIC;
- }
-}
-
-
-/**
- * @brief Create a new (empty) database. The database might be initialized
- *
- * @param p_ml This ML
- * @return VLC_SUCCESS or VLC_EGENERIC
- * @note This function is transactional
- */
-int CreateEmptyDatabase( media_library_t *p_ml )
-{
- assert( p_ml );
- int i_ret = VLC_SUCCESS;
- msg_Dbg( p_ml, "creating a new (empty) database" );
-
- Begin( p_ml );
-
- /* Albums */
- i_ret= QuerySimple( p_ml,
- "CREATE TABLE album ( "
- "id INTEGER PRIMARY KEY,"
- "album_artist_id INTEGER,"
- "title VARCHAR(1024),"
- "cover VARCHAR(1024) )" );
- if( i_ret != VLC_SUCCESS )
- goto quit_createemptydatabase;
-
- i_ret = QuerySimple( p_ml, "CREATE INDEX album_title_index ON album (title);" );
- if( i_ret != VLC_SUCCESS )
- goto quit_createemptydatabase;
-
- /* Add "unknown" entry to albums */
- i_ret = QuerySimple( p_ml,
- "INSERT INTO album ( id, title, cover, album_artist_id ) "
- "VALUES ( 0, 'Unknown', '', 0 )" );
-
- if( i_ret != VLC_SUCCESS )
- goto quit_createemptydatabase;
-
- /* Main media table */
- i_ret= QuerySimple( p_ml,
- "CREATE TABLE media ( "
- "id INTEGER PRIMARY KEY,"
- "timestamp INTEGER," /* File timestamp */
- "uri VARCHAR(1024),"
- "type INTEGER,"
- "title VARCHAR(1024),"
- "original_title VARCHAR(1024),"
- "album_id INTEGER,"
- "cover VARCHAR(1024),"
- "preview VARCHAR(1024)," /* Video preview */
- "track INTEGER," /* Track number */
- "disc INTEGER," /* Disc number */
- "year INTEGER,"
- "genre VARCHAR(1024),"
- "vote INTEGER," /* Rating/Stars */
- "score INTEGER," /* ML score/rating */
- "comment VARCHAR(1024)," /* Comment */
- "filesize INTEGER,"
- /* Dates and times */
- "duration INTEGER," /* Length of media */
- "played_count INTEGER,"
- "last_played DATE,"
- "first_played DATE,"
- "import_time DATE,"
- "skipped_count INTEGER,"
- "last_skipped DATE,"
- "directory_id INTEGER,"
- "CONSTRAINT associated_album FOREIGN KEY(album_id) "
- "REFERENCES album(id) ON DELETE SET DEFAULT ON UPDATE RESTRICT)" );
- if( i_ret != VLC_SUCCESS )
- goto quit_createemptydatabase;
-
- i_ret = QuerySimple( p_ml, "CREATE INDEX media_ui_index ON media (uri);" );
- if( i_ret != VLC_SUCCESS )
- goto quit_createemptydatabase;
-
- /* People */
- i_ret = QuerySimple( p_ml,
- "CREATE TABLE people ( "
- "id INTEGER PRIMARY KEY,"
- "name VARCHAR(1024) ,"
- "role VARCHAR(1024) )" );
- if( i_ret != VLC_SUCCESS )
- goto quit_createemptydatabase;
-
- /* Media to people */
- i_ret = QuerySimple( p_ml,
- "CREATE TABLE media_to_people ( "
- "media_id INTEGER, "
- "people_id INTEGER, "
- "PRIMARY KEY( media_id, people_id ), "
- "CONSTRAINT associated_people FOREIGN KEY(people_id) "
- "REFERENCES people(id) ON DELETE SET DEFAULT ON UPDATE RESTRICT, "
- "CONSTRAINT associated_media FOREIGN KEY(media_id) "
- "REFERENCES media(id) ON DELETE CASCADE ON UPDATE RESTRICT )" );
- if( i_ret != VLC_SUCCESS )
- goto quit_createemptydatabase;
-
- /* Add "unknown" entry to people */
- i_ret = QuerySimple( p_ml,
- "INSERT INTO people ( id, name, role ) "
- "VALUES ( 0, 'Unknown', NULL )" );
- if( i_ret != VLC_SUCCESS )
- goto quit_createemptydatabase;
-
- /* recursive is set to 1 if the directory is added to the database
- by recursion and 0 if not */
- i_ret = QuerySimple( p_ml,
- "CREATE TABLE directories ( "
- "id INTEGER PRIMARY KEY,"
- "uri VARCHAR(1024),"
- "timestamp INTEGER,"
- "recursive INTEGER )" );
- if( i_ret != VLC_SUCCESS )
- goto quit_createemptydatabase;
-
- /* Create information table
- * This table should have one row and the version number is the version
- * of the database
- * Other information may be stored here at later stages */
- i_ret = QuerySimple( p_ml,
- "CREATE TABLE information ( "
- "version INTEGER PRIMARY KEY )" );
- if( i_ret != VLC_SUCCESS )
- goto quit_createemptydatabase;
-
- /* Insert current DB version */
- i_ret = QuerySimple( p_ml,
- "INSERT INTO information ( version ) "
- "VALUES ( %d )", ML_DBVERSION );
- if( i_ret != VLC_SUCCESS )
- goto quit_createemptydatabase;
-
- /* Text data: song lyrics or subtitles */
- i_ret = QuerySimple( p_ml,
- "CREATE TABLE extra ( "
- "id INTEGER PRIMARY KEY,"
- "extra TEXT,"
- "language VARCHAR(256),"
- "bitrate INTEGER,"
- "samplerate INTEGER,"
- "bpm INTEGER )" );
- if( i_ret != VLC_SUCCESS )
- goto quit_createemptydatabase;
-
- /* Emulating foreign keys with triggers */
- /* Warning: Lots of SQL */
- if( !strcmp( module_get_name( p_ml->p_sys->p_sql->p_module, false ),
- "SQLite" ) )
- {
- i_ret = QuerySimple( p_ml,
- "\nCREATE TRIGGER genfkey1_insert_referencing BEFORE INSERT ON \"media\" WHEN\n"
- " new.\"album_id\" IS NOT NULL AND NOT EXISTS (SELECT 1 FROM \"album\" WHERE new.\"album_id\" == \"id\")\n"
- "BEGIN\n"
- " SELECT RAISE(ABORT, 'constraint genfkey1_insert_referencing failed. Cannot insert album_id into media. Album did not exist');\n"
- "END;\n"
- "\n"
- "CREATE TRIGGER genfkey1_update_referencing BEFORE\n"
- " UPDATE OF album_id ON \"media\" WHEN \n"
- " new.\"album_id\" IS NOT NULL AND \n"
- " NOT EXISTS (SELECT 1 FROM \"album\" WHERE new.\"album_id\" == \"id\")\n"
- "BEGIN\n"
- " SELECT RAISE(ABORT, 'constraint genfkey1_update_referencing failed. Cannot update album_id in media. Album did not exist');\n"
- "END;\n"
- "\n"
- "CREATE TRIGGER genfkey1_delete_referenced BEFORE DELETE ON \"album\" WHEN\n"
- " EXISTS (SELECT 1 FROM \"media\" WHERE old.\"id\" == \"album_id\")\n"
- "BEGIN\n"
- " SELECT RAISE(ABORT, 'constraint genfkey1_delete_referenced failed. Cannot delete album, media still exist');\n"
- "END;\n"
- "\n"
- "\n"
- "CREATE TRIGGER genfkey1_update_referenced AFTER\n"
- " UPDATE OF id ON \"album\" WHEN \n"
- " EXISTS (SELECT 1 FROM \"media\" WHERE old.\"id\" == \"album_id\")\n"
- "BEGIN\n"
- " SELECT RAISE(ABORT, 'constraint genfkey1_update_referenced failed. Cannot change album id in album, media still exist');\n"
- "END;\n"
- "\n"
- "\n"
- "CREATE TRIGGER genfkey2_insert_referencing BEFORE INSERT ON \"media_to_people\" WHEN \n"
- " new.\"media_id\" IS NOT NULL AND NOT EXISTS (SELECT 1 FROM \"media\" WHERE new.\"media_id\" == \"id\")\n"
- "BEGIN\n"
- " SELECT RAISE(ABORT, 'constraint genfkey2_insert_referencing failed. Cannot insert into media_to_people, that media does not exist');\n"
- "END;\n"
- "\n"
- "CREATE TRIGGER genfkey2_update_referencing BEFORE\n"
- " UPDATE OF media_id ON \"media_to_people\" WHEN \n"
- " new.\"media_id\" IS NOT NULL AND \n"
- " NOT EXISTS (SELECT 1 FROM \"media\" WHERE new.\"media_id\" == \"id\")\n"
- "BEGIN\n"
- " SELECT RAISE(ABORT, 'constraint genfkey2_update_referencing failed. Cannot update media_to_people, that media does not exist');\n"
- "END;\n"
- "\n"
- "CREATE TRIGGER genfkey2_delete_referenced BEFORE DELETE ON \"media\" WHEN\n"
- " EXISTS (SELECT 1 FROM \"media_to_people\" WHERE old.\"id\" == \"media_id\")\n"
- "BEGIN\n"
- " DELETE FROM \"media_to_people\" WHERE \"media_id\" = old.\"id\";\n"
- "END;\n"
- "\n"
- "CREATE TRIGGER genfkey2_update_referenced AFTER\n"
- " UPDATE OF id ON \"media\" WHEN \n"
- " EXISTS (SELECT 1 FROM \"media_to_people\" WHERE old.\"id\" == \"media_id\")\n"
- "BEGIN\n"
- " SELECT RAISE(ABORT, 'constraint genfkey2_update_referenced failed. Cannot update media id, refs still exist in media_to_people');\n"
- "END;\n"
- "\n"
- "CREATE TRIGGER genfkey3_insert_referencing BEFORE INSERT ON \"media_to_people\" WHEN \n"
- " new.\"people_id\" IS NOT NULL AND NOT EXISTS (SELECT 1 FROM \"people\" WHERE new.\"people_id\" == \"id\")\n"
- "BEGIN\n"
- " SELECT RAISE(ABORT, 'constraint genfkey3_insert_referencing failed. Cannot insert into media_to_people, people does not exist');\n"
- "END;\n"
- "CREATE TRIGGER genfkey3_update_referencing BEFORE\n"
- " UPDATE OF people_id ON \"media_to_people\" WHEN \n"
- " new.\"people_id\" IS NOT NULL AND \n"
- " NOT EXISTS (SELECT 1 FROM \"people\" WHERE new.\"people_id\" == \"id\")\n"
- "BEGIN\n"
- " SELECT RAISE(ABORT, 'constraint genfkey3_update_referencing failed. Cannot update media_to_people, people does not exist');\n"
- "END;\n"
- "\n"
- "CREATE TRIGGER genfkey3_delete_referenced BEFORE DELETE ON \"people\" WHEN\n"
- " EXISTS (SELECT 1 FROM \"media_to_people\" WHERE old.\"id\" == \"people_id\")\n"
- "BEGIN\n"
- " UPDATE media_to_people SET people_id = 0 WHERE people_id == old.\"id\";\n"
- "END;\n"
- "\n"
- "CREATE TRIGGER genfkey3_update_referenced AFTER\n"
- " UPDATE OF id ON \"people\" WHEN \n"
- " EXISTS (SELECT 1 FROM \"media_to_people\" WHERE old.\"id\" == \"people_id\")\n"
- "BEGIN\n"
- " SELECT RAISE(ABORT, 'constraint genfkey3_update_referenced failed. Cannot update people_id, people does not exist');\n"
- "END;\n"
- "\n"
- "CREATE TRIGGER keep_people_clean AFTER \n"
- " DELETE ON \"media_to_people\"\n"
- " WHEN NOT EXISTS( SELECT 1 from \"media_to_people\" WHERE old.\"people_id\" == \"people_id\" )\n"
- "BEGIN\n"
- " DELETE FROM people WHERE people.id = old.\"people_id\" AND people.id != 0;\n"
- "END;\n"
- "\n"
- "CREATE TRIGGER keep_album_clean AFTER\n"
- " DELETE ON \"media\"\n"
- " WHEN NOT EXISTS( SELECT 1 FROM \"media\" WHERE old.\"album_id\" == \"album_id\" )\n"
- "BEGIN\n"
- " DELETE FROM album WHERE album.id = old.\"album_id\" AND album.id != 0;\n"
- "END;" );
- if( i_ret != VLC_SUCCESS )
- goto quit_createemptydatabase;
- }
-
-quit_createemptydatabase:
- if( i_ret == VLC_SUCCESS )
- Commit( p_ml );
- else
- Rollback( p_ml );
- return VLC_SUCCESS;
-}
-
-/**
- * @brief Journal and synchronous disc and writes
- *
- * @param p_ml media library object
- * @param b_sync boolean
- * @return <= 0 on error.
- */
-static int SetSynchronous( media_library_t *p_ml, bool b_sync )
-{
- int i_rows, i_cols;
- char **pp_results;
- int i_return;
- if ( b_sync )
- i_return = Query( p_ml, &pp_results, &i_rows, &i_cols,
- "PRAGMA synchronous = ON;PRAGMA journal_mode = TRUNCATE" );
- else
- i_return = Query( p_ml, &pp_results, &i_rows, &i_cols,
- "PRAGMA synchronous = OFF;PRAGMA journal_mode = MEMORY" );
- if( i_return != VLC_SUCCESS )
- i_return = -1;
- else
- i_return = atoi( pp_results[ 1 ] );
-
- FreeSQLResult( p_ml, pp_results );
-
- return i_return;
-}
-
-/**
- * @brief Initiates database (create the database and the tables if needed)
- *
- * @param p_ml This ML
- * @return VLC_SUCCESS or an error code
- */
-int InitDatabase( media_library_t *p_ml )
-{
- assert( p_ml );
- msg_Dbg( p_ml, "initializing database" );
-
- /* Select database name */
- char *psz_dbhost = NULL, *psz_user = NULL, *psz_pass = NULL;
- int i_port = 0;
- bool b_sync = false;
- psz_dbhost = config_GetPsz( p_ml, "ml-filename" );
- psz_user = config_GetPsz( p_ml, "ml-username" );
- psz_pass = config_GetPsz( p_ml, "ml-password" );
- i_port = config_GetInt( p_ml, "ml-port" );
- b_sync = config_GetInt( p_ml, "ml-synchronous" );
-
- /* Let's consider that a filename with a DIR_SEP is a full URL */
- if( strchr( psz_dbhost, DIR_SEP_CHAR ) == NULL )
- {
- char *psz_datadir = config_GetUserDir( VLC_DATA_DIR );
- char *psz_tmp = psz_dbhost;
- if( asprintf( &psz_dbhost, "%s" DIR_SEP "%s",
- psz_datadir, psz_tmp ) == -1 )
- {
- free( psz_datadir );
- free( psz_tmp );
- return VLC_ENOMEM;
- }
- free( psz_datadir );
- free( psz_tmp );
- }
-
- p_ml->p_sys->p_sql = sql_Create( p_ml, NULL, psz_dbhost, i_port, psz_user,
- psz_pass );
- if( !p_ml->p_sys->p_sql )
- return VLC_EGENERIC;
-
- /* Let's check if tables exist */
- int i_version = GetDatabaseVersion( p_ml );
- if( i_version <= 0 )
- CreateEmptyDatabase( p_ml );
- else if( i_version != ML_DBVERSION )
- return VLC_EGENERIC;
-
- /**
- * The below code ensures that correct code is written
- * when database versions are changed
- */
-
-#if ML_DBVERSION != 1
-#error "ML versioning code needs to be updated. Is this done correctly?"
-#endif
-
- SetSynchronous( p_ml, b_sync );
-
- msg_Dbg( p_ml, "ML initialized" );
- return VLC_SUCCESS;
-}
-
-/**
- * @brief Gets the current version number from the database
- *
- * @param p_ml media library object
- * @return version number of the current db. <= 0 on error.
- */
-int GetDatabaseVersion( media_library_t *p_ml )
-{
- int i_rows, i_cols;
- char **pp_results;
- int i_return;
- i_return = Query( p_ml, &pp_results, &i_rows, &i_cols,
- "SELECT version FROM information ORDER BY version DESC LIMIT 1" );
- if( i_return != VLC_SUCCESS )
- i_return = -1;
- else
- i_return = atoi( pp_results[ 1 ] );
-
- FreeSQLResult( p_ml, pp_results );
-
- return i_return;
-}
-
- /**
- * @brief Object constructor for ml_media_t
- * @param p_ml The media library object
- * @param id If 0, this item isn't in database. If non zero, it is and
- * it will be a singleton
- * @param select Type of object
- * @param reload Whether to reload from database
- */
-ml_media_t* GetMedia( media_library_t* p_ml, int id,
- ml_select_e select, bool reload )
-{
- assert( id > 0 );
- assert( select == ML_MEDIA || select == ML_MEDIA_SPARSE );
- int i_ret = VLC_SUCCESS;
- ml_media_t* p_media = NULL;
- if( !reload )
- {
- p_media = pool_GetMedia( p_ml, id );
- if( !p_media )
- reload = true;
- else
- {
- ml_LockMedia( p_media );
- if( p_media->b_sparse && select == ML_MEDIA )
- reload = true;
- /* Utilise ML_MEDIA_EXTRA load? TODO */
- ml_UnlockMedia( p_media );
- ml_gc_incref( p_media );
- }
- }
- else
- {
- vlc_array_t *p_array = vlc_array_new();
- i_ret = ml_Find( p_ml, p_array, select, ML_ID, id );
- assert( vlc_array_count( p_array ) == 1 );
- if( ( i_ret == VLC_SUCCESS )
- && ( vlc_array_count( p_array ) > 0 )
- && vlc_array_item_at_index( p_array, 0 ) )
- {
- p_media = ((ml_result_t*)vlc_array_item_at_index( p_array, 0 ))->value.p_media;
- ml_gc_incref( p_media );
- ml_FreeResult( vlc_array_item_at_index( p_array, 0 ) );
- }
- vlc_array_destroy( p_array );
- if( select == ML_MEDIA )
- p_media->b_sparse = false;
- else
- p_media->b_sparse = true;
- }
- return p_media;
-}
-/**
- * @brief Create an input item from media (given its ID)
- *
- * @param p_ml This media_library_t object
- * @param i_media Media ID
- * @return input_item_t* created
- *
- * @note This is a public function (pf_InputItemFromMedia)
- * The input_item will have a refcount at 2 (1 for the ML, 1 for you)
- */
-input_item_t* GetInputItemFromMedia( media_library_t *p_ml, int i_media )
-{
- input_item_t *p_item = NULL;
-
- p_item = watch_get_itemOfMediaId( p_ml, i_media );
- if( !p_item )
- {
- ml_media_t* p_media = media_New( p_ml, i_media, ML_MEDIA, true );
- if( p_media == NULL )
- return NULL;
- CreateInputItemFromMedia( &p_item, p_media );
- watch_add_Item( p_ml, p_item, p_media );
- ml_gc_decref( p_media );
- }
-
- return p_item;
-}
-
-/**
- * @brief Copy an input_item_t to a ml_media_t
- * @param p_media Destination
- * @param p_item Source
- * @note Media ID will not be set! This function is threadsafe. Leaves
- * unsyncable items alone
- */
-void CopyInputItemToMedia( ml_media_t *p_media, input_item_t *p_item )
-{
- ml_LockMedia( p_media );
-#if 0
- // unused meta :
- input_item_GetCopyright( item )
- input_item_GetRating( item ) /* TODO */
- input_item_GetGetting( item )
- input_item_GetNowPlaying( item )
- input_item_GetTrackID( item )
- input_item_GetSetting( item )
-#endif
- p_media->psz_title = input_item_GetTitle ( p_item );
- p_media->psz_uri = input_item_GetURL ( p_item );
- if( !p_media->psz_uri )
- p_media->psz_uri = input_item_GetURI( p_item );
- p_media->psz_album = input_item_GetAlbum ( p_item );
- p_media->psz_cover = input_item_GetArtURL ( p_item );
- p_media->psz_genre = input_item_GetGenre ( p_item );
- p_media->psz_language = input_item_GetLanguage ( p_item );
- p_media->psz_comment = input_item_GetDescription ( p_item );
- char *psz_track = input_item_GetTrackNum ( p_item );
- p_media->i_track_number = psz_track ? atoi( psz_track ) : 0;
- free( psz_track );
- char *psz_date = input_item_GetDate( p_item );
- p_media->i_year = psz_date ? atoi( psz_date ) : 0;
- free( psz_date );
- p_media->i_duration = p_item->i_duration;
-
- /* People */
- char *psz_tmp = input_item_GetArtist( p_item );
- if( psz_tmp )
- ml_CreateAppendPersonAdv( &p_media->p_people, ML_PERSON_ARTIST,
- psz_tmp, 0 );
- free( psz_tmp );
- psz_tmp = input_item_GetPublisher( p_item );
- if( psz_tmp )
- ml_CreateAppendPersonAdv( &p_media->p_people, ML_PERSON_PUBLISHER,
- psz_tmp, 0 );
- free( psz_tmp );
- psz_tmp = input_item_GetEncodedBy( p_item );
- if( psz_tmp )
- ml_CreateAppendPersonAdv( &p_media->p_people, ML_PERSON_ENCODER,
- psz_tmp, 0 );
- free( psz_tmp );
-
- /* Determine input type: audio, video, stream */
- /* First read input type */
- switch( p_item->i_type )
- {
- case ITEM_TYPE_FILE:
- p_media->i_type |= 0;
- break;
- case ITEM_TYPE_DISC:
- case ITEM_TYPE_CARD:
- p_media->i_type |= ML_REMOVABLE;
- break;
- case ITEM_TYPE_CDDA:
- case ITEM_TYPE_NET:
- p_media->i_type |= ML_STREAM;
- break;
- case ITEM_TYPE_PLAYLIST:
- case ITEM_TYPE_NODE:
- case ITEM_TYPE_DIRECTORY:
- p_media->i_type |= ML_NODE;
- break;
- case ITEM_TYPE_NUMBER:
- case ITEM_TYPE_UNKNOWN:
- default:
- p_media->i_type |= ML_UNKNOWN;
- break;
- }
-
- /* Then try to guess if this is a video or not */
- /* Check file extension, and guess if this is a video or an audio media
- Note: this test is not very good, but it's OK for normal files */
- char *psz_ext = strrchr( p_item->psz_uri, '.' );
- if( psz_ext && strlen( psz_ext ) < 5 )
- {
- bool b_ok = false;
- psz_ext++;
- for( unsigned i = 0; ppsz_AudioExtensions[i]; i++ )
- {
- if( strcasecmp( psz_ext, ppsz_AudioExtensions[i] ) == 0 )
- {
- p_media->i_type |= ML_AUDIO;
- b_ok = true;
- break;
- }
- }
- if( !b_ok )
- {
- for( unsigned i = 0; ppsz_VideoExtensions[i]; i++ )
- {
- if( strcasecmp( psz_ext, ppsz_VideoExtensions[i] ) == 0 )
- {
- p_media->i_type |= ML_VIDEO;
- break;
- }
- }
- }
- }
- ml_UnlockMedia( p_media );
-}
-
-/**
- * @brief Copy a ml_media_t to an input_item_t
- * @param p_item Destination
- * @param p_media Source
- */
-void CopyMediaToInputItem( input_item_t *p_item, ml_media_t *p_media )
-{
- ml_LockMedia( p_media );
- if( p_media->psz_title && *p_media->psz_title )
- input_item_SetTitle( p_item, p_media->psz_title );
- if( p_media->psz_uri && *p_media->psz_uri && !strncmp( p_media->psz_uri, "http", 4 ) )
- input_item_SetURL( p_item, p_media->psz_uri );
- if( p_media->psz_album && *p_media->psz_album )
- input_item_SetAlbum( p_item, p_media->psz_album );
- if( p_media->psz_cover && *p_media->psz_cover )
- input_item_SetArtURL( p_item, p_media->psz_cover );
- if( p_media->psz_genre && *p_media->psz_genre )
- input_item_SetGenre( p_item, p_media->psz_genre );
- if( p_media->psz_language && *p_media->psz_language )
- input_item_SetLanguage( p_item, p_media->psz_language );
- if( p_media->psz_comment && *p_media->psz_comment )
- input_item_SetDescription( p_item, p_media->psz_comment );
- if( p_media->i_track_number )
- {
- char *psz_track;
- if( asprintf( &psz_track, "%d", p_media->i_track_number ) != -1 )
- input_item_SetTrackNum( p_item, psz_track );
- free( psz_track );
- }
- if( p_media->i_year )
- {
- char *psz_date;
- if( asprintf( &psz_date, "%d", p_media->i_year ) != -1 )
- input_item_SetDate( p_item, psz_date );
- free( psz_date );
- }
- p_item->i_duration = p_media->i_duration;
- ml_person_t *person = p_media->p_people;
- while( person )
- {
- if( !strcmp( person->psz_role, ML_PERSON_ARTIST ) )
- input_item_SetArtist( p_item, person->psz_name );
- else if( !strcmp( person->psz_role, ML_PERSON_PUBLISHER ) )
- input_item_SetPublisher( p_item, person->psz_name );
- else if( !strcmp( person->psz_role, ML_PERSON_ENCODER ) )
- input_item_SetEncodedBy( p_item, person->psz_name );
- person = person->p_next;
- }
- ml_UnlockMedia( p_media );
-}
-
-/**
- * @brief Copy a ml_media_t to an input_item_t
- * @param pp_item A pointer to a new input_item (return value)
- * @param p_media The media to copy as an input item
- * @note This function is threadsafe
- */
-static int CreateInputItemFromMedia( input_item_t **pp_item,
- ml_media_t *p_media )
-{
- *pp_item = input_item_New( p_media->psz_uri, p_media->psz_title );
- /* ITEM_TYPE_FILE ); */
- if( !*pp_item )
- return VLC_EGENERIC;
- CopyMediaToInputItem( *pp_item, p_media );
- return VLC_SUCCESS;
-}
-
-/**
- * @brief Find the media_id associated to an input item
- * @param p_ml This
- * @param p_item Input item to look for
- * @return Media ID or <= 0 if not found
- */
-int GetMediaIdOfInputItem( media_library_t *p_ml, input_item_t *p_item )
-{
- int i_media_id = watch_get_mediaIdOfItem( p_ml, p_item );
- if( i_media_id <= 0 )
- {
- i_media_id = GetMediaIdOfURI( p_ml, p_item->psz_uri );
- }
- return i_media_id;
-}
-
-
+++ /dev/null
-/*****************************************************************************
- * sql_media_library.h : Media Library Interface
- *****************************************************************************
- * Copyright (C) 2008-2010 the VideoLAN team and AUTHORS
- * $Id$
- *
- * Authors: Antoine Lejeune <phytos@videolan.org>
- * Jean-Philippe André <jpeg@videolan.org>
- * Rémi Duraffort <ivoire@videolan.org>
- * Adrien Maglo <magsoft@videolan.org>
- * Srikanth Raju <srikiraju at gmail dot com>
- *
- * 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.
- *****************************************************************************/
-
-#ifndef SQL_MEDIA_LIBRARY_H
-#define SQL_MEDIA_LIBRARY_H
-
-#include <stdarg.h>
-#include <assert.h>
-#include <errno.h>
-#include <sys/stat.h>
-
-#include <vlc_common.h>
-#include <vlc_sql.h>
-#include <vlc_media_library.h>
-#include <vlc_playlist.h>
-#include <vlc_input.h>
-#include <vlc_arrays.h>
-#include <vlc_charset.h>
-#include <vlc_plugin.h>
-#include <vlc_interface.h>
-#include <vlc_modules.h>
-
-#include "item_list.h"
-
-/*****************************************************************************
- * Static parameters
- *****************************************************************************/
-#define THREAD_SLEEP_DELAY 2 /* Time between two calls to item_list_loop */
-#define MONITORING_DELAY 30 /* Media library updates interval */
-#define ITEM_LOOP_UPDATE 1 /* An item is updated after 1 loop */
-#define ITEM_LOOP_MAX_AGE 10 /* An item is deleted after 10 loops */
-#define ML_DBVERSION 1 /* The current version of the database */
-#define ML_MEDIAPOOL_HASH_LENGTH 100 /* The length of the media pool hash */
-
-/*****************************************************************************
- * Structures and types definitions
- *****************************************************************************/
-typedef struct monitoring_thread_t monitoring_thread_t;
-typedef struct ml_poolobject_t ml_poolobject_t;
-
-struct ml_poolobject_t
-{
- ml_media_t* p_media;
- ml_poolobject_t* p_next;
-};
-
-struct media_library_sys_t
-{
- /* Lock on the ML object */
- vlc_mutex_t lock;
-
- /* SQL object */
- sql_t *p_sql;
-
- /* Monitoring thread */
- monitoring_thread_t *p_mon;
-
- /* Watch thread */
- watch_thread_t *p_watch;
-
- /* Holds all medias */
- DECL_ARRAY( ml_media_t* ) mediapool;
- ml_poolobject_t* p_mediapool[ ML_MEDIAPOOL_HASH_LENGTH ];
- vlc_mutex_t pool_mutex;
-
- /* Info on update/collection rebuilding */
- bool b_updating;
- bool b_rebuilding;
-};
-
-/* Directory Monitoring thread */
-struct monitoring_thread_t
-{
- VLC_COMMON_MEMBERS;
-
- vlc_cond_t wait;
- vlc_mutex_t lock;
- vlc_thread_t thread;
- media_library_t *p_ml;
-};
-
-/* Media status Watching thread */
-struct watch_thread_t
-{
- media_library_t *p_ml;
- vlc_thread_t thread;
- vlc_cond_t cond;
- vlc_mutex_t lock;
-
- /* Input items watched */
- struct item_list_t* p_hlist[ ML_ITEMLIST_HASH_LENGTH ];
- vlc_mutex_t list_mutex;
-
- /* List of items to check */
- input_item_t** item_append_queue;
- vlc_mutex_t item_append_queue_lock;
- int item_append_queue_count;
-};
-
-
-
-/*****************************************************************************
- * Function headers
- *****************************************************************************/
-/* General functions */
-int CreateEmptyDatabase( media_library_t *p_ml );
-int InitDatabase( media_library_t *p_ml );
-
-/* Module Control */
-int Control( media_library_t *p_ml,
- int i_query,
- va_list args );
-
-/* Add functions */
-int AddMedia( media_library_t *p_ml,
- ml_media_t *p_media );
-int AddAlbum( media_library_t *p_ml, const char *psz_title,
- const char *psz_cover, const int i_album_artist );
-int AddPeople( media_library_t *p_ml,
- const char *psz_name,
- const char *psz_role );
-int AddPlaylistItem( media_library_t *p_ml,
- playlist_item_t *p_playlist_item );
-int AddInputItem( media_library_t *p_ml,
- input_item_t *p_input );
-
-/* Create and Copy functions */
-ml_media_t* GetMedia( media_library_t* p_ml, int id,
- ml_select_e select, bool reload );
-input_item_t* GetInputItemFromMedia( media_library_t *p_ml,
- int i_media );
-void CopyInputItemToMedia( ml_media_t *p_media,
- input_item_t *p_item );
-void CopyMediaToInputItem( input_item_t *p_item,
- ml_media_t *p_media );
-
-/* Get functions */
-int GetDatabaseVersion( media_library_t *p_ml );
-int GetMediaIdOfInputItem( media_library_t *p_ml,
- input_item_t *p_item );
-int GetMediaIdOfURI( media_library_t *p_ml,
- const char *psz_uri );
-
-/* Search in the database */
-int BuildSelectVa( media_library_t *p_ml,
- char **ppsz_query,
- ml_result_type_e *p_result_type,
- va_list criterias );
-int BuildSelect( media_library_t *p_ml,
- char **ppsz_query,
- ml_result_type_e *p_result_type,
- const char *psz_selected_type_lvalue,
- ml_select_e selected_type,
- ml_ftree_t *tree );
-int Find( media_library_t *p_ml,
- vlc_array_t *results,
- ... );
-int FindVa( media_library_t *p_ml,
- vlc_array_t *results,
- va_list criterias );
-int FindAdv( media_library_t *p_ml,
- vlc_array_t *results,
- ml_select_e selected_type,
- const char* psz_lvalue,
- ml_ftree_t *tree );
-
-/* Update the database */
-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 BuildUpdate( media_library_t *p_ml,
- char **ppsz_query,
- char **ppsz_id_query,
- const char *psz_lvalue,
- ml_select_e selected_type,
- ml_ftree_t* where,
- vlc_array_t *changes );
-int UpdateMedia( media_library_t *p_ml,
- ml_media_t *p_media );
-int SetArtCover( media_library_t *p_ml,
- int i_album_id,
- const char *psz_cover );
-
-/* Delete medias in the database */
-int Delete( media_library_t *p_ml, vlc_array_t *p_array );
-
-/* Do some query on the database */
-int QuerySimple( media_library_t *p_ml,
- const char *psz_fmt, ... );
-int Query( media_library_t *p_ml,
- char ***ppp_res,
- int *pi_rows,
- int *pi_cols,
- const char *psz_fmt,
- ... );
-int QueryVa( media_library_t *p_ml,
- char ***ppp_res,
- int *pi_rows,
- int *pi_cols,
- const char *psz_fmt,
- va_list args );
-int QuerySimpleVa( media_library_t *p_ml,
- const char *psz_fmt,
- va_list argp );
-
-/* Convert SQL results to ML results */
-int StringToResult( ml_result_t *res,
- const char *psz,
- const char *psz_id,
- ml_result_type_e result_type );
-int SQLToMediaArray( media_library_t *p_ml,
- vlc_array_t *p_result_array,
- char **pp_results,
- int i_rows,
- int i_cols );
-int SQLToResultArray( media_library_t *p_ml,
- vlc_array_t *p_result_array,
- char **pp_results,
- int i_rows,
- int i_cols,
- ml_result_type_e result_type );
-
-/* Database locking functions */
-
-/**
- * @brief Begin a transaction
- * @param p_ml The Media Library object
- * @return VLC_SUCCESS and VLC_EGENERIC
- * @note This creates a SHARED lock in SQLITE. All queries made between
- * a Begin and Commit/Rollback will be transactional.
- */
-static inline int Begin( media_library_t* p_ml )
-{
- return sql_BeginTransaction( p_ml->p_sys->p_sql );
-}
-
-/**
- * @brief Commits the transaction
- * @param p_ml The Media Library object
- */
-static inline void Commit( media_library_t* p_ml )
-{
- sql_CommitTransaction( p_ml->p_sys->p_sql );
-}
-
-/**
- * @brief Rollback the transaction
- * @param p_ml The Media Library Object
- */
-static inline void Rollback( media_library_t* p_ml )
-{
- sql_RollbackTransaction( p_ml->p_sys->p_sql );
-}
-
-/****************************************************************************
- * Scanning/monitoring functions
- *****************************************************************************/
-void *RunMonitoringThread( void *p_mon );
-int AddDirToMonitor( media_library_t *p_ml,
- const char *psz_dir );
-int ListMonitoredDirs( media_library_t *p_ml,
- vlc_array_t *p_array );
-int RemoveDirToMonitor( media_library_t *p_ml,
- const char *psz_dir );
-
-
-/*****************************************************************************
- * Media pool functions
- *****************************************************************************/
-ml_media_t* pool_GetMedia( media_library_t* p_ml, int media_id );
-int pool_InsertMedia( media_library_t* p_ml, ml_media_t* media, bool locked );
-void pool_GC( media_library_t* p_ml );
-
-/*****************************************************************************
- * Items watching system
- *****************************************************************************/
-/* Watching thread */
-#define watch_add_Item( a, b, c ) __watch_add_Item( a, b, c, false )
-
-int watch_Init( media_library_t *p_ml );
-void watch_Close( media_library_t *p_ml );
-int __watch_add_Item( media_library_t *p_ml, input_item_t *p_item,
- ml_media_t* p_media, bool locked );
-
-#define watch_del_Item( a, b ) __watch_del_Item( a, b, false )
-int __watch_del_Item( media_library_t *p_ml, input_item_t *p_item, bool locked );
-int watch_del_MediaById( media_library_t* p_ml, int i_media_id );
-input_item_t* watch_get_itemOfMediaId( media_library_t *p_ml, int i_media_id );
-ml_media_t* watch_get_mediaOfMediaId( media_library_t* p_ml, int i_media_id );
-int watch_get_mediaIdOfItem( media_library_t *p_ml, input_item_t *p_item );
-void watch_Force_Update( media_library_t* p_ml );
-
-/*****************************************************************************
- * Free result of ml_Query
- *****************************************************************************/
-static inline void FreeSQLResult( media_library_t *p_ml, char **ppsz_result )
-{
- if( ppsz_result )
- {
- sql_Free( p_ml->p_sys->p_sql, ppsz_result );
- }
-}
-
-#endif /* SQL_MEDIA_LIBRARY_H */
+++ /dev/null
-/*****************************************************************************
- * sql_monitor.c: SQL-based media library: directory scanning and monitoring
- *****************************************************************************
- * Copyright (C) 2008-2010 the VideoLAN team and AUTHORS
- * $Id$
- *
- * Authors: Antoine Lejeune <phytos@videolan.org>
- * Jean-Philippe André <jpeg@videolan.org>
- * Rémi Duraffort <ivoire@videolan.org>
- * Adrien Maglo <magsoft@videolan.org>
- * Srikanth Raju <srikiraju at gmail dot com>
- *
- * 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.
- *****************************************************************************/
-
-/** **************************************************************************
- * MONITORING AND DIRECTORY SCANNING FUNCTIONS
- *****************************************************************************/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "sql_media_library.h"
-#include "vlc_playlist.h"
-#include "vlc_url.h"
-#include "vlc_fs.h"
-
-static const char* ppsz_MediaExtensions[] =
- { EXTENSIONS_AUDIO_CSV, EXTENSIONS_VIDEO_CSV, NULL };
-
-
-/* Monitoring and directory scanning private functions */
-typedef struct stat_list_t stat_list_t;
-typedef struct preparsed_item_t preparsed_item_t;
-static void UpdateLibrary( monitoring_thread_t *p_mon );
-static void ScanFiles( monitoring_thread_t *, int, bool, stat_list_t *stparent );
-static int Sort( const char **, const char ** );
-
-/* Struct used to verify there are no recursive directory */
-struct stat_list_t
-{
- stat_list_t *parent;
- struct stat st;
-};
-
-struct preparsed_item_t
-{
- monitoring_thread_t *p_mon;
- char* psz_uri;
- int i_dir_id;
- int i_mtime;
- int i_update_id;
- bool b_update;
-};
-
-/**
- * @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 occurred 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 occurred 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;
-}
-
-/**
- * @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;
-}
-
-/**
- * @brief Add a directory to monitor
- * @param p_ml This media_library_t object
- * @param psz_dir the directory to add
- * @return VLC_SUCCESS or VLC_EGENERIC
- */
-int AddDirToMonitor( media_library_t *p_ml, const char *psz_dir )
-{
- assert( p_ml );
-
- /* Verify if we can open the directory */
- DIR *dir = vlc_opendir( psz_dir );
- if( !dir )
- {
- int err = errno;
- if( err != ENOTDIR )
- msg_Err( p_ml, "%s: %m", psz_dir );
- else
- msg_Dbg( p_ml, "`%s' is not a directory", psz_dir );
- errno = err;
- return VLC_EGENERIC;
- }
-
- closedir( dir );
-
- msg_Dbg( p_ml, "Adding directory `%s' to be monitored", psz_dir );
- QuerySimple( p_ml, "INSERT INTO directories ( uri, timestamp, "
- "recursive ) VALUES( %Q, 0, 0 )", psz_dir );
- vlc_cond_signal( &p_ml->p_sys->p_mon->wait );
- return VLC_SUCCESS;
-}
-
-
-static int Sort( const char **a, const char **b )
-{
-#ifdef HAVE_STRCOLL
- return strcoll( *a, *b );
-#else
- return strcmp( *a, *b );
-#endif
-}
-
-/**
- * @brief Directory Monitoring thread loop
- */
-void *RunMonitoringThread( void *p_this )
-{
- monitoring_thread_t *p_mon = (monitoring_thread_t*) p_this;
- vlc_cond_init( &p_mon->wait );
- vlc_mutex_init( &p_mon->lock );
-
- var_Create( p_mon, "ml-recursive-scan", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-
- while( vlc_object_alive( p_mon ) )
- {
- vlc_mutex_lock( &p_mon->lock );
-
- /* Update */
- UpdateLibrary( p_mon );
-
- /* We wait MONITORING_DELAY seconds or wait that the media library
- signals us to do something */
- vlc_cond_timedwait( &p_mon->wait, &p_mon->lock,
- mdate() + 1000000*MONITORING_DELAY );
-
- vlc_mutex_unlock( &p_mon->lock );
- }
- vlc_cond_destroy( &p_mon->wait );
- vlc_mutex_destroy( &p_mon->lock );
- return NULL;
-}
-
-/**
- * @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 );
-}
-
-/**
- * @brief Callback for input item preparser to directory monitor
- */
-static void PreparseComplete( const vlc_event_t * p_event, void *p_data )
-{
- int i_ret = VLC_SUCCESS;
- preparsed_item_t* p_itemobject = (preparsed_item_t*) p_data;
- monitoring_thread_t *p_mon = p_itemobject->p_mon;
- media_library_t *p_ml = (media_library_t *)p_mon->p_ml;
- input_item_t *p_input = (input_item_t*) p_event->p_obj;
-
- if( input_item_IsPreparsed( p_input ) )
- {
- if( p_itemobject->b_update )
- {
- //TODO: Perhaps we don't have to load everything?
- ml_media_t* p_media = GetMedia( p_ml, p_itemobject->i_update_id,
- ML_MEDIA_SPARSE, true );
- CopyInputItemToMedia( p_media, p_input );
- i_ret = UpdateMedia( p_ml, p_media );
- ml_gc_decref( p_media );
- }
- else
- i_ret = AddInputItem( p_ml, p_input );
- }
-
- if( i_ret != VLC_SUCCESS )
- msg_Dbg( p_mon, "Item could not be correctly added"
- " or updated during scan: %s", p_input->psz_uri );
- QuerySimple( p_ml, "UPDATE media SET directory_id=%d, timestamp=%d "
- "WHERE id=%d",
- p_itemobject->i_dir_id, p_itemobject->i_mtime,
- GetMediaIdOfURI( p_ml, p_input->psz_uri ) );
- vlc_event_detach( &p_input->event_manager, vlc_InputItemPreparsedChanged,
- PreparseComplete, p_itemobject );
- vlc_gc_decref( p_input );
- free( p_itemobject->psz_uri );
-}
-
-/**
- * @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 );
-}
+++ /dev/null
-/*****************************************************************************
- * sql_search.c: SQL-based media library: all find/get functions
- *****************************************************************************
- * Copyright (C) 2008-2010 the VideoLAN team and AUTHORS
- * $Id$
- *
- * Authors: Antoine Lejeune <phytos@videolan.org>
- * Jean-Philippe André <jpeg@videolan.org>
- * Rémi Duraffort <ivoire@videolan.org>
- * Adrien Maglo <magsoft@videolan.org>
- * Srikanth Raju <srikiraju at gmail dot com>
- *
- * 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.
- *****************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "sql_media_library.h"
-
-int Find( media_library_t *p_ml, vlc_array_t *p_result_array, ... )
-{
- va_list args;
- int returned;
-
- va_start( args, p_result_array );
- returned = FindVa( p_ml, p_result_array, args );
- va_end( args );
-
- return returned;
-}
-
-/**
- * @brief Generic find in Media Library, returns arrays of psz or int
- *
- * @param p_ml the media library object
- * @param result A pointer to a result array
- * @param criterias list of criterias used in SELECT
- * @return VLC_SUCCESS or VLC_EGENERIC
- */
-int FindVa( media_library_t *p_ml,
- vlc_array_t *p_result_array, va_list criterias )
-{
- 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 = BuildSelectVa( p_ml, &psz_query, &result_type, criterias );
- 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;
-}
-
-/**
- * @brief Generic find in Media Library, returns arrays of psz or int
- *
- * @param p_ml the media library object
- * @param result a pointer to a result array
- * @param selected_type the type of the element we're selecting
- * @param criterias list of criterias used in SELECT
- * @return VLC_SUCCESS or VLC_EGENERIC
- */
-
-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;
-}
-
-/**
- * @brief Generic SELECT query builder with va_list parameter
- *
- * @param p_ml This media_library_t object
- * @param ppsz_query *ppsz_query will contain query
- * @param p_result_type see enum ml_result_type_e
- * @param criterias list of criterias used in SELECT
- * @return VLC_SUCCESS or a VLC error code
- * NOTE va_list criterias must end with ML_END or this will fail (segfault)
- *
- * This function handles results of only one column (or two if ID is included),
- * of 'normal' types: int and strings
- */
-int BuildSelectVa( media_library_t *p_ml, char **ppsz_query,
- ml_result_type_e *p_result_type, va_list criterias )
-{
- int i_continue = 1;
- ml_ftree_t* p_ftree = NULL;
- char* psz_lvalue = NULL;
-
- /* Get the name of the data we want */
- ml_select_e selected_type = va_arg( criterias, int );
- if( selected_type == ML_PEOPLE || selected_type == ML_PEOPLE_ID ||
- selected_type == ML_PEOPLE_ROLE )
- psz_lvalue = va_arg( criterias, char * );
-
- /* Loop on every arguments */
- while( i_continue )
- {
- ml_ftree_t *p_find = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
- if( !p_find )
- return VLC_ENOMEM;
- p_find->criteria = va_arg( criterias, int );
- p_find->comp = ML_COMP_EQUAL;
- switch( p_find->criteria )
- {
- case ML_SORT_ASC:
- p_ftree = ml_FtreeSpecAsc( p_ftree, va_arg( criterias, char* ) ); break;
- case ML_SORT_DESC:
- p_ftree = ml_FtreeSpecDesc( p_ftree, va_arg( criterias, char* ) ); break;
- case ML_DISTINCT:
- p_ftree = ml_FtreeSpecDistinct( p_ftree ); break;
- case ML_LIMIT:
- p_ftree = ml_FtreeSpecLimit( p_ftree, va_arg( criterias, int ) );
- break;
- case ML_ARTIST:
- /* This is OK because of a shallow free find */
- p_find->lvalue.str = (char *)ML_PERSON_ARTIST;
- p_find->value.str = va_arg( criterias, char* );
- p_ftree = ml_FtreeFastAnd( p_ftree, p_find );
- break;
- case ML_PEOPLE:
- p_find->lvalue.str = va_arg( criterias, char* );
- p_find->value.str = va_arg( criterias, char* );
- p_ftree = ml_FtreeFastAnd( p_ftree, p_find );
- break;
- case ML_PEOPLE_ID:
- p_find->lvalue.str = va_arg( criterias, char* );
- p_find->value.i = va_arg( criterias, int );
- p_ftree = ml_FtreeFastAnd( p_ftree, p_find );
- break;
- case ML_END:
- i_continue = 0;
- break;
- default:
- switch( ml_AttributeIsString( p_find->criteria ) )
- {
- case 0:
- p_find->value.i = va_arg( criterias, int );
- break;
- case 1:
- p_find->value.str = va_arg( criterias, char* );
- break;
- }
- p_ftree = ml_FtreeFastAnd( p_ftree, p_find );
- break;
- }
- }
-
- int i_ret = BuildSelect( p_ml, ppsz_query, p_result_type, psz_lvalue,
- selected_type, p_ftree );
-
- ml_ShallowFreeFindTree( p_ftree );
- return i_ret;
-}
-
-/**
- * @brief Append a string and format it using SQL vmprintf
- **/
-static int AppendStringFmtVa( media_library_t *p_ml,
- char **ppsz_dst, const char *psz_fmt,
- va_list args )
-{
- char *psz_tmp = NULL, *psz_fullexp = NULL;
-
- assert( ppsz_dst != NULL );
-
- if( !( *ppsz_dst ) )
- {
- /* New expression */
- *ppsz_dst = sql_VPrintf( p_ml->p_sys->p_sql, psz_fmt, args );
- if( !( *ppsz_dst ) )
- return VLC_ENOMEM;
- }
- else
- {
- /* Create new expression B */
- psz_tmp = sql_VPrintf( p_ml->p_sys->p_sql, psz_fmt, args );
- if( !psz_tmp )
- return VLC_ENOMEM;
-
- if( asprintf( &psz_fullexp, "%s%s", *ppsz_dst, psz_tmp ) == -1 )
- {
- free( psz_tmp );
- return VLC_ENOMEM;
- }
-
- free( *ppsz_dst );
- *ppsz_dst = psz_fullexp;
- }
-
- return VLC_SUCCESS;
-}
-
-static int AppendStringFmt( media_library_t *p_ml,
- char **ppsz_dst, const char *psz_fmt, ... )
-{
- va_list args;
- va_start( args, psz_fmt );
- int i_ret = AppendStringFmtVa( p_ml, ppsz_dst, psz_fmt, args );
- va_end( args );
- return i_ret;
-}
-
-/* Early Declaration of Where String Generator */
-static int BuildWhere( media_library_t* p_ml, char **ppsz_where, ml_ftree_t* tree,
- char** sort, int* limit, const char** distinct, char*** pppsz_frompersons,
- int* i_frompersons, int* join );
-
-# define table_media (1 << 0)
-# define table_album (1 << 1)
-# define table_people (1 << 2)
-# define table_extra (1 << 3)
-
-static void PackFromPersons( char*** pppsz_frompersons, int i_num_frompersons )
-{
- for( int i = 0; i < i_num_frompersons; i++ )
- {
- if( *pppsz_frompersons[i] == NULL )
- continue;
- for( int j = i+1; j < i_num_frompersons; j++ )
- {
- if( strcmp( *pppsz_frompersons[i], *pppsz_frompersons[j] ) == 0 )
- {
- *pppsz_frompersons[j] = NULL;
- }
- }
- }
-}
-/**
- * @brief Generic SELECT query builder
- *
- * @param p_ml This media_library_t object
- * @param ppsz_query *ppsz_query will contain query
- * @param p_result_type see enum ml_result_type_e
- * @param selected_type the type of the element we're selecting
- * @param tree the find tree
- * @return VLC_SUCCESS or VLC_EGENERIC
- */
-int BuildSelect( media_library_t *p_ml,
- char **ppsz_query, ml_result_type_e *p_result_type,
- const char *psz_selected_type_lvalue, ml_select_e selected_type,
- ml_ftree_t *tree )
-{
- /* Basic verification */
- if( !ppsz_query )
- return VLC_EGENERIC;
-
- int i_ret = VLC_SUCCESS;
- char *psz_query = NULL;
-
- /* Building psz_query :
- psz_query = "SELECT psz_distinct psz_select
- FROM psz_from [JOIN psz_join ON psz_on]
- [JOIN psz_join2 ON psz_on2]
- [WHERE psz_where[i] [AND psz_where[j] ...]]
- [LIMIT psz_limit] [ORDER BY psz_select psz_sort] ;"
- */
- char *psz_select = NULL;
- const char *psz_distinct = ""; /* "DISTINCT" or "" */
-
- /* FROM */
- char *psz_from = NULL;
- int i_from = 0; /* Main select table */
-
- char **ppsz_frompersons = NULL;
- int i_num_frompersons = 0;
- char *psz_peoplerole = NULL; /* Person to get selected */
-
- /* JOIN ... ON ... */
- char *psz_join = NULL;
- char *psz_join2 = NULL;
- char *psz_on = NULL;
- char *psz_on2 = NULL;
- int i_join = 0; /* Tables that need to be joined */
-
- /* String buffers */
- char *psz_where = NULL;
- char *psz_sort = NULL; /* ASC or DESC or NULL */
- char *psz_tmp = NULL;
-
- int i_limit = 0;
-
- /* Build the WHERE condition */
- BuildWhere( p_ml, &psz_where, tree, &psz_sort, &i_limit,
- &psz_distinct, &ppsz_frompersons, &i_num_frompersons, &i_join );
-
- PackFromPersons( &ppsz_frompersons, i_num_frompersons );
-
- /* What is the result type? */
- ml_result_type_e res_type = ML_TYPE_PSZ;
-
- /* SELECT, FROM */
- /* Note that a DISTINCT select makes id of result non sense */
- switch( selected_type )
- {
- case ML_ALBUM:
- psz_select = ( !*psz_distinct ) ?
- strdup( "album.id, album.title AS album_title" )
- : strdup( "album.title AS album_title" );
- i_from = table_album;
- break;
- case ML_ALBUM_COVER:
- psz_select = ( !*psz_distinct ) ?
- strdup( "album.id, album.cover" ) : strdup( "album.cover" );
- i_from = table_album;
- break;
- case ML_ALBUM_ID:
- psz_select = strdup( "album.id" );
- psz_distinct = "DISTINCT";
- i_from = table_album;
- res_type = ML_TYPE_INT;
- break;
- case ML_ARTIST:
- psz_select = ( !*psz_distinct ) ?
- strdup( "people_Artist.id, people_Artist.name" )
- : strdup( "people_Artist.name" );
- i_from = table_people;
- psz_peoplerole = strdup( ML_PERSON_ARTIST );
- break;
- case ML_ARTIST_ID:
- psz_select = strdup( "people_Artist.id" );
- psz_distinct = "DISTINCT";
- i_from = table_people;
- res_type = ML_TYPE_INT;
- psz_peoplerole = strdup( ML_PERSON_ARTIST );
- break;
- case ML_COVER:
- psz_select = ( !*psz_distinct ) ?
- strdup( "media.id, media.cover" ) : strdup( "media.cover" );
- i_from = table_media;
- break;
- case ML_COMMENT:
- psz_select = ( !*psz_distinct ) ?
- strdup( "media.id, extra.comment" ) : strdup( "extra.comment" );
- i_from = table_extra;
- break;
- case ML_GENRE:
- psz_select = ( !*psz_distinct ) ?
- strdup( "media.id, media.genre" ) : strdup( "media.genre" );
- i_from = table_media;
- break;
- case ML_COUNT_MEDIA:
- psz_select = ( !*psz_distinct ) ?
- strdup( "COUNT()" ) : strdup( "COUNT( DISTINCT media.id )" );
- i_from = table_media;
- res_type = ML_TYPE_INT;
- break;
- case ML_COUNT_ALBUM:
- psz_select = ( !*psz_distinct ) ?
- strdup( "COUNT()" ) : strdup( "COUNT( DISTINCT album.id )" );
- i_from = table_album;
- res_type = ML_TYPE_INT;
- break;
- case ML_COUNT_PEOPLE:
- psz_select = ( !*psz_distinct ) ?
- strdup( "COUNT()" ) : strdup( "COUNT( DISTINCT people.id )" );
- i_from = table_people;
- res_type = ML_TYPE_INT;
- break;
- case ML_FILESIZE:
- psz_select = strdup( "media.filesize" );
- i_from = table_media;
- res_type = ML_TYPE_INT;
- break;
- case ML_ID:
- psz_select = strdup( "media.id" ); /* ID: must be distinct */
- psz_distinct = "DISTINCT";
- i_from = table_media;
- res_type = ML_TYPE_INT;
- break;
- case ML_LANGUAGE:
- psz_select = strdup( "extra.language" );
- psz_distinct = "DISTINCT";
- i_from = table_extra;
- break;
- case ML_MEDIA_SPARSE:
- i_ret = AppendStringFmt( p_ml, &psz_select, "media.id AS id,"
- "media.uri AS uri,"
- "media.type AS type,"
- "media.title AS title,"
- "media.duration AS duration,"
- "media.original_title AS original_title,"
- "media.album_id AS album_id,"
- "media.cover AS cover,"
- "media.preview AS preview,"
- "media.disc AS disc,"
- "media.track AS track,"
- "media.year AS year,"
- "media.genre AS genre,"
- "media.played_count AS played_count,"
- "media.last_played AS last_played,"
- "media.first_played AS first_played,"
- "media.import_time AS import_time,"
- "media.skipped_count AS skipped_count,"
- "media.last_skipped AS last_skipped,"
- "media.vote AS vote,"
- "media.score AS score,"
- "media.comment AS comment,"
- "media.filesize AS filesize,"
- "album.title AS album_title,"
- "album.cover AS album_cover,"
- "(SELECT name FROM media_to_people JOIN people "
- "ON (people_id = id) WHERE media_id = media.id AND role = %Q LIMIT 1) AS people_%s",
- ML_PERSON_ARTIST, ML_PERSON_ARTIST );
- if( i_ret != VLC_SUCCESS )
- goto exit;
- i_from = table_media;
- i_join |= ( table_album | table_people );
- psz_distinct = "DISTINCT";
- res_type = ML_TYPE_MEDIA;
- break;
- case ML_MEDIA:
- /* Who said this was over-complicated ?? */
- /* Yea right. */
- psz_select = strdup( "media.id AS id,"
- "media.uri AS uri,"
- "media.type AS type,"
- "media.title AS title,"
- "media.duration AS duration,"
- "media.original_title AS original_title,"
- "media.album_id AS album_id,"
- "media.cover AS cover,"
- "media.preview AS preview,"
- "media.disc as disc,"
- "media.track AS track,"
- "media.year AS year,"
- "media.genre AS genre,"
- "media.played_count AS played_count,"
- "media.last_played AS last_played,"
- "media.first_played AS first_played,"
- "media.import_time AS import_time,"
- "media.last_skipped AS last_skipped,"
- "media.skipped_count AS skipped_count,"
- "media.vote AS vote,"
- "media.score AS score,"
- "media.comment AS comment,"
- "media.filesize AS filesize,"
- "album.title AS album_title,"
- "album.cover AS album_cover,"
- "people.id AS people_id,"
- "people.name AS people_name,"
- "people.role AS people_role,"
- "extra.language AS language,"
- "extra.extra AS extra" );
- i_from = table_media;
- i_join |= ( table_album | table_people | table_extra );
- psz_distinct = "DISTINCT";
- res_type = ML_TYPE_MEDIA;
- break;
- case ML_MEDIA_EXTRA:
- psz_select = strdup( "media.id AS id,"
- "people.id AS people_id,"
- "people.name AS people_name,"
- "people.role AS people_role,"
- "extra.extra AS extra,"
- "extra.language AS language" );
- i_from = table_media;
- i_join |= ( table_album | table_people | table_extra );
- psz_distinct = "DISTINCT";
- res_type = ML_TYPE_MEDIA;
- break;
- case ML_ORIGINAL_TITLE:
- psz_select = ( !*psz_distinct ) ?
- strdup( "media.id, media.original_title" ) : strdup( "media.original_title" );
- i_from = table_media;
- break;
- /* For people, if lvalue = "", then we want ANY people. */
- case ML_PEOPLE:
- assert( psz_selected_type_lvalue );
- i_ret = AppendStringFmt( p_ml, &psz_select, "people%s%s.name",
- *psz_selected_type_lvalue ? "_" : "",
- *psz_selected_type_lvalue ? psz_selected_type_lvalue : "" );
- if( i_ret != VLC_SUCCESS )
- goto exit;
- if( *psz_distinct )
- {
- i_ret = AppendStringFmt( p_ml, &psz_select, ", people%s%s.name",
- *psz_selected_type_lvalue ? "_" : "",
- *psz_selected_type_lvalue ? psz_selected_type_lvalue : "" );
- if( i_ret != VLC_SUCCESS )
- goto exit;
- }
- i_from = table_people;
- psz_peoplerole = strdup( psz_selected_type_lvalue );
- break;
- case ML_PEOPLE_ID:
- assert( psz_selected_type_lvalue );
- i_ret = AppendStringFmt( p_ml, &psz_select, "people%s%s.id",
- *psz_selected_type_lvalue ? "_" : "",
- *psz_selected_type_lvalue ? psz_selected_type_lvalue : "" );
- if( i_ret != VLC_SUCCESS )
- goto exit;
- if( *psz_distinct )
- {
- i_ret = AppendStringFmt( p_ml, &psz_select, ", people%s%s.id",
- *psz_selected_type_lvalue ? "_" : "",
- *psz_selected_type_lvalue ? psz_selected_type_lvalue : "" );
- if( i_ret != VLC_SUCCESS )
- goto exit;
- }
- psz_distinct = "DISTINCT";
- i_from = table_people;
- psz_peoplerole = strdup( psz_selected_type_lvalue );
- res_type = ML_TYPE_INT;
- break;
- case ML_PEOPLE_ROLE:
- psz_select = strdup( "people.role" );
- psz_distinct = "DISTINCT";
- i_from = table_people;
- break;
- case ML_TITLE:
- psz_select = ( !*psz_distinct ) ?
- strdup( "media.id, media.title" ) : strdup( "media.title" );
- i_from = table_media;
- break;
- case ML_TYPE:
- psz_select = ( !*psz_distinct ) ?
- strdup( "media.id, media.type" ): strdup( "media.type" );
- i_from = table_media;
- res_type = ML_TYPE_INT;
- break;
- case ML_URI:
- psz_select = ( !*psz_distinct ) ?
- strdup( "media.id, media.uri" ) : strdup( "media.uri" );
- i_from = table_media;
- break;
- case ML_VOTE:
- psz_select = ( !*psz_distinct ) ?
- strdup( "media.id, media.vote" ) : strdup( "media.vote" );
- i_from = table_media;
- res_type = ML_TYPE_INT;
- break;
- case ML_YEAR:
- psz_select = ( !*psz_distinct ) ?
- strdup( "media.id, media.year" ) : strdup( "media.year" );
- i_from = table_media;
- res_type = ML_TYPE_INT;
- break;
- case ML_LIMIT:
- case ML_SORT_DESC:
- case ML_SORT_ASC:
- case ML_END:
- default:
- msg_Dbg( p_ml, "unknown select (%d) in BuildSelect", selected_type );
- return VLC_EGENERIC;
- }
-
- /* Let's build full psz_query ! */
- i_ret = VLC_SUCCESS;
-
- /* Figure out select and join tables */
- switch( i_from )
- {
- case table_media:
- break;
- case table_album:
- switch( i_join )
- {
- case 0: break;
- case 2: i_join = 0; break;
- case 1:
- case 3: i_from = table_media; i_join = table_album; break;
- case 4:
- case 5:
- case 6:
- case 7: i_from = table_media; i_join = table_album | table_people; break;
- case 8:
- case 9:
- case 10:
- case 11: i_from = table_media; i_join = table_extra | table_album; break;
- case 12:
- case 13:
- case 14:
- case 15: i_from = table_media; i_join = table_extra | table_album | table_people; break;
- default: break;
- }
- break;
- case table_people:
- switch( i_join )
- {
- case 0: break;
- case 1: i_from = table_media; i_join = table_people; break;
- case 2:
- case 3: i_from = table_media; i_join = table_album | table_people; break;
- case 4:
- /* Determine if a join from media is required */
- if( i_num_frompersons > 1 )
- i_from = table_media;
- else
- i_join = 0;
- break;
- case 5: i_from = table_media; i_join = table_people; break;
- case 6:
- case 7: i_from = table_media; i_join = table_album | table_people; break;
- case 8:
- case 9: i_from = table_media; i_join = table_people | table_extra; break;
- case 10:
- case 11: i_from = table_media; i_join = table_people | table_album | table_extra; break;
- case 12:
- case 13: i_from = table_media; i_join = table_people | table_extra; break;
- case 14:
- case 15: i_from = table_media; i_join = table_people | table_album | table_extra; break;
- default: break;
- }
- break;
- case table_extra:
- switch( i_join )
- {
- case 0: break;
- case 1: i_from = table_media; i_join = table_extra; break;
- case 2:
- case 3: i_from = table_media; i_join = table_extra | table_album; break;
- case 4:
- case 5: i_from = table_media; i_join = table_extra | table_people; break;
- case 6:
- case 7: i_from = table_media; i_join = table_extra | table_people | table_album; break;
- case 8: i_from = table_extra; i_join = 0; break;
- case 9: i_from = table_media; i_join = table_extra; break;
- case 10:
- case 11: i_from = table_media; i_join = table_extra | table_album; break;
- case 12:
- case 13: i_from = table_media; i_join = table_extra | table_people; break;
- case 14:
- case 15: i_from = table_media; i_join = table_extra | table_people | table_album; break;
- default: break;
- }
- break;
- default: msg_Warn( p_ml, "You can't be selecting from this table!!" );
- i_ret = VLC_EGENERIC;
- goto exit;
- }
-
- assert( !( i_from & table_album && i_join & table_album ) );
- assert( !( i_from & table_people && i_join & table_people ) );
- assert( !( i_from & table_extra && i_join & table_extra ) );
-
- /* Generate FROM - psz_from */
- if( i_from == table_media )
- i_ret = AppendStringFmt( p_ml, &psz_from, "media" );
- else if( i_from == table_album )
- i_ret = AppendStringFmt( p_ml, &psz_from, "album" );
- else if( i_from == table_extra )
- i_ret = AppendStringFmt( p_ml, &psz_from, "extra" );
- else if( i_from == table_people )
- {
- i_ret = AppendStringFmt( p_ml, &psz_from, "people AS people%s%s",
- psz_peoplerole ? "_" : "", psz_peoplerole );
- if( i_ret < 0 ) goto exit;
-
- /* The ugly next statement is only required if persons are being
- * selected. Otherwise the joins will handle this */
- if( psz_peoplerole && *psz_peoplerole )
- {
- i_ret = AppendStringFmt( p_ml, &psz_where, "%s people_%s.role = %Q ",
- ( psz_where && *psz_where ) ? " AND" : "",
- psz_peoplerole, psz_peoplerole );
- if( i_ret < 0 ) goto exit;
- }
- }
- if( i_ret < 0 ) goto exit;
-
- i_ret = AppendStringFmt( p_ml, &psz_query,
- "SELECT %s %s ", psz_distinct, psz_select );
- if( i_ret < 0 ) goto exit;
-
- i_ret = AppendStringFmt( p_ml, &psz_query, "FROM %s ", psz_from );
- if( i_ret < 0 ) goto exit;
-
- /* Create join conditions */
- if( i_join & table_people )
- {
- /* we can join psz_peoplerole safely because
- * if i_join = people, then i_from != people */
- bool join = true;
- for( int i = 0; i < i_num_frompersons ; i++ )
- {
- /* We assume ppsz_frompersons has unique entries and
- * if ppsz_frompersons[i] is empty(but not NULL), then it
- * means we accept any role */
- if( ppsz_frompersons[i] && *ppsz_frompersons[i] )
- {
- if( strcmp( psz_peoplerole, ppsz_frompersons[i] ) == 0 )
- join = false;
- AppendStringFmt( p_ml, &psz_join, "%smedia_to_people AS people_%sx ",
- psz_join == NULL ? "" : ",", ppsz_frompersons[i] );
- /* This is possible because from is usually the media table */
- AppendStringFmt( p_ml, &psz_on, "%speople_%sx.media_id = media.id ",
- psz_on == NULL ? "" : " AND ", ppsz_frompersons[i] );
- AppendStringFmt( p_ml, &psz_join2, "%speople AS people_%s ",
- psz_join2 == NULL ? "" : ",", ppsz_frompersons[i] );
- AppendStringFmt( p_ml, &psz_on2, "%s ( people_%sx.people_id = people_%s.id AND "
- "people_%s.role = %Q )", psz_on2 == NULL ? "" : " AND ",
- ppsz_frompersons[i], ppsz_frompersons[i],
- ppsz_frompersons[i], ppsz_frompersons[i] );
- }
- else if( ppsz_frompersons[i] )
- {
- if( strcmp( psz_peoplerole, ppsz_frompersons[i] ) == 0 )
- join = false;
- AppendStringFmt( p_ml, &psz_join, "%smedia_to_people AS peoplex ",
- psz_join == NULL ? "" : "," );
- /* This is possible because from is usually the media table */
- AppendStringFmt( p_ml, &psz_on, "%speoplex.media_id = media.id ",
- psz_on == NULL ? "" : " AND " );
- AppendStringFmt( p_ml, &psz_join2, "%speople AS people ",
- psz_join2 == NULL ? "" : "," );
- AppendStringFmt( p_ml, &psz_on2, "%s peoplex.people_id = people.id",
- psz_on2 == NULL ? "" : " AND " );
- }
- }
- if( join )
- {
- if( psz_peoplerole && *psz_peoplerole )
- {
- AppendStringFmt( p_ml, &psz_join, "%smedia_to_people AS people_%sx ",
- psz_join == NULL ? "" : ",", psz_peoplerole );
- /* This is possible because from is always the media table */
- AppendStringFmt( p_ml, &psz_on, "%speople_%sx.media_id = media.id ",
- psz_on == NULL ? "" : " AND ", psz_peoplerole );
- AppendStringFmt( p_ml, &psz_join2, "%speople AS people_%s ",
- psz_join2 == NULL ? "" : ",", psz_peoplerole );
- AppendStringFmt( p_ml, &psz_on2, "%s ( people_%sx.people_id = people_%s.id AND "
- "people_%s.role = %Q )", psz_on2 == NULL ? "" : " AND ",
- psz_peoplerole, psz_peoplerole,
- psz_peoplerole, psz_peoplerole );
- }
- else
- {
- AppendStringFmt( p_ml, &psz_join, "%smedia_to_people AS peoplex ",
- psz_join == NULL ? "" : "," );
- /* This is possible because from is usually the media table */
- AppendStringFmt( p_ml, &psz_on, "%speoplex.media_id = media.id ",
- psz_on == NULL ? "" : " AND " );
- AppendStringFmt( p_ml, &psz_join2, "%speople ",
- psz_join2 == NULL ? "" : "," );
- AppendStringFmt( p_ml, &psz_on2, "%s peoplex.people_id = people.id",
- psz_on2 == NULL ? "" : " AND " );
-
- }
- }
- }
- if( i_join & table_album )
- {
- AppendStringFmt( p_ml, &psz_join, "%salbum", psz_join == NULL ? "" : "," );
- AppendStringFmt( p_ml, &psz_on, "%s album.id = media.album_id ",
- psz_on == NULL ? "" : " AND " );
- }
- if( i_join & table_extra )
- {
- AppendStringFmt( p_ml, &psz_join, "%sextra", psz_join == NULL ? "" : "," );
- AppendStringFmt( p_ml, &psz_on, "%s extra.id = media.id ",
- psz_on == NULL ? "" : " AND " );
- }
-
- /* Complete the join clauses */
- if( psz_join )
- {
- AppendStringFmt( p_ml, &psz_query,
- "JOIN %s ON %s ", psz_join, psz_on );
- }
- if( psz_join2 )
- {
- AppendStringFmt( p_ml, &psz_query,
- "JOIN %s ON %s ", psz_join2, psz_on2 );
- }
- if( psz_where && *psz_where )
- {
- AppendStringFmt( p_ml, &psz_query,
- "WHERE %s ", psz_where );
- }
- /* TODO: FIXME: Limit on media objects doesn't work! */
- if( i_limit )
- {
- AppendStringFmt( p_ml, &psz_query,
- "LIMIT %d ", i_limit );
- }
-
- if( psz_sort )
- {
- AppendStringFmt( p_ml, &psz_query,
- "ORDER BY %s %s", psz_select, psz_sort );
- }
-
- if( i_ret > 0 ) i_ret = VLC_SUCCESS;
-
- if( p_result_type ) *p_result_type = res_type;
- if( !psz_query ) i_ret = VLC_EGENERIC;
- else *ppsz_query = strdup( psz_query );
-
-exit:
- free( psz_query );
- free( psz_where );
- free( psz_tmp );
- free( psz_from );
- free( psz_join );
- free( psz_select );
- free( psz_join2 );
- free( psz_on );
- free( psz_on2 );
- free( psz_peoplerole );
- free( ppsz_frompersons );
-
- if( i_ret != VLC_SUCCESS )
- msg_Warn( p_ml, "an unknown error occurred (%d)", i_ret );
-
- return i_ret;
-}
-
-#undef CASE_INT
-#define CASE_INT( casestr, fmt, table ) \
-case casestr: \
-assert( tree->comp != ML_COMP_HAS && tree->comp != ML_COMP_STARTS_WITH \
- && tree->comp != ML_COMP_ENDS_WITH ); \
-*ppsz_where = sql_Printf( p_ml->p_sys->p_sql, "%s %s %d", fmt, \
- tree->comp == ML_COMP_LESSER ? "<" : \
- tree->comp == ML_COMP_LESSER_OR_EQUAL ? "<=" : \
- tree->comp == ML_COMP_GREATER ? ">" : \
- tree->comp == ML_COMP_GREATER_OR_EQUAL ? ">=" : "=", tree->value.i ); \
-if( *ppsz_where == NULL ) \
- goto parsefail; \
-*join |= table; \
-break
-
-#undef CASE_PSZ
-#define CASE_PSZ( casestr, fmt, table ) \
-case casestr: \
- assert( tree->comp == ML_COMP_HAS || tree->comp == ML_COMP_EQUAL \
- || tree->comp == ML_COMP_STARTS_WITH \
- || tree->comp == ML_COMP_ENDS_WITH ); \
- *ppsz_where = sql_Printf( p_ml->p_sys->p_sql, "%s %s '%s%q%s'", fmt, \
- (ML_COMP_EQUAL)?"=":"LIKE", \
- tree->comp == ML_COMP_HAS \
- || tree->comp == ML_COMP_STARTS_WITH? "%%" : "", \
- tree->value.str, \
- tree->comp == ML_COMP_HAS \
- || tree->comp == ML_COMP_ENDS_WITH? "%%" : "" ); \
- if( *ppsz_where == NULL ) \
- goto parsefail; \
- *join |= table; \
- break
-
-#define SLDPJ sort, limit, distinct, pppsz_frompersons, i_frompersons, join
-static int BuildWhere( media_library_t* p_ml, char **ppsz_where, ml_ftree_t* tree,
- char** sort, int* limit, const char** distinct,
- char*** pppsz_frompersons, int* i_frompersons, int* join )
-{
- assert( ppsz_where && sort && distinct );
- if( !tree ) /* Base case */
- {
- return VLC_SUCCESS;
- }
-
- int i_ret = VLC_EGENERIC;
- char* psz_left = NULL;
- char* psz_right = NULL;
-
- switch( tree->op )
- {
- case ML_OP_AND:
- case ML_OP_OR:
- i_ret = BuildWhere( p_ml, &psz_left, tree->left, SLDPJ );
- if( i_ret != VLC_SUCCESS )
- goto parsefail;
- i_ret = BuildWhere( p_ml, &psz_right, tree->right, SLDPJ );
- if( i_ret != VLC_SUCCESS )
- goto parsefail;
- if( psz_left == NULL || psz_right == NULL )
- {
- msg_Err( p_ml, "Parsing failed for AND/OR" );
- i_ret = VLC_EGENERIC;
- goto parsefail;
- }
- if( asprintf( ppsz_where, "( %s %s %s )", psz_left,
- ( tree->op == ML_OP_AND ? "AND" : "OR" ), psz_right ) == -1 )
- {
- i_ret = VLC_ENOMEM;
- goto parsefail;
- }
- break;
- case ML_OP_NOT:
- i_ret = BuildWhere( p_ml, &psz_left, tree->left, SLDPJ );
- if( i_ret != VLC_SUCCESS )
- goto parsefail;
- if( psz_left == NULL )
- {
- msg_Err( p_ml, "Parsing failed at NOT" );
- i_ret = VLC_EGENERIC;
- goto parsefail;
- }
- if( asprintf( ppsz_where, "( NOT %s )", psz_left ) == -1 )
- {
- i_ret = VLC_ENOMEM;
- goto parsefail;
- }
- break;
- case ML_OP_SPECIAL:
- i_ret = BuildWhere( p_ml, &psz_right, tree->right, SLDPJ );
- if( i_ret != VLC_SUCCESS )
- goto parsefail;
- i_ret = BuildWhere( p_ml, &psz_left, tree->left, SLDPJ );
- if( i_ret != VLC_SUCCESS )
- goto parsefail;
- /* Ignore right parse tree as this is a special node */
- *ppsz_where = strdup( psz_left ? psz_left : "" );
- if( !*ppsz_where )
- {
- i_ret = VLC_ENOMEM;
- goto parsefail;
- }
- break;
- case ML_OP_NONE:
- switch( tree->criteria )
- {
- case ML_PEOPLE:
- assert( tree->comp == ML_COMP_HAS
- || tree->comp == ML_COMP_EQUAL
- || tree->comp == ML_COMP_STARTS_WITH
- || tree->comp == ML_COMP_ENDS_WITH );
- *ppsz_where = sql_Printf( p_ml->p_sys->p_sql,
- "people%s%s.name LIKE '%s%q%s'",
- tree->lvalue.str ? "_" : "",
- tree->lvalue.str ? tree->lvalue.str : "",
- tree->comp == ML_COMP_HAS
- || tree->comp == ML_COMP_STARTS_WITH ? "%%" : "",
- tree->value.str,
- tree->comp == ML_COMP_HAS
- || tree->comp == ML_COMP_ENDS_WITH ? "%%" : "" );
- if( *ppsz_where == NULL )
- goto parsefail;
- *pppsz_frompersons = realloc( *pppsz_frompersons,
- ++*i_frompersons * sizeof( char* ) );
- *pppsz_frompersons[ *i_frompersons - 1 ] = tree->lvalue.str;
- *join |= table_people;
- break;
- case ML_PEOPLE_ID:
- assert( tree->comp == ML_COMP_EQUAL );
- *ppsz_where = sql_Printf( p_ml->p_sys->p_sql,
- "( people%s%s.id = %d )", tree->lvalue.str ? "_":"",
- tree->lvalue.str ? tree->lvalue.str:"",
- tree->value.i );
- if( *ppsz_where == NULL )
- goto parsefail;
- *pppsz_frompersons = realloc( *pppsz_frompersons,
- ++*i_frompersons * sizeof( char* ) );
- *pppsz_frompersons[ *i_frompersons - 1 ] = tree->lvalue.str;
- *join |= table_people;
- break;
- case ML_PEOPLE_ROLE:
- assert( tree->comp == ML_COMP_HAS
- || tree->comp == ML_COMP_EQUAL
- || tree->comp == ML_COMP_STARTS_WITH
- || tree->comp == ML_COMP_ENDS_WITH );
- *ppsz_where = sql_Printf( p_ml->p_sys->p_sql,
- "people%s%s.role LIKE '%s%q%s'",
- tree->lvalue.str ? "_" : "",
- tree->lvalue.str ? tree->lvalue.str : "",
- tree->comp == ML_COMP_HAS
- || tree->comp == ML_COMP_STARTS_WITH ? "%%" : "",
- tree->value.str,
- tree->comp == ML_COMP_HAS
- || tree->comp == ML_COMP_ENDS_WITH ? "%%" : "" );
- if( *ppsz_where == NULL )
- goto parsefail;
- *pppsz_frompersons = realloc( *pppsz_frompersons,
- ++*i_frompersons * sizeof( char* ) );
- *pppsz_frompersons[ *i_frompersons - 1 ] = tree->lvalue.str;
- *join |= table_people;
- break;
- CASE_PSZ( ML_ALBUM, "album.title", table_album );
- CASE_PSZ( ML_ALBUM_COVER, "album.cover", table_album );
- case ML_ALBUM_ID:
- assert( tree->comp == ML_COMP_EQUAL );
- *ppsz_where = sql_Printf( p_ml->p_sys->p_sql,
- "album.id = %d", tree->value.i );
- if( *ppsz_where == NULL )
- goto parsefail;
- *join |= table_album;
- break;
- CASE_PSZ( ML_COMMENT, "media.comment", table_media );
- CASE_PSZ( ML_COVER, "media.cover", table_media );
- CASE_INT( ML_DURATION, "media.duration", table_media );
- CASE_PSZ( ML_EXTRA, "extra.extra", table_extra );
- CASE_INT( ML_FILESIZE, "media.filesize", table_media );
- CASE_PSZ( ML_GENRE, "media.genre", table_media );
- case ML_ID:
- assert( tree->comp == ML_COMP_EQUAL );
- *ppsz_where = sql_Printf( p_ml->p_sys->p_sql,
- "media.id = %d", tree->value.i );
- if( *ppsz_where == NULL )
- goto parsefail;
- *join |= table_media;
- break;
- CASE_PSZ( ML_LANGUAGE, "extra.language", table_extra );
- CASE_INT( ML_LAST_PLAYED, "media.last_played", table_media );
- CASE_PSZ( ML_ORIGINAL_TITLE, "media.original_title", table_media );
- msg_Warn( p_ml, "Deprecated Played Count tags" );
- CASE_INT( ML_PLAYED_COUNT, "media.played_count", table_media );
- CASE_INT( ML_SCORE, "media.score", table_media );
- CASE_PSZ( ML_TITLE, "media.title", table_media );
- CASE_INT( ML_TRACK_NUMBER, "media.track", table_media);
- CASE_INT( ML_TYPE, "media.type", table_media );
- CASE_PSZ( ML_URI, "media.uri", table_media );
- CASE_INT( ML_VOTE, "media.vote", table_media );
- CASE_INT( ML_YEAR, "media.year", table_media );
- case ML_LIMIT:
- if( !*limit )
- *limit = tree->value.i;
- else
- msg_Warn( p_ml, "Double LIMIT found" );
- break;
- case ML_SORT_DESC:
- *sort = sql_Printf( p_ml->p_sys->p_sql, "%s%s%s DESC ",
- sort ? *sort : "", sort ? ", " : "",
- tree->value.str );
- if( *sort == NULL )
- goto parsefail;
- break;
- case ML_SORT_ASC:
- *sort = sql_Printf( p_ml->p_sys->p_sql, "%s%s%s ASC ",
- sort ? *sort : "", sort ? ", " : "",
- tree->value.str );
- if( *sort == NULL )
- goto parsefail;
- break;
- case ML_DISTINCT:
- if( !**distinct )
- *distinct = "DISTINCT";
- else
- msg_Warn( p_ml, "Double DISTINCT found!" );
- break;
- default:
- msg_Err( p_ml, "Invalid select type or unsupported: %d", tree->criteria );
- }
- break;
- default:
- msg_Err( p_ml, "Broken find tree!" );
- i_ret = VLC_EGENERIC;
- goto parsefail;
- }
-
- i_ret = VLC_SUCCESS;
-parsefail:
- free( psz_left );
- free( psz_right );
- return i_ret;
-}
-
-
-# undef CASE_INT
-# undef CASE_PSZ
-
-# undef table_media
-# undef table_album
-# undef table_people
-# undef table_extra
+++ /dev/null
-/*****************************************************************************
- * sql_update.c: SQL-based media library: all database update functions
- *****************************************************************************
- * Copyright (C) 2008-2010 the VideoLAN team and AUTHORS
- * $Id$
- *
- * Authors: Antoine Lejeune <phytos@videolan.org>
- * Jean-Philippe André <jpeg@videolan.org>
- * Rémi Duraffort <ivoire@videolan.org>
- * Adrien Maglo <magsoft@videolan.org>
- * Srikanth Raju <srikiraju at gmail dot com>
- *
- * 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.
- *****************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "sql_media_library.h"
-
-
-/**
- * @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;
-}
-
-#define SET_STR( a ) \
-if( !psz_set[i_type] ) \
-{ \
- psz_set[i_type] = sql_Printf( p_ml->p_sys->p_sql, a, find->value.str ); \
- if( !psz_set[i_type] ) \
- goto quit_buildupdate; \
-} \
-break;
-
-#define SET_INT( a ) \
-if( !psz_set[i_type] ) \
-{ \
- psz_set[i_type] = sql_Printf( p_ml->p_sys->p_sql, a, find->value.i ); \
- if( !psz_set[i_type] ) \
- goto quit_buildupdate; \
-} \
-break;
-
-/* TODO: Build smarter updates by using IN () */
-static int BuildWhere( media_library_t* p_ml, char **ppsz_where, ml_ftree_t *tree )
-{
- assert( ppsz_where );
- char* psz_left = NULL;
- char* psz_right = NULL;
- int i_ret = VLC_SUCCESS;
- switch( tree->op )
- {
- case ML_OP_AND:
- case ML_OP_OR:
- i_ret = BuildWhere( p_ml, &psz_left, tree->left );
- if( i_ret != VLC_SUCCESS )
- goto quit_buildwhere;
- i_ret = BuildWhere( p_ml, &psz_right, tree->right );
- if( i_ret != VLC_SUCCESS )
- goto quit_buildwhere;
- if( psz_left == NULL || psz_right == NULL )
- {
- msg_Err( p_ml, "Couldn't build AND/OR for Update statement" );
- i_ret = VLC_EGENERIC;
- goto quit_buildwhere;
- }
- if( asprintf( ppsz_where, "( %s %s %s )", psz_left,
- ( tree->op == ML_OP_AND ? "AND" : "OR" ), psz_right ) == -1 )
- {
- i_ret = VLC_ENOMEM;
- goto quit_buildwhere;
- }
- break;
- case ML_OP_NOT:
- i_ret = BuildWhere( p_ml, &psz_left, tree->left );
- if( i_ret != VLC_SUCCESS )
- goto quit_buildwhere;
- if( psz_left == NULL )
- {
- msg_Err( p_ml, "Couldn't build NOT for Update statement" );
- i_ret = VLC_EGENERIC;
- goto quit_buildwhere;
- }
- if( asprintf( ppsz_where, "( NOT %s )", psz_left ) == -1 )
- {
- i_ret = VLC_ENOMEM;
- goto quit_buildwhere;
- }
- break;
- case ML_OP_SPECIAL:
- msg_Err( p_ml, "Couldn't build special for Update statement" );
- break;
- case ML_OP_NONE:
- switch( tree->criteria )
- {
- case ML_ID:
- assert( tree->comp == ML_COMP_EQUAL );
- *ppsz_where = sql_Printf( p_ml->p_sys->p_sql, "media.id = %d",
- tree->value.i );
- if( *ppsz_where == NULL )
- goto quit_buildwhere;
- break;
- case ML_URI:
- assert( tree->comp == ML_COMP_EQUAL );
- *ppsz_where = sql_Printf( p_ml->p_sys->p_sql, "media.uri = %q",
- tree->value.str );
- if( *ppsz_where == NULL )
- goto quit_buildwhere;
- break;
- default:
- msg_Err( p_ml, "Trying to update with unsupported condition" );
- break;
- }
- }
-quit_buildwhere:
- return i_ret;
-}
-
-/**
- * @brief Generic UPDATE query builder
- *
- * @param p_ml This media_library_t object
- * @param ppsz_query *ppsz_query will contain query for update
- * @param ppsz_id_query will contain query to get the ids of updated files
- * @param selected_type the type of the element we're selecting
- * @param where parse tree of where condition
- * @param changes list of changes to make in the entries
- * @return VLC_SUCCESS or VLC_EGENERIC
- */
-int BuildUpdate( media_library_t *p_ml,
- char **ppsz_query, char **ppsz_id_query,
- const char *psz_lvalue,
- ml_select_e selected_type,
- ml_ftree_t *where, vlc_array_t *changes )
-{
- assert( ppsz_query );
- assert( ppsz_id_query );
-
- *ppsz_query = NULL;
- int i_type;
- int i_index;
- int i_ret = VLC_ENOMEM;
-
- char *psz_table = NULL;
- /* TODO: Hack? */
- char *psz_set[ ML_DIRECTORY + 1 ] = { NULL };
- char *psz_fullset = NULL;
- char *psz_extra = NULL; /*<< For an update to extra table */
-
- char *psz_where = NULL;
- char *psz_tmp = NULL;
-
- int *pi_padd_ids = NULL;
- int i_people_add = 0;
-
- int i_album_id = 0;
- char *psz_album = NULL;
- char *psz_cover = NULL;
-
-
- if( !where )
- {
- msg_Warn( p_ml, "You're trying to update no rows."
- "Trying to guess update based on uri" );
- }
-
- /* Create the id/uri lists for WHERE part of the query */
- i_ret = BuildWhere( p_ml, &psz_where, where );
- if( i_ret != VLC_SUCCESS )
- goto quit_buildupdate;
- i_ret = VLC_ENOMEM;
-
- /** Firstly, choose the right table */
- switch( selected_type )
- {
- case ML_ALBUM:
- psz_table = strdup( "album" );
- break;
- case ML_PEOPLE:
- psz_table = strdup( "people" );
- break;
- case ML_MEDIA:
- psz_table = strdup( "media" );
- break;
- default:
- msg_Err( p_ml, "Not a valid element to Update!" );
- i_ret = VLC_EGENERIC;
- goto quit_buildupdate;
- break;
- }
-
- if( !psz_table )
- return VLC_ENOMEM;
-
- /** Secondly, build the SET part of the query */
- for( i_index = 0; i_index < vlc_array_count( changes ); i_index++ )
- {
- ml_element_t *find = ( ml_element_t * )
- vlc_array_item_at_index( changes, i_index );
- i_type = find->criteria;
-
- switch( i_type )
- {
- case ML_ALBUM:
- if( selected_type == ML_ALBUM )
- {
- if( !psz_set[i_type] )
- {
- psz_set[i_type] = sql_Printf( p_ml->p_sys->p_sql,
- "title = %Q",
- find->value.str );
- if( !psz_set[i_type] )
- {
- msg_Err( p_ml, "Couldn't create string at BuildUpdate():(%s, %d)",
- __FILE__, __LINE__ );
- goto quit_buildupdate;
- }
- }
- }
- else if( selected_type == ML_MEDIA )
- {
- if( !psz_album )
- psz_album = find->value.str;
- }
- else
- assert( 0 );
- break;
- case ML_ALBUM_ID:
- assert( selected_type != ML_ALBUM );
- if( selected_type == ML_MEDIA )
- {
- if( i_album_id <= 0 )
- {
- i_album_id = find->value.i;
- if( !psz_set[i_type] )
- {
- psz_set[i_type] = sql_Printf( p_ml->p_sys->p_sql,
- "album_id = '%d'",
- find->value.i );
- if( !psz_set[i_type] )
- {
- msg_Err( p_ml, "Couldn't create string at BuildUpdate():(%s, %d)",
- __FILE__, __LINE__ );
- goto quit_buildupdate;
- }
- }
- }
- }
- break;
- case ML_PEOPLE:
- if( selected_type == ML_MEDIA )
- {
- pi_padd_ids = (int*) realloc( pi_padd_ids , ( ++i_people_add * sizeof(int) ) );
- pi_padd_ids[ i_people_add - 1 ] = ml_GetInt( p_ml, ML_PEOPLE_ID,
- find->lvalue.str, ML_PEOPLE, find->lvalue.str,
- find->value.str );
- if( pi_padd_ids[ i_people_add - 1 ] <= 0 )
- {
- AddPeople( p_ml, find->value.str, find->lvalue.str );
- pi_padd_ids[ i_people_add - 1 ] = ml_GetInt( p_ml, ML_PEOPLE_ID,
- find->lvalue.str, ML_PEOPLE, find->lvalue.str,
- find->value.str );
- }
- }
- else if( strcmp( psz_lvalue, find->lvalue.str ) )
- {
- msg_Err( p_ml, "Trying to update a different person type" );
- return VLC_EGENERIC;
- }
- else
- {
- if( !psz_set[i_type] ) psz_set[i_type] =
- sql_Printf( p_ml->p_sys->p_sql, "name = %Q", find->value.str );
- }
- break;
- case ML_PEOPLE_ID:
- /* TODO: Implement smarter updates for this case? */
- assert( selected_type == ML_MEDIA );
- if( selected_type == ML_MEDIA )
- {
- bool b_update = true;
- for( int i = 0; i < i_people_add; i++ )
- {
- if( pi_padd_ids[ i ] == find->value.i )
- {
- b_update = false;
- break;
- }
- }
- if( b_update )
- {
- pi_padd_ids = (int *)realloc( pi_padd_ids, ( ++i_people_add * sizeof(int) ) );
- pi_padd_ids[ i_people_add - 1 ] = find->value.i;
- }
- }
- break;
- case ML_PEOPLE_ROLE:
- msg_Dbg( p_ml, "Can't update role" );
- break;
- case ML_COMMENT:
- assert( selected_type == ML_MEDIA );
- SET_STR( "comment = %Q" );
- case ML_COVER:
- assert( selected_type == ML_ALBUM || selected_type == ML_MEDIA );
- psz_cover = find->value.str;
- SET_STR( "cover = %Q" );
- case ML_DISC_NUMBER:
- assert( selected_type == ML_MEDIA );
- SET_INT( "disc = '%d'" );
- case ML_DURATION:
- assert( selected_type == ML_MEDIA );
- SET_INT( "duration = '%d'" );
- case ML_EXTRA:
- assert( selected_type == ML_MEDIA );
- SET_STR( "extra = %Q" );
- case ML_FIRST_PLAYED:
- assert( selected_type == ML_MEDIA );
- SET_INT( "first_played =='%d'" );
- case ML_GENRE:
- assert( selected_type == ML_MEDIA );
- SET_STR( "genre = %Q" );
- /* ID cannot be updated */
- /* Import time can't be updated */
- case ML_LAST_PLAYED:
- assert( selected_type == ML_MEDIA );
- SET_INT( "last_played = '%d'" );
- case ML_ORIGINAL_TITLE:
- assert( selected_type == ML_MEDIA );
- SET_STR( "original_title = %Q" );
- case ML_PLAYED_COUNT:
- assert( selected_type == ML_MEDIA );
- SET_INT( "played_count = '%d'" );
- case ML_PREVIEW:
- assert( selected_type == ML_MEDIA );
- SET_STR( "preview = %Q" );
- case ML_SKIPPED_COUNT:
- assert( selected_type == ML_MEDIA );
- SET_INT( "skipped_count = '%d'" );
- case ML_SCORE:
- assert( selected_type == ML_MEDIA );
- SET_INT( "score = '%d'" );
- case ML_TITLE:
- assert( selected_type == ML_MEDIA );
- SET_STR( "title = %Q" );
- case ML_TRACK_NUMBER:
- assert( selected_type == ML_MEDIA );
- SET_INT( "track = '%d'" );
- case ML_TYPE:
- assert( selected_type == ML_MEDIA );
- if( !psz_set[i_type] ) psz_set[i_type] =
- sql_Printf( p_ml->p_sys->p_sql, "type = '%d'", find->value.i );
- break;
- case ML_URI:
- assert( selected_type == ML_MEDIA );
- if( !psz_set[i_type] )
- {
- psz_set[i_type] = sql_Printf( p_ml->p_sys->p_sql,
- "uri = %Q",
- find->value.str );
- }
- break;
- case ML_VOTE:
- assert( selected_type == ML_MEDIA );
- SET_INT( "vote = '%d'" );
- case ML_YEAR:
- assert( selected_type == ML_MEDIA );
- SET_INT( "year = '%d'" );
- case ML_END:
- goto exitfor;
- default:
- msg_Warn( p_ml, "Invalid type for update : %d", i_type );
- }
- }
-exitfor:
-
- /* TODO: Album artist. Verify albumart */
- if( i_album_id <= 0 && psz_album )
- {
- i_album_id = ml_GetAlbumId( p_ml, psz_album );
- if( i_album_id < 0 ) //0 is Unknown
- {
- i_ret = AddAlbum( p_ml, psz_album, psz_cover, 0 );
- if( i_ret != VLC_SUCCESS )
- {
-
- msg_Err( p_ml, "Couldn't AddAlbum at BuildUpdate():(%s, %d)",
- __FILE__, __LINE__ );
- goto quit_buildupdate;
- }
- i_album_id = ml_GetAlbumId( p_ml, psz_album );
- if( i_album_id < 0 )
- goto quit_buildupdate;
- }
- psz_set[ML_ALBUM_ID] = sql_Printf( p_ml->p_sys->p_sql,
- "album_id = '%d'", i_album_id );
- if( !psz_set[ML_ALBUM_ID] )
- {
- msg_Err( p_ml, "Couldn't create string at BuildUpdate():(%s, %d)",
- __FILE__, __LINE__ );
- goto quit_buildupdate;
- }
- }
-
- for( unsigned i = 0; i <= ML_DIRECTORY; i++ )
- {
- if( psz_set[i] )
- {
- if( i == ML_EXTRA || i == ML_LANGUAGE )
- {
- free( psz_tmp );
- if( asprintf( &psz_tmp, "%s%s%s", psz_extra ? psz_extra : "",
- psz_extra ? ", ": "", psz_set[i] ) == -1 )
- {
- msg_Err( p_ml, "Couldn't create string at BuildUpdate():(%s, %d)",
- __FILE__, __LINE__ );
- goto quit_buildupdate;
- }
- free( psz_extra );
- psz_extra = strdup( psz_tmp );
- }
- else
- {
- free( psz_tmp );
- if( asprintf( &psz_tmp, "%s%s%s", psz_fullset ? psz_fullset : "",
- psz_fullset ? ", ": "", psz_set[i] ) == -1 )
- {
- msg_Err( p_ml, "Couldn't create string at BuildUpdate():(%s, %d)",
- __FILE__, __LINE__ );
- goto quit_buildupdate;
- }
- free( psz_fullset );
- psz_fullset = strdup( psz_tmp );
- }
- }
- }
- i_ret = VLC_SUCCESS;
-
- /** Now build the right WHERE condition */
- assert( psz_where && *psz_where );
-
- /** Finally build the full query */
- /** Pass if we have some people to add - Indirect update */
- if( !psz_fullset && i_people_add == 0 )
- {
- i_ret = VLC_EGENERIC;
- msg_Err( p_ml, "Nothing found to create update at BuildUpdate():(%s, %d)",
- __FILE__, __LINE__ );
- goto quit_buildupdate;
- }
-
- if( psz_fullset ){
- if( asprintf( ppsz_query, "UPDATE %s SET %s WHERE %s", psz_table,
- psz_fullset, psz_where ) == -1 )
- {
- msg_Err( p_ml, "Couldn't create string at BuildUpdate():(%s, %d)",
- __FILE__, __LINE__ );
- goto quit_buildupdate;
- }
- }
-
- if( selected_type == ML_MEDIA )
- {
- if( psz_extra )
- {
- if( asprintf( &psz_tmp, "%s; UPDATE extra SET %s WHERE %s",
- *ppsz_query, psz_extra, psz_where ) == -1 )
- {
- msg_Err( p_ml, "Couldn't create string at BuildUpdate():(%s, %d)",
- __FILE__, __LINE__ );
- goto quit_buildupdate;
- }
- free( *ppsz_query );
- *ppsz_query = psz_tmp;
- psz_tmp = NULL;
- }
- char* psz_idstring = NULL;
- if( i_people_add > 0 )
- {
- for( int i = 0; i < i_people_add; i++ )
- {
- if( asprintf( &psz_tmp, "%s%s%d", psz_idstring == NULL? "" : psz_idstring,
- psz_idstring == NULL ? "" : ",", pi_padd_ids[i] ) == -1 )
- {
- free( psz_tmp );
- free( psz_idstring );
- msg_Err( p_ml, "Couldn't create string at BuildUpdate():(%s, %d)",
- __FILE__, __LINE__ );
- goto quit_buildupdate;
- }
- free( psz_idstring );
- psz_idstring = psz_tmp;
- psz_tmp = NULL;
- }
- /* Delete all connections with people whom we will update now! */
- if( asprintf( &psz_tmp, "%s;DELETE FROM media_to_people WHERE EXISTS "
- "(SELECT media.id, people.id FROM media JOIN media_to_people "
- "AS temp ON media.id = temp.media_id "
- "JOIN people ON temp.people_id = people.id "
- "WHERE %s AND people.role IN "
- "(SELECT people.role FROM people WHERE people.id IN (%s)) "
- "AND people.id NOT IN (%s) "
- "AND temp.media_id = media_to_people.media_id AND "
- "temp.people_id = media_to_people.people_id )",
- *ppsz_query == NULL ? "": *ppsz_query, psz_where,
- psz_idstring, psz_idstring ) == -1 )
- {
- free( psz_idstring );
- msg_Err( p_ml, "Couldn't create string at BuildUpdate():(%s, %d)",
- __FILE__, __LINE__ );
- goto quit_buildupdate;
- }
- free( *ppsz_query );
- *ppsz_query = psz_tmp;
- psz_tmp = NULL;
- free( psz_idstring );
- }
- for( int i = 0; i < i_people_add ; i++ )
- {
- if( pi_padd_ids[i] > 0 )
- {
- /* OR IGNORE will avoid errors from collisions from old media
- * Perhaps this hack can be fixed...FIXME */
- if( asprintf( &psz_tmp, "%s;INSERT OR IGNORE into media_to_people "
- "(media_id,people_id) SELECT media.id, %d FROM media WHERE %s",
- *ppsz_query == NULL ? "" : *ppsz_query, pi_padd_ids[i],
- psz_where ) == -1 )
- {
- msg_Err( p_ml, "Couldn't create string at BuildUpdate():(%s, %d)",
- __FILE__, __LINE__ );
- goto quit_buildupdate;
- }
- FREENULL( *ppsz_query );
- *ppsz_query = psz_tmp;
- psz_tmp = NULL;
- }
- }
- }
-
- if( asprintf( ppsz_id_query, "SELECT id AS %s_id FROM %s WHERE %s",
- psz_table, psz_table, psz_where ) == -1 )
- {
- msg_Err( p_ml, "Couldn't create string at BuildUpdate():(%s, %d)",
- __FILE__, __LINE__ );
- goto quit_buildupdate;
- }
-#ifndef NDEBUG
- msg_Dbg( p_ml, "updated media where %s", psz_where );
-#endif
- goto quit_buildupdate_success;
-
-quit_buildupdate:
- msg_Warn( p_ml, "BuildUpdate() could not generate update sql query" );
-quit_buildupdate_success:
- free( psz_tmp );
- free( psz_table );
- free( psz_fullset );
- free( psz_extra );
- free( pi_padd_ids );
- for( int i = 0; i <= ML_DIRECTORY; i++ )
- free( psz_set[ i ] );
-
- return i_ret;
-}
-
-#undef SET_STR
-#undef SET_INT
-
-/**
- * @brief Update a ml_media_t
- *
- * @param p_ml the media library object
- * @param p_media media to synchronise in the database
- * @return VLC_SUCCESS or VLC_EGENERIC
- * @note: the media id may be 0, in this case, the update is based
- * on the url (less powerful). This function is threadsafe
- *
- * This synchronises all non NULL and non zero fields of p_media
- * Synchronization of album and people is TODO
- */
-int UpdateMedia( media_library_t *p_ml, ml_media_t *p_media )
-{
- assert( p_media->i_id || ( p_media->psz_uri && *p_media->psz_uri ) );
- vlc_array_t *changes = vlc_array_new();
- ml_element_t *find = NULL;
- int i_ret = VLC_EGENERIC;
-
- ml_LockMedia( p_media );
-#define APPEND_ICHANGES( cond, crit ) \
- if( cond ) { \
- find = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) ); \
- find->criteria = crit; \
- find->value.i = cond; \
- vlc_array_append( changes, find ); \
- }
-#define APPEND_SCHANGES( cond, crit ) \
- if( cond ) { \
- find = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) ); \
- find->criteria = crit; \
- find->value.str = cond; \
- vlc_array_append( changes, find ); \
- }
-
- APPEND_SCHANGES( p_media->psz_title, ML_TITLE );
- APPEND_ICHANGES( p_media->i_type, ML_TYPE );
- APPEND_ICHANGES( p_media->i_duration, ML_DURATION );
- APPEND_SCHANGES( p_media->psz_preview, ML_PREVIEW );
- APPEND_SCHANGES( p_media->psz_cover, ML_COVER );
- APPEND_ICHANGES( p_media->i_disc_number, ML_DISC_NUMBER );
- APPEND_ICHANGES( p_media->i_track_number, ML_TRACK_NUMBER );
- APPEND_ICHANGES( p_media->i_year, ML_YEAR);
- APPEND_SCHANGES( p_media->psz_genre, ML_GENRE );
- APPEND_ICHANGES( p_media->i_album_id, ML_ALBUM_ID );
- APPEND_SCHANGES( p_media->psz_album, ML_ALBUM );
- APPEND_ICHANGES( p_media->i_skipped_count, ML_SKIPPED_COUNT );
- APPEND_ICHANGES( p_media->i_last_skipped, ML_LAST_SKIPPED );
- APPEND_ICHANGES( p_media->i_played_count, ML_PLAYED_COUNT );
- APPEND_ICHANGES( p_media->i_last_played, ML_LAST_PLAYED );
- APPEND_ICHANGES( p_media->i_first_played, ML_FIRST_PLAYED );
- APPEND_ICHANGES( p_media->i_vote, ML_VOTE );
- APPEND_ICHANGES( p_media->i_score, ML_SCORE );
- APPEND_SCHANGES( p_media->psz_comment, ML_COMMENT );
- APPEND_SCHANGES( p_media->psz_extra, ML_EXTRA );
- APPEND_SCHANGES( p_media->psz_language, ML_LANGUAGE );
-
- if( p_media->psz_uri && p_media->i_id )
- {
- find = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) );
- find->criteria = ML_URI;
- find->value.str = p_media->psz_uri;
- vlc_array_append( changes, find );
- }
- /*TODO: implement extended meta */
- /* We're not taking import time! Good */
-
-#undef APPEND_ICHANGES
-#undef APPEND_SCHANGES
- ml_person_t* person = p_media->p_people;
- while( person )
- {
- if( person->i_id > 0 )
- {
- find = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) );
- find->criteria = ML_PEOPLE_ID;
- find->lvalue.str = person->psz_role;
- find->value.i = person->i_id;
- vlc_array_append( changes, find );
- }
- else if( person->psz_name && *person->psz_name )
- {
- find = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) );
- find->criteria = ML_PEOPLE;
- find->lvalue.str = person->psz_role;
- find->value.str = person->psz_name;
- vlc_array_append( changes, find );
- }
- person = person->p_next;
- }
-
- ml_ftree_t* p_where = NULL;
- ml_ftree_t* p_where_elt = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
- if( p_media->i_id )
- {
- p_where_elt->criteria = ML_ID;
- p_where_elt->value.i = p_media->i_id ;
- p_where_elt->comp = ML_COMP_EQUAL;
- p_where = ml_FtreeFastAnd( p_where, p_where_elt );
- }
- else if( p_media->psz_uri )
- {
- p_where_elt->criteria = ML_URI;
- p_where_elt->value.str = p_media->psz_uri;
- p_where_elt->comp = ML_COMP_EQUAL;
- p_where = ml_FtreeFastAnd( p_where, p_where_elt );
- }
- else
- {
- goto quit1;
- }
- i_ret = Update( p_ml, ML_MEDIA, NULL, p_where, changes );
-
-quit1:
- ml_FreeFindTree( p_where );
- for( int i = 0; i < vlc_array_count( changes ); i++ )
- /* Note: DO NOT free the strings because
- * they belong to the ml_media_t object */
- free( vlc_array_item_at_index( changes, i ) );
- vlc_array_destroy( changes );
- ml_UnlockMedia( p_media );
- return i_ret;
-}
-
-/**
- * @brief Update an album's cover art
- * @param p_ml The Media Library
- * @param i_album_id Album's ID
- * @param psz_cover New cover art
- * @return VLC success/error code
- **/
-int SetArtCover( media_library_t *p_ml,
- int i_album_id, const char *psz_cover )
-{
- assert( i_album_id != 0 );
- assert( psz_cover != NULL );
-
- char *psz_query = sql_Printf( p_ml->p_sys->p_sql,
- "UPDATE album SET cover = %Q WHERE id = '%d'",
- psz_cover, i_album_id );
-
- if( !psz_query )
- return VLC_ENOMEM;
-
- if( QuerySimple( p_ml, "%s", psz_query ) != VLC_SUCCESS )
- {
- msg_Warn( p_ml, "Could not update the album's cover art "
- "(Database error)" );
- free( psz_query );
- return VLC_EGENERIC;
- }
-
- free( psz_query );
- return VLC_SUCCESS;
-}
modules/lua/meta.c
modules/lua/vlc.c
modules/lua/vlc.h
-modules/media_library/sql_media_library.c
modules/meta_engine/folder.c
modules/meta_engine/taglib.cpp
modules/misc/audioscrobbler.c