diff --git a/configure.in b/configure.in
index e87b9fc..87a014a 100644
--- a/configure.in
+++ b/configure.in
@@ -50,7 +50,7 @@ AC_SUBST(TOTEM_VERSION_MINOR)
 AC_SUBST(TOTEM_VERSION_MICRO)
 
 # The full list of plugins
-allowed_plugins="thumbnail screensaver ontop galago gromit lirc media-player-keys mythtv properties sidebar-test skipto sample-python sample-vala bemused youtube publish tracker pythonconsole jamendo opensubtitles screenshot brasero-disc-recorder coherence_upnp"
+allowed_plugins="thumbnail screensaver ontop galago gromit lirc media-player-keys mythtv properties sidebar-test skipto sample-python sample-vala bemused youtube publish tracker pythonconsole jamendo opensubtitles screenshot brasero-disc-recorder coherence_upnp resume-playback"
 
 PLUGINDIR='${libdir}/totem/plugins'
 AC_SUBST(PLUGINDIR)
@@ -876,6 +876,7 @@ src/plugins/pythonconsole/Makefile
 src/plugins/publish/Makefile
 src/plugins/jamendo/Makefile
 src/plugins/brasero-disc-recorder/Makefile
+src/plugins/resume-playback/Makefile
 src/backend/Makefile
 browser-plugin/Makefile
 data/Makefile
