library refresh UI montor
[omnplay] / src / library.c
1 /*
2 * playlist.c -- GTK+ 2 omnplay
3 * Copyright (C) 2011 Maksym Veremeyenko <verem@m1stereo.tv>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <gtk/gtk.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <pthread.h>
30
31 #include "omnplay.h"
32 #include "ui.h"
33 #include "timecode.h"
34
35 playlist_item_t* omnplay_library_find(omnplay_instance_t* app, char* id)
36 {
37 int i;
38 playlist_item_t* item = NULL;
39
40 pthread_mutex_lock(&app->library.lock);
41
42 for(i = 0; i < app->library.count && !item; i++)
43 if(!strcasecmp(id, app->library.item[i].id))
44 item = &app->library.item[i];
45
46 pthread_mutex_unlock(&app->library.lock);
47
48 return item;
49 };
50
51 int omnplay_library_normalize_item(omnplay_instance_t* app, playlist_item_t* item)
52 {
53 int r = 0;
54 playlist_item_t* lib;
55
56 pthread_mutex_lock(&app->library.lock);
57
58 lib = omnplay_library_find(app, item->id);
59
60 item->error = 0;
61
62 if(lib)
63 {
64
65 if(!item->title[0])
66 {
67 strcpy(item->title, lib->title);
68 r = 1;
69 };
70
71 if(!item->dur || item->in < lib->in || (item->in + item->dur) > (lib->in + lib->dur))
72 {
73 item->dur = lib->dur;
74 item->in = lib->in;
75 r = 1;
76 };
77 }
78 else
79 {
80 r = 1;
81 item->error = PLAYLIST_ITEM_ERROR_LIB;
82 };
83
84 pthread_mutex_unlock(&app->library.lock);
85
86 return r;
87 };
88
89 void omnplay_library_sort(omnplay_instance_t* app)
90 {
91 int i, j, m;
92 playlist_item_t item;
93
94 for(i = 0; i < app->library.count; i++)
95 {
96 /* find max */
97 for(j = i + 1, m = i; j < app->library.count; j++)
98 if(strcasecmp(app->library.item[j].id, app->library.item[m].id) < 0)
99 m = j;
100
101 if(m != i)
102 {
103 item = app->library.item[i];
104 app->library.item[i] = app->library.item[m];
105 app->library.item[m] = item;
106 };
107 };
108 };
109
110 int omnplay_library_load_file(playlist_item_t* items, int *pcount, char* filename)
111 {
112 int i, c = 0, r = 0;
113 FILE* f;
114 char *l;
115 int limit = *pcount;
116 playlist_item_t item;
117
118 /* allocate space for strings and items */
119 l = malloc(PATH_MAX);
120
121 *pcount = 0;
122
123 /* open and process file */
124 if((f = fopen(filename, "rt")))
125 {
126 while( !feof(f) && c < (limit -1))
127 {
128 char *s, *sp_r, *sp_b;
129
130 /* load string */
131 memset(l, 0, PATH_MAX);
132 fgets(l, PATH_MAX, f);
133
134 /* remove newlines */
135 if( (s = strchr(l, '\n')) ) *s = 0;
136 if( (s = strchr(l, '\r')) ) *s = 0;
137
138 /* check for empty line */
139 if(l[0] && l[0] != '#' && l[0] != '|')
140 {
141 memset(&item, 0, sizeof(playlist_item_t));
142
143 for(i = 0, sp_b = l; (NULL != (sp_r = strtok(sp_b, "\t"))); i++, sp_b = NULL)
144 {
145 switch(i)
146 {
147 case 0: strncpy(item.id, sp_r, PATH_MAX); break;
148 case 1: tc2frames(sp_r, 25.0, &item.in); break;
149 case 2: tc2frames(sp_r, 25.0, &item.dur); break;
150 case 3: strncpy(item.title, sp_r, PATH_MAX); break;
151 };
152 };
153
154 /* insert item */
155 items[c++] = item;
156 };
157 }
158
159 fclose(f);
160 }
161 else
162 r = -1;
163
164 /* free data */
165 free(l);
166
167 *pcount = c;
168
169 return r;
170 };
171
172 void omnplay_library_load(omnplay_instance_t* app)
173 {
174 pthread_mutex_lock(&app->library.lock);
175
176 if(app->library.filename[0])
177 {
178 app->library.count = MAX_LIBRARY_ITEMS;
179 omnplay_library_load_file(app->library.item, &app->library.count, app->library.filename);
180 };
181
182 omnplay_library_sort(app);
183
184 pthread_mutex_unlock(&app->library.lock);
185
186 omnplay_library_draw(app);
187 };
188
189 static void omnplay_library_save_file(playlist_item_t* item, int count, char* filename)
190 {
191 int i;
192 FILE* f;
193
194 if((f = fopen(filename, "wt")))
195 {
196 char tc_in[32], tc_dur[32];
197
198 for(i = 0; i < count; i++)
199 fprintf(f, "%s\t%s\t%s\t%s\n",
200 item[i].id,
201 frames2tc(item[i].in, 25.0, tc_in),
202 frames2tc(item[i].dur, 25.0, tc_dur),
203 item[i].title);
204
205 fclose(f);
206 };
207 };
208
209 void omnplay_library_save(omnplay_instance_t* app)
210 {
211 pthread_mutex_lock(&app->library.lock);
212
213 if(app->library.filename[0])
214 omnplay_library_save_file(app->library.item, app->library.count,
215 app->library.filename);
216
217 pthread_mutex_unlock(&app->library.lock);
218 };
219
220 static void omnplay_get_content_cb(omnplay_instance_t* app, playlist_item_t* item, void* data)
221 {
222 gdk_threads_enter();
223 gtk_label_set_text(GTK_LABEL(app->library.refresh_ui[1]), item->id);
224 gdk_flush();
225 gdk_threads_leave();
226 };
227
228 static void* omnplay_library_refresh_proc(void* data)
229 {
230 omnplay_instance_t* app = (omnplay_instance_t*)data;
231 int count, i;
232 playlist_item_t* items;
233
234 items = (playlist_item_t*)malloc(sizeof(playlist_item_t) * MAX_LIBRARY_ITEMS);
235
236 count = omnplay_get_content(app, items, MAX_LIBRARY_ITEMS, omnplay_get_content_cb, NULL);
237
238 if(count > 0)
239 {
240 gdk_threads_enter();
241 gtk_label_set_text(GTK_LABEL(app->library.refresh_ui[1]), "Quering whois...");
242 gdk_flush();
243 gdk_threads_leave();
244
245 if(app->library.whois[0])
246 omnplay_whois_list(app, items, &count);
247
248 pthread_mutex_lock(&app->library.lock);
249
250 for(i = 0; i < count; i++)
251 app->library.item[i] = items[i];
252
253 app->library.count = count;
254
255 omnplay_library_sort(app);
256
257 pthread_mutex_unlock(&app->library.lock);
258
259 gdk_threads_enter();
260 omnplay_library_draw(app);
261 gdk_flush();
262 gdk_threads_leave();
263 };
264
265 free(items);
266
267 gdk_threads_enter();
268 omnplay_playlist_normalize(app);
269 gtk_widget_destroy(app->library.refresh_ui[0]);
270 gdk_flush();
271 gdk_threads_leave();
272
273 return NULL;
274 };
275
276 void omnplay_library_refresh(omnplay_instance_t* app)
277 {
278 if(app->library.refresh_ui[0])
279 pthread_join(app->library.refresh_thread, NULL);
280
281 /* create UI for monitoring update */
282 ui_library_refresh(app, &app->library.refresh_ui[0], &app->library.refresh_ui[1]);
283
284 pthread_create(&app->library.refresh_thread, NULL,
285 omnplay_library_refresh_proc, app);
286
287 };
288
289 void omnplay_library_draw(omnplay_instance_t* app)
290 {
291 int i;
292 char tc[12];
293 GtkListStore *list_store;
294 GtkTreeIter iter;
295
296 list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(app->library_grid)));
297 gtk_list_store_clear(list_store);
298
299 pthread_mutex_lock(&app->library.lock);
300
301 for(i = 0;i < app->library.count; i++)
302 {
303 gtk_list_store_append(list_store, &iter);
304
305 gtk_list_store_set(list_store, &iter,
306 0, app->library.item[i].id,
307 1, frames2tc(app->library.item[i].dur, 25.0, tc),
308 2, app->library.item[i].title,
309 3, i,
310 4, FALSE,
311 5, "red",
312 -1 );
313 }
314
315 pthread_mutex_unlock(&app->library.lock);
316 };
317
318 static void get_selected_idx_library_proc(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
319 {
320 int idx, *list = (int*)data;
321 gtk_tree_model_get(model, iter, 3, &idx, -1);
322 list[list[0] + 1] = idx;
323 list[0] = list[0] + 1;
324 };
325
326 static int* get_selected_idx_library(omnplay_instance_t* app)
327 {
328 int* list = NULL;
329 GtkTreeSelection *selection;
330
331 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(app->library_grid));
332 if(selection)
333 {
334 list = (int*)malloc(sizeof(int) * (MAX_LIBRARY_ITEMS + 1));
335 memset(list, 0, sizeof(int) * (MAX_LIBRARY_ITEMS + 1));
336
337 gtk_tree_selection_selected_foreach(
338 selection,
339 get_selected_idx_library_proc,
340 list);
341
342 if(!list[0])
343 {
344 free(list);
345 list = NULL;
346 };
347 };
348
349 return list;
350 };
351
352
353 playlist_item_t* omnplay_library_get_selected(omnplay_instance_t* app, int *count)
354 {
355 int* idxs;
356 playlist_item_t* items = NULL;
357
358 pthread_mutex_lock(&app->library.lock);
359
360 *count = 0;
361
362 idxs = get_selected_idx_library(app);
363
364 if(idxs)
365 {
366 int i;
367
368 /* alloc items */
369 items = (playlist_item_t*)malloc(sizeof(playlist_item_t) * (idxs[0] + 1));
370
371 /* clear last item */
372 memset(&items[idxs[0]], 0, sizeof(playlist_item_t));
373
374 /* copy items */
375 for(i = 0; i < idxs[0]; i++)
376 items[i] = app->library.item[idxs[i + 1]];
377
378 *count = idxs[0];
379 free(idxs);
380 };
381
382 pthread_mutex_unlock(&app->library.lock);
383
384 return items;
385 };