>From ae30810af3526d74ae6faa9f864e4af54ed8d945 Mon Sep 17 00:00:00 2001
From: Antoine Lejeune <phytos@via.ecp.fr>
Date: Tue, 25 Mar 2008 12:44:26 +0100
Subject: [PATCH] Ability to remember the item playing when VLC is closed so that when VLC
 is restarted the item restarts at the last position.
 I've had a new option remember-playing-item which control this behaviour
 and which is true by default.

---
 include/vlc_input.h              |    5 ++-
 src/input/control.c              |   23 ++++++++++
 src/libvlc-module.c              |    6 +++
 src/playlist/engine.c            |    3 +
 src/playlist/loadsave.c          |   90 ++++++++++++++++++++++++++++++++++++++
 src/playlist/playlist_internal.h |    4 ++
 src/playlist/tree.c              |    2 +-
 7 files changed, 131 insertions(+), 2 deletions(-)

diff --git a/include/vlc_input.h b/include/vlc_input.h
index 75af0c0..6a6f3b5 100644
--- a/include/vlc_input.h
+++ b/include/vlc_input.h
@@ -711,7 +711,10 @@ enum input_query_e
     INPUT_GET_ATTACHMENT,  /* arg1=input_attachment_t**, arg2=char*  res=can fail */
 
     /* On the fly input slave */
-    INPUT_ADD_SLAVE        /* arg1= char * */
+    INPUT_ADD_SLAVE,       /* arg1= char * */
+    
+    /* Saving to the start-time option the playing time */
+    INPUT_SAVE_TIME        /* res= */
 };
 
 VLC_EXPORT( int, input_vaControl,( input_thread_t *, int i_query, va_list  ) );
diff --git a/src/input/control.c b/src/input/control.c
index 3b6af5d..d64e0e7 100644
--- a/src/input/control.c
+++ b/src/input/control.c
@@ -588,7 +588,30 @@ int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
             vlc_mutex_unlock( &p_input->p->input.p_item->lock );
             return VLC_EGENERIC;
         }
+        
+        case INPUT_SAVE_TIME:
+        {
+            char *psz_time;
+            if( asprintf( &psz_time, I64Fd, p_input->i_time/1000000 ) == -1 )
+                psz_time = NULL;
+            input_Control( p_input, INPUT_ADD_OPTION, "start-time", psz_time );
+
+            // If it's a dvd://, rename it if its title is > 0 (not the menu)
+            const char *psz_access, *psz_demux;
+            char *psz_path;
+            char *psz_uri = strdup( p_input->p->input.p_item->psz_uri );
+
+            MRLSplit( psz_uri, &psz_access, &psz_demux, &psz_path );
+            if( strcmp( psz_access, "dvd" ) == 0 && 
+                var_GetInteger( p_input, "title" ) > 0 &&
+                asprintf( &p_input->p->input.p_item->psz_uri,
+                          "dvdsimple://%s", psz_path ) == -1 )
+                p_input->p->input.p_item->psz_uri = NULL;
 
+            free( psz_uri );
+
+            return VLC_SUCCESS;
+        }
 
         default:
             msg_Err( p_input, "unknown query in input_vaControl" );
diff --git a/src/libvlc-module.c b/src/libvlc-module.c
index 90e668b..779db23 100644
--- a/src/libvlc-module.c
+++ b/src/libvlc-module.c
@@ -1118,6 +1118,11 @@ static const char *ppsz_albumart_descriptions[] =
     "The media library is automatically saved and reloaded each time you " \
     "start VLC." )
 
+#define RPL_TEXT N_("Remember the playing item")
+#define RPL_LONGTEXT N_( \
+    "Remember the item playing when VLC was closed so that it will be " \
+    "reopened at the correct position." )
+
 #define PLTREE_TEXT N_("Use playlist tree")
 #define PLTREE_LONGTEXT N_( \
     "The playlist can use a tree to categorize some items, like the " \
@@ -1863,6 +1868,7 @@ vlc_module_begin();
     add_bool( "play-and-exit", 0, NULL, PAE_TEXT, PAE_LONGTEXT, VLC_FALSE );
     add_bool( "play-and-stop", 0, NULL, PAS_TEXT, PAS_LONGTEXT, VLC_FALSE );
     add_bool( "media-library", 1, NULL, ML_TEXT, ML_LONGTEXT, VLC_FALSE );
+    add_bool( "remember-playing-item", 1, NULL, RPL_TEXT, RPL_LONGTEXT, VLC_FALSE );
     add_integer( "playlist-tree", 0, NULL, PLTREE_TEXT, PLTREE_LONGTEXT,
                  VLC_TRUE );
         change_integer_list( pi_pltree_values, ppsz_pltree_descriptions, 0 );
diff --git a/src/playlist/engine.c b/src/playlist/engine.c
index 07f0b72..5413386 100644
--- a/src/playlist/engine.c
+++ b/src/playlist/engine.c
@@ -154,6 +154,7 @@ playlist_t * playlist_Create( vlc_object_t *p_parent )
     b_save = p_playlist->b_auto_preparse;
     p_playlist->b_auto_preparse = VLC_FALSE;
     playlist_MLLoad( p_playlist );
+    playlist_RestorePlayingItem( p_playlist );
     p_playlist->b_auto_preparse = VLC_TRUE;
     return p_playlist;
 }