diff --git a/src/plugins/resume-playback/Makefile.am b/src/plugins/resume-playback/Makefile.am
new file mode 100644
index 0000000..2a43032
--- /dev/null
+++ b/src/plugins/resume-playback/Makefile.am
@@ -0,0 +1,44 @@
+modules_flags = -export_dynamic -avoid-version -module
+
+plugindir = $(PLUGINDIR)/resume-playback
+uidir = $(plugindir)
+plugin_LTLIBRARIES = libresume-playback.la
+
+plugin_in_files = resume-playback.totem-plugin.in
+
+%.totem-plugin: %.totem-plugin.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache
+
+plugin_DATA = $(plugin_in_files:.totem-plugin.in=.totem-plugin)
+ui_DATA = resume-playback.ui
+
+common_defines = \
+	-D_REENTRANT					\
+	-DDBUS_API_SUBJECT_TO_CHANGE			\
+	-DGNOMELOCALEDIR=\""$(datadir)/locale"\"	\
+	-DGCONF_PREFIX=\""/apps/totem"\"		\
+	-DDATADIR=\""$(datadir)"\"			\
+	-DLIBEXECDIR=\""$(libexecdir)"\"		\
+	-DBINDIR=\""$(bindir)"\"			\
+	-DTOTEM_PLUGIN_DIR=\""$(libdir)/totem/plugins"\"\
+	$(DISABLE_DEPRECATED)
+
+libresume_playback_la_SOURCES = totem-resume-playback-plugin.c totem-resume-playback-plugin.h totem-resume-list.c totem-resume-list.h
+libresume_playback_la_LDFLAGS = $(modules_flags)
+libresume_playback_la_CPPFLAGS = $(common_defines)
+
+libresume_playback_la_CFLAGS = \
+	$(DEPENDENCY_CFLAGS)	\
+	$(WARN_CFLAGS)		\
+	$(DBUS_CFLAGS)		\
+	$(AM_CFLAGS)		\
+	$(SCREENSAVER_CFLAGS)	\
+	-I$(top_srcdir)/	\
+	-I$(top_srcdir)/lib	\
+	-I$(top_srcdir)/src	\
+	-I$(top_srcdir)/src/plugins
+
+EXTRA_DIST = $(plugin_in_files) $(ui_DATA) 
+
+CLEANFILES = $(plugin_DATA) $(BUILT_SOURCES)
+DISTCLEANFILES = $(plugin_DATA)
+
diff --git a/src/plugins/resume-playback/resume-playback.totem-plugin.in b/src/plugins/resume-playback/resume-playback.totem-plugin.in
new file mode 100644
index 0000000..171bc33
--- /dev/null
+++ b/src/plugins/resume-playback/resume-playback.totem-plugin.in
@@ -0,0 +1,9 @@
+[Totem Plugin]
+Module=resume-playback
+IAge=1
+Builtin=false
+Name=Resume playback
+Description=Resume playback plugin.
+Authors=Iliya Grushevskiy <iliya@1kab.ru>
+Copyright=Copyright © 2009 Iliya Grushevskiy
+Website=http://www.gnome.org/projects/totem/
diff --git a/src/plugins/resume-playback/resume-playback.ui b/src/plugins/resume-playback/resume-playback.ui
new file mode 100644
index 0000000..9f2d0cb
--- /dev/null
+++ b/src/plugins/resume-playback/resume-playback.ui
@@ -0,0 +1,150 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkDialog" id="trp_dlg">
+    <property name="border_width">5</property>
+    <property name="type_hint">normal</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkFrame" id="frame1">
+            <property name="visible">True</property>
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">none</property>
+            <child>
+              <object class="GtkAlignment" id="alignment1">
+                <property name="visible">True</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <object class="GtkTable" id="table1">
+                    <property name="visible">True</property>
+                    <property name="n_rows">3</property>
+                    <property name="n_columns">2</property>
+                    <property name="row_spacing">5</property>
+                    <child>
+                      <object class="GtkLabel" id="label3">
+                        <property name="visible">True</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">Skip back seconds:</property>
+                      </object>
+                      <packing>
+                        <property name="y_options">GTK_FILL</property>
+                        <property name="x_padding">5</property>
+                        <property name="y_padding">5</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label4">
+                        <property name="visible">True</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">Store resume playback history days:</property>
+                      </object>
+                      <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="y_options">GTK_FILL</property>
+                        <property name="x_padding">5</property>
+                        <property name="y_padding">5</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkSpinButton" id="skip_back">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">&#x25CF;</property>
+                        <property name="adjustment">skip_back_adjustment</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkSpinButton" id="gc">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">&#x25CF;</property>
+                        <property name="adjustment">gc_adjustment</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="notify">
+                        <property name="label" translatable="yes">Notify resume</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="label">
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">&lt;b&gt;Resume options:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkAdjustment" id="skip_back_adjustment">
+    <property name="upper">3600</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+    <property name="page_size">10</property>
+  </object>
+  <object class="GtkAdjustment" id="gc_adjustment">
+    <property name="value">1</property>
+    <property name="lower">1</property>
+    <property name="upper">36500</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+    <property name="page_size">10</property>
+  </object>
+</interface>
diff --git a/src/plugins/resume-playback/totem-resume-list.c b/src/plugins/resume-playback/totem-resume-list.c
new file mode 100644
index 0000000..56bea55
--- /dev/null
+++ b/src/plugins/resume-playback/totem-resume-list.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2009 Iliya Grushevskiy <iliya@1kab.ru>
+ *
+ * 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.
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission are above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add exception clause.
+ * See license_change file for details.
+ */
+
+#include "totem-resume-list.h"
+
+#include <string.h>
+#include <time.h>
+
+struct TotemResumeListRecord
+{
+        time_t mtime; // last modified time
+        gint64 time; // time
+};
+
+
+TOTEM_PLUGIN_DEFINE_TYPE(TotemResumeList, totem_resume_list, G_TYPE_OBJECT)
+
+static int
+record_key_cmp(gconstpointer a, gconstpointer b, gpointer data)
+{
+        return strcmp((char*) a, (char*) b);
+}
+
+static void
+record_free(gpointer data)
+{
+        g_slice_free(struct TotemResumeListRecord, data);
+}
+
+static gboolean
+record_dump(gpointer key, gpointer value, gpointer data)
+{
+        GString *buffer = data;
+        g_return_val_if_fail( buffer != NULL, TRUE);
+
+        char* cbuf;
+        char* name = (char*) key;
+        struct TotemResumeListRecord *rec =
+                        (struct TotemResumeListRecord *) value;
+
+        cbuf = g_markup_printf_escaped(
+                        "<file path=\"%s\" time=\"%li\" mtime=\"%li\"/>\n",
+                        name,
+                        rec->time,
+                        rec->mtime);
+
+        g_string_append(buffer, cbuf);
+        g_free(cbuf);
+        return FALSE;
+}
+
+static void
+totem_resume_list_init(TotemResumeList* self)
+{
+        self->records = g_tree_new_full(record_key_cmp,
+                        NULL,
+                        g_free,
+                        record_free);
+}
+
+static void
+totem_resume_list_dispose(GObject* object)
+{
+        TotemResumeList *self = TOTEM_RESUME_LIST(object);
+
+        /* release tree */
+        if (self->records != NULL) {
+                g_tree_destroy(self->records);
+                self->records = NULL;
+        }
+
+        G_OBJECT_CLASS(totem_resume_list_parent_class)->dispose(object);
+}
+
+static void
+totem_resume_list_class_init(TotemResumeListClass* klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS(klass);
+        object_class->dispose = totem_resume_list_dispose;
+}
+
+TotemResumeList*
+totem_resume_list_new()
+{
+        return g_object_new(TOTEM_TYPE_RESUME_LIST, NULL);
+}
+
+void
+totem_resume_list_free(TotemResumeList* rlist)
+{
+        g_object_unref(rlist);
+}
+
+void
+totem_resume_list_insert_ext(TotemResumeList *rlist, const char *name,
+                             gint64 vtime, time_t mtime)
+{
+        g_return_if_fail(rlist->records != NULL);
+
+        struct TotemResumeListRecord *rec;
+
+        /* update record if it already exists else insert new */
+        if ((rec = g_tree_lookup(rlist->records, name)) != NULL) {
+                rec->time = vtime;
+                rec->mtime = mtime;
+        } else {
+                rec = g_slice_new(struct TotemResumeListRecord);
+                rec->time = vtime;
+                rec->mtime = mtime;
+                g_tree_insert(rlist->records, strdup(name), rec);
+        }
+}
+
+gint64
+totem_resume_list_lookup(TotemResumeList *rlist, const char *name)
+{
+        g_return_val_if_fail(rlist->records != NULL, 0);
+
+        struct TotemResumeListRecord *rec;
+
+        if ((rec = g_tree_lookup(rlist->records, name)) != NULL)
+                return rec->time;
+
+        return 0;
+}
+
+void
+totem_resume_list_save(TotemResumeList* rlist, const char* filename,
+                       GError **error)
+{
+        g_return_if_fail(rlist->records != NULL);
+
+        gchar* cbuf;
+        /* prepare content */
+        GString *buffer = g_string_new(
+                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+                "<resumelist>\n");
+
+        g_tree_foreach(rlist->records, record_dump, buffer);
+        g_string_append(buffer, "</resumelist>");
+
+        cbuf = g_string_free(buffer, FALSE);
+
+        /* save content */
+        g_file_set_contents(filename, cbuf, -1, error);
+        g_free(cbuf);
+}
+
+static void
+record_parser_from_xml(GMarkupParseContext *context, const gchar *element_name,
+                       const gchar **attribute_names,
+                       const gchar **attribute_values, gpointer user_data,
+                       GError **error)
+{
+        TotemResumeList *rlist = (TotemResumeList*) user_data;
+
+        g_return_if_fail(rlist != NULL);
+        g_return_if_fail(rlist->records != NULL);
+
+        /* parse file entry */
+        if (strcmp(element_name, "file") == 0) {
+                char* path = NULL;
+                time_t mtime = 0;
+                gint64 time = 0;
+
+                int i;
+                for (i = 0; attribute_names[i]; i++) {
+                        if (strcmp(attribute_names[i], "path") == 0) {
+                                path = strdup(attribute_values[i]);
+                        } else if (strcmp(attribute_names[i], "time") == 0) {
+                                sscanf(attribute_values[i], "%lu", &time);
+                        } else if (strcmp(attribute_names[i], "mtime") == 0) {
+                                sscanf(attribute_values[i], "%lu", &mtime);
+                        }
+                }
+
+                /* load records with non empty path and non zero time */
+                if (path != NULL && time != 0)
+                        totem_resume_list_insert_ext(rlist, path, time, mtime);
+        }
+}
+
+static void
+on_error(GMarkupParseContext *context, GError *error, gpointer user_data)
+{
+        /* do nothing */
+}
+
+void
+totem_resume_list_load(TotemResumeList* rlist, const char* filename,
+                       GError **error)
+{
+        g_return_if_fail(rlist->records!=NULL);
+
+        GMarkupParser parser;
+        GMarkupParseContext *context;
+
+        char* content = NULL;
+        size_t size;
+
+        bzero(&parser, sizeof(GMarkupParser));
+
+        parser.start_element = record_parser_from_xml;
+        parser.error = on_error;
+
+        if (g_file_get_contents(filename, &content, &size, error) == FALSE) {
+                return;
+        }
+
+        context = g_markup_parse_context_new(&parser, 0, rlist, NULL);
+        g_markup_parse_context_parse(context, content, -1, error);
+        g_markup_parse_context_free(context);
+        g_free(content);
+}
+
+void
+totem_resume_list_remove(TotemResumeList *rlist, const char* name)
+{
+        g_return_if_fail(rlist->records != NULL);
+
+        g_tree_remove(rlist->records, name);
+}
+
+static gboolean
+record_filter_mtime(gpointer key, gpointer value, gpointer data)
+{
+        char *name = (char*) key;
+        struct TotemResumeListRecord* rec =
+                        (struct TotemResumeListRecord*) value;
+
+        GPtrArray *arr = (GPtrArray*) data;
+        time_t mtime = *((time_t*) g_ptr_array_index(arr, 1));
+
+        if (mtime > rec->mtime) {
+                TotemResumeList *rlist = (TotemResumeList*) g_ptr_array_index(arr, 0);
+                g_tree_remove(rlist->records, name);
+        }
+
+        return FALSE;
+}
+
+void
+totem_resume_list_filter(TotemResumeList *rlist, time_t mtime)
+{
+        g_return_if_fail(rlist->records != NULL);
+
+        GPtrArray *arr;
+
+        arr = g_ptr_array_new();
+
+        g_ptr_array_add(arr, rlist);
+        g_ptr_array_add(arr, &mtime);
+
+        g_tree_foreach(rlist->records, record_filter_mtime, arr);
+
+        g_ptr_array_free(arr, FALSE);
+}
diff --git a/src/plugins/resume-playback/totem-resume-list.h b/src/plugins/resume-playback/totem-resume-list.h
new file mode 100644
index 0000000..9b6f4e8
--- /dev/null
+++ b/src/plugins/resume-playback/totem-resume-list.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2009 Iliya Grushevskiy <iliya@1kab.ru>
+ *
+ * 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.
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission are above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add exception clause.
+ * See license_change file for details.
+ */
+
+#ifndef __TOTEM_RESUME_LIST_H__
+#define __TOTEM_RESUME_LIST_H__
+
+#include "config.h"
+#include "totem-plugin.h"
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define TOTEM_TYPE_RESUME_LIST          (totem_resume_list_get_type())
+#define TOTEM_RESUME_LIST(o)            (G_TYPE_CHECK_INSTANCE_CAST((o), TOTEM_TYPE_RESUME_LIST, TotemResumeList))
+#define TOTEM_RESUME_LIST_CLASS(k)      (G_TYPE_CHECK_CLASS_CAST((k), TOTEM_TYPE_RESUME_LIST, TotemResumeList))
+#define TOTEM_IS_RESUME_LIST(o)         (G_TYPE_CHECK_INSTANCE_TYPE((o), TOTEM_TYPE_RESUME_LIST))
+#define TOTEM_IS_RESUME_LIST_CLASS(k)   (G_TYPE_CHECK_CLASS_TYPE((k), TOTEM_TYPE_RESUME_LIST))
+#define TOTEM_RESUME_LIST_GET_CLASS(o)  (G_TYPE_INSTANCE_GET_CLASS((o), TOTEM_TYPE_RESUME_LIST, TotemResumeList))
+
+typedef struct TotemResumeList TotemResumeList;
+typedef struct TotemResumeListClass TotemResumeListClass;
+
+struct TotemResumeList
+{
+        GObject parent;
+        GTree *records;
+};
+
+struct TotemResumeListClass
+{
+        GObjectClass parent_class;
+};
+
+GType totem_resume_list_register_type (GTypeModule*);
+GType totem_resume_list_get_type ();
+
+void totem_resume_list_filter (TotemResumeList*, time_t);
+void totem_resume_list_free (TotemResumeList*);
+void totem_resume_list_insert_ext (TotemResumeList *,const char*, gint64, time_t);
+#define totem_resume_list_insert(list,name,vtime)       (totem_resume_list_insert_ext((list),(name),(vtime),time(NULL)))
+void totem_resume_list_load (TotemResumeList*, const char*, GError**);
+gint64 totem_resume_list_lookup(TotemResumeList*, const char*);
+TotemResumeList* totem_resume_list_new();
+void totem_resume_list_remove(TotemResumeList*, const char*);
+void totem_resume_list_save(TotemResumeList*, const char*, GError**);
+
+G_END_DECLS
+
+#endif /* __TOTEM_RESUME_LIST_H__ */
diff --git a/src/plugins/resume-playback/totem-resume-playback-plugin.c b/src/plugins/resume-playback/totem-resume-playback-plugin.c
new file mode 100644
index 0000000..2acc8b6
--- /dev/null
+++ b/src/plugins/resume-playback/totem-resume-playback-plugin.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2009 Iliya Grushevskiy <iliya@1kab.ru>
+ *
+ * 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.
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission are above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add exception clause.
+ * See license_change file for details.
+ */
+
+#include "totem-resume-playback-plugin.h"
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <gconf/gconf-value.h>
+
+#include "totem.h"
+#include "totem-options.h"
+#include "totem-uri.h"
+
+#define TOTEM_RESUME_PLAYBACK_DB_FILE                         "resume-playback.xml"
+
+#define TOTEM_RESUME_PLAYBACK_CONF_PREFIX                     GCONF_PREFIX "/plugins/resume-playback"
+#define TOTEM_RESUME_PLAYBACK_CONF_GC                         TOTEM_RESUME_PLAYBACK_CONF_PREFIX"/gc"
+#define TOTEM_RESUME_PLAYBACK_CONF_SKIP_BACK                  TOTEM_RESUME_PLAYBACK_CONF_PREFIX"/skip-back"
+#define TOTEM_RESUME_PLAYBACK_CONF_NOTIFY                     TOTEM_RESUME_PLAYBACK_CONF_PREFIX"/notify"
+
+struct TotemResumePlaybackPluginPrivate
+{
+        /* current mrl*/
+        char* cmrl;
+
+        /* time value */
+        gint64 time;
+
+        /* open flag */
+        gboolean open;
+
+        /* options */
+        gboolean notify;
+
+        guint gc;
+        gint64 skip_back;
+
+        /* list of stored time */
+        GTree* times;
+
+        /* handler id */
+        guint handler_id_state;
+        guint handler_id_opened;
+        guint handler_id_closed;
+        guint handler_id_seekable;
+        guint gconf_id;
+
+        /* resume list */
+        TotemResumeList *rlist;
+};
+
+TOTEM_PLUGIN_REGISTER_EXTENDED(TotemResumePlaybackPlugin, totem_resume_playback_plugin, TOTEM_PLUGIN_REGISTER_TYPE(totem_resume_list))
+
+static gboolean impl_activate(TotemPlugin*, TotemObject*, GError**);
+static void impl_deactivate(TotemPlugin*, TotemObject*);
+static GtkWidget* impl_config(TotemPlugin*);
+
+static void file_open_callback(Totem *, const char*, TotemResumePlaybackPlugin *);
+static void file_close_callback(Totem *, TotemResumePlaybackPlugin *);
+static void playback_state_callback(TotemObject*, GParamSpec*, TotemResumePlaybackPlugin*);
+
+static void start_watch_playback(Totem* totem, TotemResumePlaybackPlugin *plugin);
+static void stop_watch_playback(Totem* totem, TotemResumePlaybackPlugin *plugin);
+
+static void update_resume_info(Totem* totem, TotemResumePlaybackPlugin *plugin);
+static void save_resume_info(TotemResumePlaybackPlugin *plugin);
+
+
+static void
+totem_resume_playback_plugin_dispose(GObject* object)
+{
+        TotemResumePlaybackPlugin *plugin =
+                        TOTEM_RESUME_PLAYBACK_PLUGIN(object);
+        TotemResumePlaybackPluginPrivate *priv = plugin->private;
+
+        if (priv->rlist != NULL) {
+                totem_resume_list_free(priv->rlist);
+                priv->rlist = NULL;
+        }
+
+        G_OBJECT_CLASS(totem_resume_playback_plugin_parent_class)->dispose(object);
+}
+
+static void
+totem_resume_playback_plugin_class_init(TotemResumePlaybackPluginClass *klass)
+{
+        TotemPluginClass *plugin_class = TOTEM_PLUGIN_CLASS(klass);
+        GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+        g_type_class_add_private(plugin_class,
+                        sizeof(TotemResumePlaybackPluginPrivate));
+
+        plugin_class->activate = impl_activate;
+        plugin_class->deactivate = impl_deactivate;
+        plugin_class->create_configure_dialog = impl_config;
+        object_class->dispose = totem_resume_playback_plugin_dispose;
+}
+
+
+static void
+totem_resume_playback_plugin_init(TotemResumePlaybackPlugin* plugin)
+{
+        TotemResumePlaybackPluginPrivate *priv;
+
+        priv = plugin->private = G_TYPE_INSTANCE_GET_PRIVATE(plugin,
+                        TOTEM_TYPE_RESUME_PLAYBACK_PLUGIN,
+                        TotemResumePlaybackPluginPrivate);
+
+        priv->cmrl = NULL;
+        priv->time = 0;
+        priv->open = FALSE;
+
+        priv->rlist = totem_resume_list_new();
+}
+
+
+static void
+config_dialog_close(GtkDialog* dialog, gint response_id, void* userdata)
+{
+
+        g_return_if_fail(userdata != NULL);
+
+        if(response_id != GTK_RESPONSE_CLOSE)
+                return;
+
+#define SHIFT_ARG      g_ptr_array_index(arr, i++)
+
+        int i=0;
+        GPtrArray* arr = (GPtrArray*)userdata;
+        GConfClient *client = gconf_client_get_default();
+        GtkWidget *skip_back, *gc, *notify;
+
+        skip_back = GTK_WIDGET(SHIFT_ARG);
+        gc = GTK_WIDGET(SHIFT_ARG);
+        notify = GTK_WIDGET(SHIFT_ARG);
+
+#undef SHIFT_ARG
+
+        /* updating config */
+        gconf_client_set_int(client,
+                             TOTEM_RESUME_PLAYBACK_CONF_SKIP_BACK,
+                             gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(skip_back)),
+                             NULL);
+        gconf_client_set_int(client,
+                             TOTEM_RESUME_PLAYBACK_CONF_GC,
+                             gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gc))*86400,
+                             NULL);
+        gconf_client_set_bool(client,
+                              TOTEM_RESUME_PLAYBACK_CONF_NOTIFY,
+                              gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(notify)),
+                              NULL);
+
+        gtk_widget_destroy(GTK_WIDGET(dialog));
+        g_object_unref(client);
+        g_ptr_array_free(arr, FALSE);
+}
+
+static GtkWidget*
+impl_config(TotemPlugin* plugin)
+{
+        TotemResumePlaybackPlugin *pi = TOTEM_RESUME_PLAYBACK_PLUGIN(plugin);
+        TotemResumePlaybackPluginPrivate *priv = pi->private;
+
+        GPtrArray *arr = g_ptr_array_new();
+        GtkBuilder *xml;
+        GtkWidget *dlg;
+
+        xml = totem_plugin_load_interface(plugin,
+                        "resume-playback.ui", TRUE, NULL, pi);
+
+        g_return_val_if_fail(xml != NULL, NULL);
+
+#define UI_WIDGET(name)    (gtk_builder_get_object(xml, (name)))
+
+
+        /* configuring dialog */
+        dlg = GTK_WIDGET(UI_WIDGET("trp_dlg"));
+        gtk_window_set_title(GTK_WINDOW(dlg), _("Resume playback configuration"));
+        gtk_dialog_add_button(GTK_DIALOG(dlg), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
+
+        /* skip back */
+        gtk_spin_button_set_value(GTK_SPIN_BUTTON(UI_WIDGET("skip_back")), priv->skip_back);
+        g_ptr_array_add(arr, UI_WIDGET("skip_back"));
+
+        /* gc */
+        gtk_spin_button_set_value(GTK_SPIN_BUTTON(UI_WIDGET("gc")), (int)priv->gc/86400);
+        g_ptr_array_add(arr, UI_WIDGET("gc"));
+
+        /* notify */
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(UI_WIDGET("notify")), priv->notify);
+        g_ptr_array_add(arr, UI_WIDGET("notify"));
+
+#undef UI_WIDGET
+
+        g_signal_connect(dlg, "response", G_CALLBACK(config_dialog_close), arr);
+
+        g_object_unref(xml);
+        return dlg;
+}
+
+
+static void
+config_changed(GConfClient *client, guint cnid, GConfEntry *entry, TotemResumePlaybackPlugin *plugin)
+{
+        g_return_if_fail(plugin != NULL);
+        g_return_if_fail(plugin->private != NULL);
+
+        const char* key = gconf_entry_get_key(entry);
+        TotemResumePlaybackPluginPrivate *priv = plugin->private;
+
+        if(strcmp(key, TOTEM_RESUME_PLAYBACK_CONF_NOTIFY)==0){
+                priv->notify = gconf_value_get_bool(gconf_entry_get_value(entry));
+        } else if(strcmp(key, TOTEM_RESUME_PLAYBACK_CONF_GC)==0) {
+                priv->gc = gconf_value_get_int(gconf_entry_get_value(entry));
+        } else if(strcmp(key, TOTEM_RESUME_PLAYBACK_CONF_SKIP_BACK)==0) {
+                priv->skip_back = gconf_value_get_int(gconf_entry_get_value(entry));
+        }
+}
+
+static void
+config_load(GConfClient *client, TotemResumePlaybackPlugin *plugin)
+{
+        g_return_if_fail(plugin != NULL);
+        g_return_if_fail(plugin->private != NULL);
+
+        TotemResumePlaybackPluginPrivate *priv = plugin->private;
+
+        priv->notify = FALSE;
+        priv->skip_back = 0;
+        priv->gc = 7*86400;
+
+        GSList *list, *cur;
+        cur = list = gconf_client_all_entries(client, TOTEM_RESUME_PLAYBACK_CONF_PREFIX, NULL);
+
+        for(;cur!=NULL;cur = g_slist_next(cur)) {
+                config_changed(client, priv->gconf_id, (GConfEntry*)cur->data, plugin);
+                gconf_entry_unref((GConfEntry*)cur->data);
+        }
+
+        g_slist_free(list);
+}
+
+
+
+static gboolean
+impl_activate(TotemPlugin* plugin, TotemObject* totem, GError** error)
+{
+        TotemResumePlaybackPlugin *pi = TOTEM_RESUME_PLAYBACK_PLUGIN(plugin);
+        TotemResumePlaybackPluginPrivate *priv = pi->private;
+        TotemResumeList *rlist = priv->rlist;
+        GConfClient *conf = gconf_client_get_default();
+        char *db_file_path;
+
+        /* file open handler */
+        priv->handler_id_opened = g_signal_connect(G_OBJECT(totem),
+                        "file-opened",
+                        G_CALLBACK(file_open_callback),
+                        plugin);
+
+        /* file close handler */
+        priv->handler_id_closed = g_signal_connect(G_OBJECT(totem),
+                        "file-closed",
+                        G_CALLBACK(file_close_callback),
+                        plugin);
+
+        /* seekable property handler */
+        priv->handler_id_seekable = g_signal_connect(G_OBJECT(totem),
+                        "notify::seekable",
+                        G_CALLBACK(playback_state_callback),
+                        plugin);
+
+        /* play/stop handler */
+        priv->handler_id_state = g_signal_connect(G_OBJECT(totem),
+                        "notify::playing",
+                        G_CALLBACK(playback_state_callback),
+                        plugin);
+
+        /* loading configuration */
+        gconf_client_add_dir(conf,
+                             TOTEM_RESUME_PLAYBACK_CONF_PREFIX,
+                             GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+
+        priv->gconf_id = gconf_client_notify_add(conf,
+                                TOTEM_RESUME_PLAYBACK_CONF_PREFIX,
+                                config_changed,
+                                pi, NULL, NULL);
+        config_load(conf, pi);
+
+        /* loading resume info */
+        db_file_path = g_build_filename(totem_data_dot_dir(),
+                        TOTEM_RESUME_PLAYBACK_DB_FILE, NULL);
+
+        totem_resume_list_load(rlist, db_file_path, NULL);
+        g_free(db_file_path);
+
+        /* filtering old records */
+        totem_resume_list_filter(rlist,
+                                 time(NULL) - priv->gc);
+
+        /* start watch playback */
+        start_watch_playback(totem, pi);
+
+
+        g_object_unref(conf);
+        return TRUE;
+}
+
+static void
+impl_deactivate(TotemPlugin* plugin, TotemObject* totem)
+{
+        TotemResumePlaybackPlugin *pi = TOTEM_RESUME_PLAYBACK_PLUGIN(plugin);
+        TotemResumePlaybackPluginPrivate *priv = pi->private;
+        TotemResumeList *rlist = priv->rlist;
+        char *db_file_path;
+        GConfClient *conf  = gconf_client_get_default();
+
+        g_return_if_fail(rlist != NULL);
+
+        /* retrieving playback info and stop watch video*/
+        update_resume_info(totem, pi);
+        save_resume_info(pi);
+        stop_watch_playback(totem, pi);
+
+        g_signal_handler_disconnect(totem, priv->handler_id_opened);
+        g_signal_handler_disconnect(totem, priv->handler_id_closed);
+        g_signal_handler_disconnect(totem, priv->handler_id_seekable);
+        g_signal_handler_disconnect(totem, priv->handler_id_state);
+
+        gconf_client_notify_remove(conf, priv->gconf_id);
+
+
+        /* filtering old records */
+        totem_resume_list_filter(rlist,
+                                 time(NULL) - priv->gc);
+
+        /* save resume list */
+        db_file_path = g_build_filename(totem_data_dot_dir(),
+                                TOTEM_RESUME_PLAYBACK_DB_FILE, NULL);
+
+        totem_resume_list_save(rlist, db_file_path, NULL);
+
+        g_free(db_file_path);
+        g_object_unref(conf);
+}
+
+static void
+file_open_callback(Totem *totem, const char* mrl,
+                   TotemResumePlaybackPlugin *plugin)
+{
+        start_watch_playback(totem, plugin);
+}
+
+static void
+file_close_callback(Totem *totem,
+                    TotemResumePlaybackPlugin *plugin)
+{
+        save_resume_info(plugin);
+        stop_watch_playback(totem, plugin);
+}
+
+static void
+start_watch_playback(Totem* totem,
+                     TotemResumePlaybackPlugin *plugin)
+{
+        TotemResumePlaybackPluginPrivate *priv = plugin->private;
+
+        g_return_if_fail(totem != NULL);
+        g_return_if_fail(priv != NULL);
+
+        char* mrl = totem_get_current_mrl(totem);
+
+        if (!totem_is_special_mrl(mrl) && !totem_playing_dvd(mrl)) {
+                priv->cmrl = mrl;
+                priv->open = TRUE;
+        } else {
+                g_free(mrl);
+                priv->cmrl = NULL;
+                priv->open = FALSE;
+        }
+}
+
+static void
+stop_watch_playback(Totem* totem,
+                    TotemResumePlaybackPlugin *plugin)
+{
+        TotemResumePlaybackPluginPrivate *priv = plugin->private;
+
+        g_return_if_fail(totem != NULL);
+        g_return_if_fail(priv != NULL);
+
+        /* check state */
+        if (priv->cmrl == NULL)
+                return;
+
+        g_free(priv->cmrl);
+        priv->cmrl = NULL;
+        priv->open = FALSE;
+
+}
+
+static void
+update_resume_info(Totem* totem,
+                   TotemResumePlaybackPlugin *plugin)
+{
+        TotemResumePlaybackPluginPrivate *priv = plugin->private;
+
+        g_return_if_fail(totem != NULL);
+        g_return_if_fail(priv != NULL);
+
+        /* check state */
+        if (priv->cmrl == NULL)
+                return;
+
+        priv->time = totem_get_current_time(totem);
+}
+
+static void
+save_resume_info(TotemResumePlaybackPlugin *plugin)
+{
+        g_return_if_fail(plugin->private != NULL);
+
+        TotemResumePlaybackPluginPrivate *priv = plugin->private;
+
+        /* check state */
+        if (priv->cmrl == NULL)
+                return;
+
+        TotemResumeList *rlist = priv->rlist;
+        if(priv->time!=0)
+                totem_resume_list_insert(rlist, priv->cmrl, priv->time);
+        else
+                totem_resume_list_remove(rlist, priv->cmrl);
+}
+
+static void
+playback_state_callback(TotemObject* totem, GParamSpec* spec,
+                        TotemResumePlaybackPlugin* plugin)
+{
+
+        g_return_if_fail(totem != NULL);
+        g_return_if_fail(plugin->private != NULL);
+        g_return_if_fail(plugin->private->rlist != NULL);
+
+        TotemResumePlaybackPluginPrivate *priv = plugin->private;
+        TotemResumeList *rlist = priv->rlist;
+
+        /* check state */
+        if (priv->cmrl == NULL)
+                return;
+
+        gint64 time = totem_get_current_time(totem);
+
+        if (priv->open) {
+
+                if (totem_resume_list_lookup(rlist, priv->cmrl) <= priv->skip_back || time
+                                != 0 || !totem_is_playing(totem))
+                {
+                        priv->open = FALSE;
+                } else if (totem_is_seekable(totem)) {
+                        gint64 seek_to = totem_resume_list_lookup(rlist, priv->cmrl) - priv->skip_back*1000;
+                        priv->open = FALSE;
+
+                        if(priv->notify) {
+                                GtkMessageDialog *dialog = gtk_message_dialog_new(NULL,
+                                                                          GTK_DIALOG_MODAL,
+                                                                          GTK_MESSAGE_QUESTION,
+                                                                          GTK_BUTTONS_YES_NO,
+                                                                          _("Do you want to resume playing?")
+                                                                          );
+
+                                if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) {
+                                        totem_action_seek_time(totem, seek_to);
+                                }
+
+                                gtk_widget_destroy(GTK_WIDGET(dialog));
+
+                        } else {
+                                totem_action_seek_time(totem, seek_to);
+                        }
+
+                }
+        } else
+                update_resume_info(totem, plugin);
+}
diff --git a/src/plugins/resume-playback/totem-resume-playback-plugin.h b/src/plugins/resume-playback/totem-resume-playback-plugin.h
new file mode 100644
index 0000000..56d362a
--- /dev/null
+++ b/src/plugins/resume-playback/totem-resume-playback-plugin.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2009 Iliya Grushevskiy <iliya@1kab.ru>
+ *
+ * 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.
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission are above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add exception clause.
+ * See license_change file for details.
+ */
+
+#ifndef __TOTEM_RESUME_PLAYBACK_PLUGIN_H__
+#define __TOTEM_RESUME_PLAYBACK_PLUGIN_H__
+
+#include "config.h"
+
+#include "totem-plugin.h"
+#include "totem-resume-list.h"
+
+G_BEGIN_DECLS
+
+#define TOTEM_TYPE_RESUME_PLAYBACK_PLUGIN               (totem_resume_playback_plugin_get_type())
+#define TOTEM_RESUME_PLAYBACK_PLUGIN(o)                 (G_TYPE_CHECK_INSTANCE_CAST((o), TOTEM_TYPE_RESUME_PLAYBACK_PLUGIN, TotemResumePlaybackPlugin))
+#define TOTEM_RESUME_PLAYBACK_PLUGIN_CLASS(k)           (G_TYPE_CHECK_CLASS_CAST((k), TOTEM_TYPE_RESUME_PLAYBACK_PLUGIN, TotemResumePlaybackPluginClass))
+#define TOTEM_IS_RESUME_PLAYBACK_PLUGIN(o)              (G_TYPE_CHECK_INSTANCE_TYPE((o), TOTEM_TYPE_RESUME_PLAYBACK_PLUGIN))
+#define TOTEM_IS_RESUME_PLAYBACK_PLUGIN_CLASS(k)        (G_TYPE_CHECK_CLASS_TYPE()((k), TOTEM_TYPE_RESUME_PLAYBACK_PLUGIN))
+#define TOTEM_RESUME_PLAYBACK_PLUGIN_GET_CLASS(o)       (G_TYPE_INSTANCE_GET_CLASS((o), TOTEM_TYPE_RESUME_PLAYBACK_PLUGIN, TotemResumePlaybackPluginClass))
+
+typedef struct TotemResumePlaybackPlugin TotemResumePlaybackPlugin;
+typedef struct TotemResumePlaybackPluginClass TotemResumePlaybackPluginClass;
+typedef struct TotemResumePlaybackPluginPrivate TotemResumePlaybackPluginPrivate;
+
+struct TotemResumePlaybackPlugin
+{
+        TotemPlugin parent;
+        TotemResumePlaybackPluginPrivate *private;
+};
+
+struct TotemResumePlaybackPluginClass
+{
+        TotemPluginClass parent_class;
+};
+
+G_MODULE_EXPORT GType register_totem_plugin(GTypeModule *module);
+G_MODULE_EXPORT GType totem_resume_playback_plugin_get_type(void);
+
+G_END_DECLS
+
+#endif /* __TOTEM_RESUME_PLAYBACK_PLUGIN_H__ */
