Updated package version
[lms] / lightmediascanner / src / lib / lightmediascanner_db_video.c
1 /**
2  * Copyright (C) 2007 by INdT
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  * @author Gustavo Sverzut Barbieri <gustavo.barbieri@openbossa.org>
19  */
20
21 #include <lightmediascanner_db.h>
22 #include "lightmediascanner_db_private.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25
26 struct lms_db_video {
27     sqlite3 *db;
28     sqlite3_stmt *insert;
29     unsigned int _references;
30     unsigned int _is_started:1;
31 };
32
33 static struct lms_db_cache _cache = {0, NULL};
34
35 static int
36 _db_table_updater_videos_0(sqlite3 *db, const char *table, unsigned int current_version, int is_last_run) {
37     char *errmsg;
38     int r, ret;
39
40     errmsg = NULL;
41     r = sqlite3_exec(db,
42                      "CREATE TABLE IF NOT EXISTS videos ("
43                      "id INTEGER PRIMARY KEY, "
44                      "title TEXT, "
45                      "artist TEXT"
46                      ")",
47                      NULL, NULL, &errmsg);
48     if (r != SQLITE_OK) {
49         fprintf(stderr, "ERROR: could not create 'videos' table: %s\n", errmsg);
50         sqlite3_free(errmsg);
51         return -1;
52     }
53
54     r = sqlite3_exec(db,
55                      "CREATE INDEX IF NOT EXISTS videos_title_idx ON videos ("
56                      "title"
57                      ")",
58                      NULL, NULL, &errmsg);
59     if (r != SQLITE_OK) {
60         fprintf(stderr,
61                 "ERROR: could not create 'videos_title_idx' index: %s\n",
62                 errmsg);
63         sqlite3_free(errmsg);
64         return -2;
65     }
66
67     r = sqlite3_exec(db,
68                      "CREATE INDEX IF NOT EXISTS videos_artist_idx ON videos ("
69                      "artist"
70                      ")",
71                      NULL, NULL, &errmsg);
72     if (r != SQLITE_OK) {
73         fprintf(stderr,
74                 "ERROR: could not create 'videos_artist_idx' index: %s\n",
75                 errmsg);
76         sqlite3_free(errmsg);
77         return -3;
78     }
79
80     ret = lms_db_create_trigger_if_not_exists(db,
81         "delete_videos_on_files_deleted "
82         "DELETE ON files FOR EACH ROW BEGIN "
83         " DELETE FROM videos WHERE id = OLD.id; END;");
84     if (ret != 0)
85         goto done;
86
87     ret = lms_db_create_trigger_if_not_exists(db,
88         "delete_files_on_videos_deleted "
89         "DELETE ON videos FOR EACH ROW BEGIN "
90         " DELETE FROM files WHERE id = OLD.id; END;");
91
92   done:
93     return ret;
94 }
95
96 static lms_db_table_updater_t _db_table_updater_videos[] = {
97     _db_table_updater_videos_0
98 };
99
100
101 static int
102 _db_create_table_if_required(sqlite3 *db)
103 {
104     return lms_db_table_update_if_required(db, "videos",
105          LMS_ARRAY_SIZE(_db_table_updater_videos),
106          _db_table_updater_videos);
107 }
108
109 /**
110  * Create video DB access tool.
111  *
112  * Creates or get a reference to tools to access 'videos' table in an
113  * optimized and easy way.
114  *
115  * This is usually called from plugin's @b setup() callback with the @p db
116  * got from @c ctxt.
117  *
118  * @param db database connection.
119  *
120  * @return DB access tool handle.
121  * @ingroup LMS_Plugins
122  */
123 lms_db_video_t *
124 lms_db_video_new(sqlite3 *db)
125 {
126     lms_db_video_t *ldv;
127     void *p;
128
129     if (lms_db_cache_get(&_cache, db, &p) == 0) {
130         ldv = p;
131         ldv->_references++;
132         return ldv;
133     }
134
135     if (!db)
136         return NULL;
137
138     if (_db_create_table_if_required(db) != 0) {
139         fprintf(stderr, "ERROR: could not create table.\n");
140         return NULL;
141     }
142
143     ldv = calloc(1, sizeof(lms_db_video_t));
144     ldv->_references = 1;
145     ldv->db = db;
146
147     if (lms_db_cache_add(&_cache, db, ldv) != 0) {
148         lms_db_video_free(ldv);
149         return NULL;
150     }
151
152     return ldv;
153 }
154
155 /**
156  * Start video DB access tool.
157  *
158  * Compile SQL statements and other initialization functions.
159  *
160  * This is usually called from plugin's @b start() callback.
161  *
162  * @param ldv handle returned by lms_db_video_new().
163  *
164  * @return On success 0 is returned.
165  * @ingroup LMS_Plugins
166  */
167 int
168 lms_db_video_start(lms_db_video_t *ldv)
169 {
170     if (!ldv)
171         return -1;
172     if (ldv->_is_started)
173         return 0;
174
175     ldv->insert = lms_db_compile_stmt(ldv->db,
176         "INSERT OR REPLACE INTO videos (id, title, artist) VALUES (?, ?, ?)");
177     if (!ldv->insert)
178         return -2;
179
180     ldv->_is_started = 1;
181     return 0;
182 }
183
184 /**
185  * Free video DB access tool.
186  *
187  * Unreference and possible free resources allocated to access tool.
188  *
189  * This is usually called from plugin's @b finish() callback.
190  *
191  * @param ldv handle returned by lms_db_video_new().
192  *
193  * @return On success 0 is returned.
194  * @ingroup LMS_Plugins
195  */
196 int
197 lms_db_video_free(lms_db_video_t *ldv)
198 {
199     int r;
200
201     if (!ldv)
202         return -1;
203     if (ldv->_references == 0) {
204         fprintf(stderr, "ERROR: over-called lms_db_video_free(%p)\n", ldv);
205         return -1;
206     }
207
208     ldv->_references--;
209     if (ldv->_references > 0)
210         return 0;
211
212     if (ldv->insert)
213         lms_db_finalize_stmt(ldv->insert, "insert");
214
215     r = lms_db_cache_del(&_cache, ldv->db, ldv);
216     free(ldv);
217
218     return r;
219 }
220
221 static int
222 _db_insert(lms_db_video_t *ldv, const struct lms_video_info *info)
223 {
224     sqlite3_stmt *stmt;
225     int r, ret;
226
227     stmt = ldv->insert;
228
229     ret = lms_db_bind_int64(stmt, 1, info->id);
230     if (ret != 0)
231         goto done;
232
233     ret = lms_db_bind_text(stmt, 2, info->title.str, info->title.len);
234     if (ret != 0)
235         goto done;
236
237     ret = lms_db_bind_text(stmt, 3, info->artist.str, info->artist.len);
238     if (ret != 0)
239         goto done;
240
241     r = sqlite3_step(stmt);
242     if (r != SQLITE_DONE) {
243         fprintf(stderr, "ERROR: could not insert video info: %s\n",
244                 sqlite3_errmsg(ldv->db));
245         ret = -4;
246         goto done;
247     }
248
249     ret = 0;
250
251   done:
252     lms_db_reset_stmt(stmt);
253
254     return ret;
255 }
256
257 /**
258  * Add video file to DB.
259  *
260  * This is usually called from plugin's @b parse() callback.
261  *
262  * @param ldv handle returned by lms_db_video_new().
263  * @param info video information to store.
264  *
265  * @return On success 0 is returned.
266  * @ingroup LMS_Plugins
267  */
268 int
269 lms_db_video_add(lms_db_video_t *ldv, struct lms_video_info *info)
270 {
271     if (!ldv)
272         return -1;
273     if (!info)
274         return -2;
275     if (info->id < 1)
276         return -3;
277
278     return _db_insert(ldv, info);
279 }