@@ -418,6 +419,7 @@ void playlist_LastLoop( playlist_t *p_playlist )
         }
         else if( p_playlist->p_input->b_error || p_playlist->p_input->b_eof )
         {
+            input_Control( p_playlist->p_input, INPUT_SAVE_TIME);
             input_StopThread( p_playlist->p_input );
             PL_UNLOCK;
             continue;
@@ -455,6 +457,7 @@ void playlist_LastLoop( playlist_t *p_playlist )
                                           p_playlist->pp_sds[0]->p_sd->psz_module );
     }
 
+    playlist_SavePlayingItem( p_playlist );
     playlist_MLDump( p_playlist );
 
     PL_LOCK;
diff --git a/src/playlist/loadsave.c b/src/playlist/loadsave.c
index b50c76d..d6b8513 100644
--- a/src/playlist/loadsave.c
+++ b/src/playlist/loadsave.c
@@ -199,3 +199,93 @@ int playlist_MLDump( playlist_t *p_playlist )
 
     return VLC_SUCCESS;
 }
+
+int playlist_SavePlayingItem( playlist_t *p_playlist )
+{
+    char *psz_datadir = p_playlist->p_libvlc->psz_datadir;
+    if( !config_GetInt( p_playlist, "remember-playing-item" ) )
+        return VLC_SUCCESS;
+    if( !psz_datadir ) /* XXX: This should never happen */
+    {
+        msg_Err( p_playlist, "no data directory, cannot save media library") ;
+        return VLC_EGENERIC;
+    }
+
+    char psz_dirname[ strlen( psz_datadir )
+                      + sizeof( DIR_SEP "last-played.xspf")];
+    sprintf( psz_dirname, "%s", psz_datadir );
+    if( config_CreateDir( (vlc_object_t *)p_playlist, psz_dirname ) )
+    {
+        return VLC_EGENERIC;
+    }
+
+    strcat( psz_dirname, DIR_SEP "last-played.xspf" );
+    
+    // If playlist is stopped then we don't want to save anything and delete 
+    // last-played.xspf if it exists.
+    if( p_playlist->status.i_status == PLAYLIST_STOPPED )
+    {
+        utf8_unlink( psz_dirname );
+        return VLC_SUCCESS;
+    }
+
+    playlist_item_t *p_playlist_item = playlist_NodeCreate( 
+        p_playlist,
+        "Playing when VLC was closed",
+        NULL, 0,
+        NULL );
+    playlist_NodeAppend( p_playlist, 
+                         ARRAY_VAL( p_playlist->current, 
+                                    p_playlist->i_current_index ),
+                         p_playlist_item );
+
+    playlist_Export( p_playlist, psz_dirname, p_playlist_item, "export-xspf" );
+
+    return VLC_SUCCESS;
+}
+
+int playlist_RestorePlayingItem( playlist_t *p_playlist )
+{
+    const char *psz_datadir = p_playlist->p_libvlc->psz_datadir;
+    char *psz_uri = NULL;
+    input_item_t *p_input;
+
+    if( !config_GetInt( p_playlist, "remember-playing-item") ) 
+        return VLC_SUCCESS;
+    if( !psz_datadir ) /* XXX: This should never happen */
+    {
+        msg_Err( p_playlist, "no data directory, cannot restore the playing item") ;
+        return VLC_EGENERIC;
+    }
+
+    if( asprintf( &psz_uri, "%s" DIR_SEP "last-played.xspf", psz_datadir ) == -1 )
+    {
+        psz_uri = NULL;
+        goto error;
+    }
+    struct stat p_stat;
+    /* checks if playing item file is present */
+    if( utf8_stat( psz_uri , &p_stat ) )
+    {
+        free( psz_uri );
+        return VLC_EGENERIC;
+    }
+    free( psz_uri );
+
+    if( asprintf( &psz_uri, "file/xspf-open://%s" DIR_SEP "last-played.xspf",
+                  psz_datadir ) == -1 )
+    {
+        psz_uri = NULL;
+        goto error;
+    }
+
+    playlist_Add( p_playlist, psz_uri, _("Playing when VLC was closed"), 0, 0,
+                  VLC_TRUE, VLC_FALSE);
+
+    free( psz_uri );
+    return VLC_SUCCESS;
+
+error:
+    free( psz_uri );
+    return VLC_ENOMEM;
+}
diff --git a/src/playlist/playlist_internal.h b/src/playlist/playlist_internal.h
index 8ba4278..e4517c1 100644
--- a/src/playlist/playlist_internal.h
+++ b/src/playlist/playlist_internal.h
@@ -91,6 +91,10 @@ int playlist_PlayItem  ( playlist_t *, playlist_item_t * );
 int playlist_MLLoad( playlist_t *p_playlist );
 int playlist_MLDump( playlist_t *p_playlist );
 
+/* Load/Save of last playing item */
+int playlist_SavePlayingItem( playlist_t *p_playlist );
+int playlist_RestorePlayingItem( playlist_t *p_playlist );
+
 /**********************************************************************
  * Item management
  **********************************************************************/
diff --git a/src/playlist/tree.c b/src/playlist/tree.c
index 35f50cf..bdd7363 100644
--- a/src/playlist/tree.c
+++ b/src/playlist/tree.c
@@ -48,7 +48,7 @@ playlist_item_t *GetPrevItem( playlist_t *p_playlist,
  * Create a playlist node
  *
  * \param p_playlist the playlist
- * \paam psz_name the name of the node
+ * \param psz_name the name of the node
  * \param p_parent the parent node to attach to or NULL if no attach
  * \param p_flags miscellaneous flags
  * \param p_input the input_item to attach to or NULL if it has to be created
-- 
1.5.3.7

