📄 playlist.c
字号:
a_filename = strrchr(a->filename, '/') + 1; else a_filename = a->filename; if (strrchr(b->filename,'/')) b_filename = strrchr(b->filename, '/') + 1; else b_filename = b->filename; return strcasecmp(a_filename, b_filename);}void playlist_sort_by_filename(void){ PL_LOCK(); playlist = g_list_sort(playlist, (GCompareFunc) playlist_sort_by_filename_cmpfunc); PL_UNLOCK();}static int playlist_sort_str_by_path_cmpfunc(gconstpointer pa, gconstpointer pb){ const char *a = pa, *b = pb; char *posa, *posb; posa = strrchr(a, '/'); posb = strrchr(b, '/'); /* * Sort directories before files */ if (posa && posb && (posa - a != posb - b)) { int len, ret; if (posa - a > posb - b) { len = posb - b; ret = -1; } else { len = posa - a; ret = 1; } if (!strncasecmp(a, b, len)) return ret; } return strcasecmp(a, b);}static int playlist_sort_by_path_cmpfunc(PlaylistEntry * a, PlaylistEntry * b){ return playlist_sort_str_by_path_cmpfunc(a->filename, b->filename);}void playlist_sort_by_path(void){ PL_LOCK(); playlist = g_list_sort(playlist, (GCompareFunc) playlist_sort_by_path_cmpfunc); PL_UNLOCK();}static int playlist_sort_by_date_cmpfunc(PlaylistEntry * a, PlaylistEntry * b){ struct stat buf; time_t modtime; if (!lstat(a->filename, &buf)) { modtime = buf.st_mtime; if (!lstat(b->filename, &buf)) { if (buf.st_mtime == modtime) return 0; else return (buf.st_mtime-modtime) > 0 ? -1 : 1; } else return -1; } else if(!lstat(b->filename, &buf)) return 1; else return playlist_sort_by_filename_cmpfunc(a,b);}void playlist_sort_by_date(void){ PL_LOCK(); playlist = g_list_sort(playlist, (GCompareFunc) playlist_sort_by_date_cmpfunc); PL_UNLOCK();}static GList* playlist_sort_selected(GList *list, GCompareFunc cmpfunc){ GList *list1, *list2; GList *temp_list = NULL; GList *index_list = NULL; /* * We take all the selected entries out of the playlist, * sorts them, and then put them back in again. */ list1 = g_list_last(list); while (list1) { list2 = g_list_previous(list1); if (((PlaylistEntry *) list1->data)->selected) { gpointer idx; idx = GINT_TO_POINTER(g_list_position(list, list1)); index_list = g_list_prepend(index_list, idx); list = g_list_remove_link(list, list1); temp_list = g_list_concat(list1, temp_list); } list1 = list2; } temp_list = g_list_sort(temp_list, cmpfunc); list1 = temp_list; list2 = index_list; while (list2) { if (!list1) { g_log(NULL, G_LOG_LEVEL_CRITICAL, "%s: Error during list sorting. " "Possibly dropped some playlist-entries.", PACKAGE); break; } list = g_list_insert(list, list1->data, GPOINTER_TO_INT(list2->data)); list2 = g_list_next(list2); list1 = g_list_next(list1); } g_list_free(index_list); g_list_free(temp_list); return list;}void playlist_sort_selected_by_title(void){ PL_LOCK(); playlist = playlist_sort_selected(playlist, (GCompareFunc) playlist_sort_by_title_cmpfunc); PL_UNLOCK();}void playlist_sort_selected_by_filename(void){ PL_LOCK(); playlist = playlist_sort_selected(playlist, (GCompareFunc) playlist_sort_by_filename_cmpfunc); PL_UNLOCK();}void playlist_sort_selected_by_path(void){ PL_LOCK(); playlist = playlist_sort_selected(playlist, (GCompareFunc) playlist_sort_by_path_cmpfunc); PL_UNLOCK();}void playlist_sort_selected_by_date(void){ PL_LOCK(); playlist = playlist_sort_selected(playlist, (GCompareFunc) playlist_sort_by_date_cmpfunc); PL_UNLOCK();}void playlist_reverse(void){ PL_LOCK(); playlist = g_list_reverse(playlist); PL_UNLOCK();}static GList *playlist_shuffle_list(GList *list){ /* Caller should hold playlist mutex */ /* * Note that this doesn't make a copy of the original list. * The pointer to the original list is not valid after this * fuction is run. */ int len = g_list_length(list); int i, j; GList *node, **ptrs; if (!len) return NULL; ptrs = g_new(GList *, len); for (node = list, i = 0; i < len; node = g_list_next(node), i++) ptrs[i] = node; j = random() % len; list = ptrs[j]; ptrs[j]->next = NULL; ptrs[j] = ptrs[0]; for (i = 1; i < len; i++) { j = random() % (len - i); list->prev = ptrs[i + j]; ptrs[i + j]->next = list; list = ptrs[i + j]; ptrs[i + j] = ptrs[i]; } list->prev = NULL; g_free(ptrs); return list;}void playlist_random(void){ PL_LOCK(); playlist = playlist_shuffle_list(playlist); PL_UNLOCK();}GList * playlist_get_selected(void){ GList *node, *list = NULL; int i = 0; PL_LOCK(); for (node = get_playlist(); node != 0; node = g_list_next(node), i++) { PlaylistEntry *entry = node->data; if (entry->selected) list = g_list_prepend(list, GINT_TO_POINTER(i)); } PL_UNLOCK(); return g_list_reverse(list);}int playlist_get_num_selected(void){ GList *node; int num = 0; PL_LOCK(); for (node = get_playlist(); node != 0; node = g_list_next(node)) { PlaylistEntry *entry = node->data; if (entry->selected) num++; } PL_UNLOCK(); return num;} static void playlist_generate_shuffle_list(void){ PL_LOCK(); __playlist_generate_shuffle_list(); PL_UNLOCK();}static void __playlist_generate_shuffle_list(void){ /* Caller should hold playlist mutex */ GList *node; int numsongs; if (shuffle_list) { g_list_free(shuffle_list); shuffle_list = NULL; } if (!cfg.shuffle || !playlist) return; shuffle_list = playlist_shuffle_list(g_list_copy(playlist)); numsongs = g_list_length(shuffle_list); if (playlist_position) { int i = g_list_index(shuffle_list, playlist_position); node = g_list_nth(shuffle_list, i); shuffle_list = g_list_remove_link(shuffle_list, node); shuffle_list = g_list_prepend(shuffle_list, node->data); }}void playlist_fileinfo(int pos){ char *path = NULL; GList *node; PL_LOCK(); if ((node = g_list_nth(get_playlist(), pos)) != NULL) { PlaylistEntry *entry = node->data; path = g_strdup(entry->filename); } PL_UNLOCK(); if (path) { input_file_info_box(path); g_free(path); }}void playlist_fileinfo_current(void){ char *path = NULL; PL_LOCK(); if (get_playlist() && playlist_position) path = g_strdup(playlist_position->filename); PL_UNLOCK(); if (path) { input_file_info_box(path); g_free(path); }}static gboolean playlist_get_info_entry(PlaylistEntry *entry){ /* * Caller need to hold playlist mutex. * Note that this function temporarily drops the playlist mutex. * If it returns false, the entry might no longer be valid. */ char *temp_filename, *temp_title; int temp_length; temp_filename = g_strdup(entry->filename); temp_title = NULL; temp_length = -1; /* We don't want to lock the playlist while reading info */ PL_UNLOCK(); input_get_song_info(temp_filename, &temp_title, &temp_length); PL_LOCK(); g_free(temp_filename); if (!temp_title && temp_length == -1) return FALSE; /* Make sure entry is still around */ if (g_list_index(get_playlist(), entry) == -1) return FALSE; /* entry is still around */ entry->title = temp_title; entry->length = temp_length; return TRUE;}static void *playlist_get_info_func(void *arg){ GList *node; gboolean update_playlistwin = FALSE, update_mainwin = FALSE; PlaylistEntry *entry; while (playlist_get_info_going) { if (cfg.get_info_on_load && playlist_get_info_scan_active) { PL_LOCK(); for (node = get_playlist(); node; node = g_list_next(node)) { entry = node->data; if (entry->title || entry->length != -1) continue; if (!playlist_get_info_entry(entry)) { if (g_list_index(get_playlist(), entry) == -1) /* Entry disapeared while we looked it up. Restart. */ node = get_playlist(); } else if (entry->title || entry->length != -1) { update_playlistwin = TRUE; if (entry == playlist_position) update_mainwin = TRUE; break; } } PL_UNLOCK(); if (!node) playlist_get_info_scan_active = FALSE; } else if (!cfg.get_info_on_load && cfg.get_info_on_demand && cfg.playlist_visible && !cfg.playlist_shaded) { gboolean found = FALSE; PL_LOCK(); if (!get_playlist()) { PL_UNLOCK(); xmms_usleep(1000000); continue; } for (node = g_list_nth(get_playlist(), playlistwin_get_toprow()); node && playlistwin_item_visible(g_list_position(get_playlist(), node)); node = g_list_next(node)) { entry = node->data; if (entry->title || entry->length != -1) continue; if (!playlist_get_info_entry(entry)) { if (g_list_index(get_playlist(), entry) == -1) /* Entry disapeared while we looked it up. Restart. */ node = g_list_nth(get_playlist(), playlistwin_get_toprow()); } else if (entry->title || entry->length != -1) { update_playlistwin = TRUE; if (entry == playlist_position) update_mainwin = TRUE; found = TRUE; break; } } PL_UNLOCK(); if (!found) { xmms_usleep(500000); continue; } } else xmms_usleep(500000); if (update_playlistwin) { playlistwin_update_list(); update_playlistwin = FALSE; } if (update_mainwin) { mainwin_set_info_text(); update_mainwin = FALSE; } } pthread_exit(NULL);}void playlist_start_get_info_thread(void){ playlist_get_info_going = TRUE; pthread_create(&playlist_get_info_thread, NULL, playlist_get_info_func, NULL);}void playlist_stop_get_info_thread(void){ playlist_get_info_going = FALSE; pthread_join(playlist_get_info_thread, NULL);}void playlist_start_get_info_scan(void){ playlist_get_info_scan_active = TRUE;}void playlist_remove_dead_files(void){ /* FIXME? Does virtual directories work well? */ GList *node, *next_node, *curr_pos = NULL, *temp = NULL; PlaylistEntry *entry; gboolean list_changed = FALSE; PL_LOCK(); node = playlist; while (node) { /* A dead file is a file that is not readable. */ next_node = g_list_next(node); entry = node->data; if (entry && entry->filename && !strstr(entry->filename, "://") && /* Don't kill URL's */ ((temp = input_scan_dir(entry->filename)) == NULL) && access(entry->filename, R_OK)) { list_changed = TRUE; if (playlist_position) curr_pos = g_list_find(playlist, playlist_position); if (node == curr_pos) { if (get_input_playing()) { /* Don't remove the currently playing song */ node = next_node; continue; } if (g_list_next(curr_pos)) playlist_position = curr_pos->next->data; else if (g_list_previous(curr_pos)) playlist_position = curr_pos->prev->data; else if (node != playlist) playlist_position = playlist->data; else playlist_position = NULL; } playlist = g_list_remove_link(playlist, node); g_free(entry->title); g_free(entry->filename); g_free(node->data); g_list_free_1(node); } else if (temp) { g_list_free(temp); temp = NULL; } node = next_node; } PL_UNLOCK(); if (list_changed) { playlist_generate_shuffle_list(); playlistwin_update_list(); }}void playlist_get_total_time(gulong *total_time, gulong *selection_time, gboolean *total_more, gboolean *selection_more){ GList *list; PlaylistEntry *entry; *total_time = 0; *selection_time = 0; *total_more = FALSE; *selection_more = FALSE; PL_LOCK(); list = get_playlist(); while (list) { entry = list->data; if (entry->length != -1) *total_time += entry->length / 1000; else *total_more = TRUE; if (entry->selected) { if (entry->length != -1) *selection_time += entry->length / 1000; else *selection_more = TRUE; } list = g_list_next(list); } PL_UNLOCK();}void playlist_select_all(gboolean set){ GList *list; PL_LOCK(); list = get_playlist(); while (list) { PlaylistEntry *entry = list->data; entry->selected = set; list = list->next; } PL_UNLOCK();}void playlist_select_invert_all(void){ GList *list; PL_LOCK(); list = get_playlist(); while (list) { PlaylistEntry *entry = list->data; entry->selected = !entry->selected; list = list->next; } PL_UNLOCK();}gboolean playlist_select_invert(int num){ GList *list; gboolean retv = FALSE; PL_LOCK(); if ((list = g_list_nth(get_playlist(), num)) != NULL) { PlaylistEntry *entry = list->data; entry->selected = !entry->selected; retv = TRUE; } PL_UNLOCK(); return retv;} void playlist_select_range(int min, int max, gboolean sel){ GList *list; int i; if (min > max) { int tmp = min; min = max; max = tmp; } PL_LOCK(); list = g_list_nth(get_playlist(), min); for (i = min; i <= max && list; i++) { PlaylistEntry *entry = list->data; entry->selected = sel; list = list->next; } PL_UNLOCK();}gboolean playlist_read_info_selection(void){ GList *node; gboolean retval = FALSE; PL_LOCK(); for (node = get_playlist(); node; node = node->next) { PlaylistEntry *entry = node->data; if (entry->selected) { retval = TRUE; if (entry->title) g_free(entry->title); entry->title = NULL; entry->length = -1; if (!playlist_get_info_entry(entry)) { if (g_list_index(get_playlist(), entry) == -1) /* Entry disapeared while we looked it up. Restart. */ node = get_playlist(); } } } PL_UNLOCK(); playlistwin_update_list(); return retval;}void playlist_read_info(int pos){ GList *node; PL_LOCK(); if ((node = g_list_nth(get_playlist(), pos)) != NULL) { PlaylistEntry *entry = node->data; if (entry->title) g_free(entry->title); entry->title = NULL; entry->length = -1; playlist_get_info_entry(entry); } PL_UNLOCK(); playlistwin_update_list();}void playlist_set_shuffle(gboolean shuffle){ PL_LOCK(); cfg.shuffle = shuffle; __playlist_generate_shuffle_list(); PL_UNLOCK();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -