2 * playlist.c -- GTK+ 2 omnplay
3 * Copyright (C) 2011 Maksym Veremeyenko <verem@m1stereo.tv>
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.
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.
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.
32 #include <gdk/gdkkeysyms.h>
40 playlist_item_t
* omnplay_library_find(omnplay_instance_t
* app
, char* id
)
43 playlist_item_t
* item
= NULL
;
45 pthread_mutex_lock(&app
->library
.lock
);
47 for(i
= 0; i
< app
->library
.count
&& !item
; i
++)
48 if(!strcasecmp(id
, app
->library
.item
[i
].id
))
49 item
= &app
->library
.item
[i
];
51 pthread_mutex_unlock(&app
->library
.lock
);
56 int omnplay_library_normalize_item(omnplay_instance_t
* app
, playlist_item_t
* item
)
62 pthread_mutex_lock(&app
->library
.lock
);
66 lib
= omnplay_library_find(app
, item
->id
);
74 strcpy(item
->title
, lib
->title
);
75 g_warning("%s: [%s] title=[%s]->[%s]", __FUNCTION__
, item
->id
, prev
.title
, item
->title
);
79 if(item
->in
< lib
->in
|| item
->in
>= (lib
->in
+ lib
->dur
))
81 g_warning("%s: [%s] (item->in=[%d] < lib->in=[%d] || item->in=[%d] >= (lib->in=[%d] + lib->dur=[%d]))",
82 __FUNCTION__
, item
->id
,
83 item
->in
, lib
->in
, item
->in
, lib
->in
, lib
->dur
);
87 g_warning("%s: [%s] in=[%d]->[%d]", __FUNCTION__
, item
->id
, prev
.in
, item
->in
);
92 if(!item
->dur
|| (item
->in
+ item
->dur
) > (lib
->in
+ lib
->dur
))
94 g_warning("%s: [%s] (!item->dur=[%d] || (item->in=[%d] + item->dur=[%d]) > (lib->in=[%d] + lib->dur=[%d])",
95 __FUNCTION__
, item
->id
,
96 item
->dur
, item
->in
, item
->dur
, lib
->in
, lib
->dur
);
98 item
->dur
= lib
->in
+ lib
->dur
- item
->in
;
100 g_warning("%s: [%s] dur=[%d]->[%d]", __FUNCTION__
, item
->id
, prev
.dur
, item
->dur
);
108 item
->error
= PLAYLIST_ITEM_ERROR_LIB
;
111 pthread_mutex_unlock(&app
->library
.lock
);
116 int omnplay_library_relink_item(omnplay_instance_t
* app
, playlist_item_t
* item
)
119 playlist_item_t
* lib
;
121 pthread_mutex_lock(&app
->library
.lock
);
123 lib
= omnplay_library_find(app
, item
->id
);
130 strcpy(item
->title
, lib
->title
);
131 item
->dur
= lib
->dur
;
137 item
->error
= PLAYLIST_ITEM_ERROR_LIB
;
140 pthread_mutex_unlock(&app
->library
.lock
);
145 void omnplay_library_sort(omnplay_instance_t
* app
)
148 playlist_item_t item
;
150 for(i
= 0; i
< app
->library
.count
; i
++)
153 for(j
= i
+ 1, m
= i
; j
< app
->library
.count
; j
++)
154 if(strcasecmp(app
->library
.item
[j
].id
, app
->library
.item
[m
].id
) < 0)
159 item
= app
->library
.item
[i
];
160 app
->library
.item
[i
] = app
->library
.item
[m
];
161 app
->library
.item
[m
] = item
;
166 int omnplay_library_load_file(playlist_item_t
* items
, int *pcount
, char* filename
)
172 playlist_item_t item
;
174 /* allocate space for strings and items */
175 l
= malloc(PATH_MAX
);
179 /* open and process file */
180 if((f
= fopen(filename
, "rt")))
182 while(!feof(f
) && c
< limit
)
184 char *s
, *sp_r
, *sp_b
;
187 memset(l
, 0, PATH_MAX
);
188 fgets(l
, PATH_MAX
, f
);
190 /* remove newlines */
191 if( (s
= strchr(l
, '\n')) ) *s
= 0;
192 if( (s
= strchr(l
, '\r')) ) *s
= 0;
194 /* check for empty line */
195 if(l
[0] && l
[0] != '#' && l
[0] != '|')
197 memset(&item
, 0, sizeof(playlist_item_t
));
199 g_warning("%s: [%s]", __FUNCTION__
, l
);
201 for(i
= 0, sp_b
= l
; (NULL
!= (sp_r
= strtok(sp_b
, "\t"))); i
++, sp_b
= NULL
)
203 g_warning("%s: [%d]=[%s]", __FUNCTION__
, i
, sp_r
);
207 case 0: strncpy(item
.id
, sp_r
, PATH_MAX
); break;
208 case 1: tc2frames(sp_r
, 25.0, &item
.in
); break;
209 case 2: tc2frames(sp_r
, 25.0, &item
.dur
); break;
210 case 3: strncpy(item
.title
, sp_r
, PATH_MAX
); break;
216 g_warning("%s: id=[%s], in=[%d], dur=[%d]", __FUNCTION__
, item
.id
, item
.in
, item
.dur
);
219 g_warning("omnplay_library_load_file: ignored line [%s]\n", l
);
232 g_warning("omnplay_library_load_file: loaded [%d] items from [%s] file, limit [%d]\n", c
, filename
, limit
);
237 void omnplay_library_load(omnplay_instance_t
* app
)
239 pthread_mutex_lock(&app
->library
.lock
);
241 if(app
->library
.filename
[0])
243 app
->library
.count
= MAX_LIBRARY_ITEMS
;
244 omnplay_library_load_file(app
->library
.item
, &app
->library
.count
, app
->library
.filename
);
247 omnplay_library_sort(app
);
249 pthread_mutex_unlock(&app
->library
.lock
);
251 omnplay_library_draw(app
);
254 static void omnplay_library_save_file(playlist_item_t
* item
, int count
, char* filename
)
259 if((f
= fopen(filename
, "wt")))
261 char tc_in
[32], tc_dur
[32];
263 for(i
= 0; i
< count
; i
++)
264 fprintf(f
, "%s\t%s\t%s\t%s\n",
266 frames2tc(item
[i
].in
, 25.0, tc_in
),
267 frames2tc(item
[i
].dur
, 25.0, tc_dur
),
270 g_warning("omnplay_library_save_file: written [%d] lines to file [%s]\n", count
, filename
);
274 void omnplay_library_save(omnplay_instance_t
* app
)
276 pthread_mutex_lock(&app
->library
.lock
);
278 if(app
->library
.filename
[0])
279 omnplay_library_save_file(app
->library
.item
, app
->library
.count
,
280 app
->library
.filename
);
282 pthread_mutex_unlock(&app
->library
.lock
);
285 static void omnplay_get_content_cb(omnplay_instance_t
* app
, playlist_item_t
* item
, void* data
)
287 if(!(app
->library
.id_display_idx
% app
->library
.id_display_rate
))
288 omnplay_set_status(app
, item
->id
);
289 app
->library
.id_display_idx
++;
292 static void* omnplay_library_refresh_proc(void* data
)
294 omnplay_instance_t
* app
= (omnplay_instance_t
*)data
;
296 playlist_item_t
* items
;
299 gtk_widget_set_sensitive(app
->window
, FALSE
);
303 omnplay_set_status(app
, "Updating library...");
305 items
= (playlist_item_t
*)malloc(sizeof(playlist_item_t
) * MAX_LIBRARY_ITEMS
);
307 count
= omnplay_get_content(app
, items
, MAX_LIBRARY_ITEMS
, omnplay_get_content_cb
, NULL
);
311 omnplay_set_status(app
, "Quering whois...");
313 if(app
->library
.whois
[0])
314 omnplay_whois_list(app
, items
, &count
);
316 omnplay_set_status(app
, "Setting library...");
318 pthread_mutex_lock(&app
->library
.lock
);
320 for(i
= 0; i
< count
; i
++)
321 app
->library
.item
[i
] = items
[i
];
323 app
->library
.count
= count
;
325 omnplay_library_sort(app
);
327 pthread_mutex_unlock(&app
->library
.lock
);
330 omnplay_library_draw(app
);
335 omnplay_set_status(app
, "Normalizing playlist...");
340 omnplay_playlist_normalize(app
);
344 omnplay_set_status(app
, "");
347 gtk_widget_set_sensitive(app
->window
, TRUE
);
355 void omnplay_library_refresh(omnplay_instance_t
* app
)
357 if(app
->library
.refresh_thread
)
358 g_thread_join(app
->library
.refresh_thread
);
360 app
->library
.refresh_thread
= g_thread_create(
361 omnplay_library_refresh_proc
, app
, TRUE
, NULL
);
364 void omnplay_library_draw(omnplay_instance_t
* app
)
368 GtkListStore
*list_store
;
371 list_store
= GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(app
->library_grid
)));
372 gtk_list_store_clear(list_store
);
374 pthread_mutex_lock(&app
->library
.lock
);
376 for(i
= 0;i
< app
->library
.count
; i
++)
378 gtk_list_store_append(list_store
, &iter
);
380 gtk_list_store_set(list_store
, &iter
,
381 0, app
->library
.item
[i
].id
,
382 1, frames2tc(app
->library
.item
[i
].dur
, 25.0, tc
),
383 2, app
->library
.item
[i
].title
,
390 pthread_mutex_unlock(&app
->library
.lock
);
393 static void get_selected_idx_library_proc(GtkTreeModel
*model
, GtkTreePath
*path
, GtkTreeIter
*iter
, gpointer data
)
395 int idx
, *list
= (int*)data
;
396 gtk_tree_model_get(model
, iter
, 3, &idx
, -1);
397 list
[list
[0] + 1] = idx
;
398 list
[0] = list
[0] + 1;
401 static int* get_selected_idx_library(omnplay_instance_t
* app
)
404 GtkTreeSelection
*selection
;
406 selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(app
->library_grid
));
409 list
= (int*)malloc(sizeof(int) * (MAX_LIBRARY_ITEMS
+ 1));
410 memset(list
, 0, sizeof(int) * (MAX_LIBRARY_ITEMS
+ 1));
412 gtk_tree_selection_selected_foreach(
414 get_selected_idx_library_proc
,
428 playlist_item_t
* omnplay_library_get_selected(omnplay_instance_t
* app
, int *count
)
431 playlist_item_t
* items
= NULL
;
433 pthread_mutex_lock(&app
->library
.lock
);
437 idxs
= get_selected_idx_library(app
);
444 items
= (playlist_item_t
*)malloc(sizeof(playlist_item_t
) * (idxs
[0] + 1));
446 /* clear last item */
447 memset(&items
[idxs
[0]], 0, sizeof(playlist_item_t
));
450 for(i
= 0; i
< idxs
[0]; i
++)
451 items
[i
] = app
->library
.item
[idxs
[i
+ 1]];
457 pthread_mutex_unlock(&app
->library
.lock
);
462 void omnplay_library_search(omnplay_instance_t
* app
, int next
)
469 pthread_mutex_lock(&app
->library
.lock
);
471 idxs
= get_selected_idx_library(app
);
472 if(idxs
) idx
= idxs
[1];
478 search
= gtk_entry_get_text(GTK_ENTRY(app
->library
.search
));
482 for(i
= idx
; i
< app
->library
.count
; i
++)
483 if( strcasestr(app
->library
.item
[i
].id
, search
) ||
484 strcasestr(app
->library
.item
[i
].title
, search
))
487 if(i
< app
->library
.count
)
489 g_warning("found at pos=%d\n", i
);
492 path
= gtk_tree_path_new_from_indices(i
, -1);
493 gtk_tree_selection_select_path(gtk_tree_view_get_selection(
494 GTK_TREE_VIEW(app
->library_grid
)), path
);
495 gtk_tree_view_set_cursor(GTK_TREE_VIEW(app
->library_grid
), path
, NULL
, FALSE
);
496 gtk_tree_path_free(path
);
500 pthread_mutex_unlock(&app
->library
.lock
);