]> git.sesse.net Git - vlc/blobdiff - modules/media_library/sql_media_library.c
pulse: fix start time, do not confuse first and last PTS in buffer
[vlc] / modules / media_library / sql_media_library.c
index 5af66a1b746f21e74ab30e37d5f0d38952ea4f53..6a5788d61c4395b35e8385d688d5b4fed92ae321 100644 (file)
  * 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 };
@@ -52,50 +56,55 @@ static const char* ppsz_VideoExtensions[] = { EXTENSIONS_VIDEO_CSV, NULL };
 static int load( vlc_object_t* );
 static void unload( vlc_object_t* );
 
-static int CreateInputItemFromMedia( media_library_t *p_ml,
-                              input_item_t **pp_item,
-                              ml_media_t *p_media );
+static int CreateInputItemFromMedia( input_item_t **pp_item,
+                                     ml_media_t *p_media );
 
 
 struct ml_table_elt
 {
     int column_id;
-    char column_name[];
+    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" }
+    { 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" }
 };
 
 /*****************************************************************************
@@ -120,6 +129,8 @@ vlc_module_begin()
             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()
 
 
@@ -148,7 +159,12 @@ static int load( vlc_object_t *obj )
     vlc_mutex_init( &p_ml->p_sys->lock );
 
     /* Initialise Sql module */
-    InitDatabase( p_ml );
+    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 );
@@ -471,31 +487,23 @@ int SQLToMediaArray( media_library_t *p_ml, vlc_array_t *p_result_array,
     /* 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++ )
     {
-        //binary search
-        int low = 0, high = count - 1;
-        int answer = -1;
-        while( low <= high ) {
-            int mid = (low + high ) / 2;
-            char* mid_val = ml_table_map[mid].column_name;
-            int cmp = strcmp( mid_val, res( 0, col ) );
-            if( cmp > 0 )
-                low = mid + 1;
-            else if ( cmp < 0 )
-                high = mid - 1;
-            else
-            {
-                answer = mid;  break;
-            }
-        }
-        if( answer == -1 )
+        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] = ml_table_map[answer].column_id;
+            indexes[col] = result->column_id;
     }
 
     /* Read rows 1 to i_rows */
@@ -508,14 +516,16 @@ int SQLToMediaArray( media_library_t *p_ml, vlc_array_t *p_result_array,
         if( !p_media )
         {
             free( indexes );
-            return VLC_ENOMEM;
+            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 );
-            return VLC_ENOMEM;
+            i_ret = VLC_ENOMEM;
+            goto quit_sqlmediaarray;
         }
 
         char* psz_append_pname = NULL;
@@ -626,6 +636,7 @@ int SQLToMediaArray( media_library_t *p_ml, vlc_array_t *p_result_array,
         }
         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),
@@ -792,6 +803,10 @@ int CreateEmptyDatabase( media_library_t *p_ml )
     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 ) "
@@ -834,6 +849,10 @@ int CreateEmptyDatabase( media_library_t *p_ml )
     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 ( "
@@ -1016,6 +1035,33 @@ quit_createemptydatabase:
     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)
@@ -1031,10 +1077,12 @@ int InitDatabase( media_library_t *p_ml )
     /* 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 )
@@ -1055,11 +1103,7 @@ int InitDatabase( media_library_t *p_ml )
     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 )
-    {
-        vlc_mutex_destroy( &p_ml->p_sys->lock );
-        free( p_ml->p_sys );
         return VLC_EGENERIC;
-    }
 
     /* Let's check if tables exist */
     int i_version = GetDatabaseVersion( p_ml );
@@ -1077,6 +1121,8 @@ int InitDatabase( media_library_t *p_ml )
 #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;
 }
@@ -1127,7 +1173,7 @@ ml_media_t* GetMedia( media_library_t* p_ml, int id,
         else
         {
             ml_LockMedia( p_media );
-            if( p_media->b_sparse == true && select == ML_MEDIA )
+            if( p_media->b_sparse && select == ML_MEDIA )
                 reload = true;
             /* Utilise ML_MEDIA_EXTRA load? TODO */
             ml_UnlockMedia( p_media );
@@ -1175,7 +1221,7 @@ input_item_t* GetInputItemFromMedia( media_library_t *p_ml, int i_media )
         ml_media_t* p_media = media_New( p_ml, i_media, ML_MEDIA, true );
         if( p_media == NULL )
             return NULL;
-        CreateInputItemFromMedia( p_ml, &p_item, p_media );
+        CreateInputItemFromMedia( &p_item, p_media );
         watch_add_Item( p_ml, p_item, p_media );
         ml_gc_decref( p_media );
     }
@@ -1205,7 +1251,7 @@ void CopyInputItemToMedia( ml_media_t *p_media, input_item_t *p_item )
     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    = strdup( p_item->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 );
@@ -1305,7 +1351,7 @@ 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 )
+    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 );
@@ -1348,19 +1394,14 @@ void CopyMediaToInputItem( input_item_t *p_item, ml_media_t *p_media )
 
 /**
  * @brief Copy a ml_media_t to an input_item_t
- * @param p_ml The Media Library object
  * @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( media_library_t *p_ml,
-                              input_item_t **pp_item,
-                              ml_media_t *p_media )
+static int CreateInputItemFromMedia( input_item_t **pp_item,
+                                     ml_media_t *p_media )
 {
-    playlist_t *p_pl = pl_Get( p_ml );
-    *pp_item = input_item_New( VLC_OBJECT( p_pl ),
-                               p_media->psz_uri,
-                               p_media->psz_title );
+    *pp_item = input_item_New( p_media->psz_uri, p_media->psz_title );
                                /* ITEM_TYPE_FILE ); */
     if( !*pp_item )
         return VLC_EGENERIC;