2015-12-07 09:35:58 -05:00
|
|
|
/*
|
2013-10-27 17:25:26 -04:00
|
|
|
* Copyright 2013 (c) Anna Schumaker.
|
|
|
|
*/
|
2015-12-07 09:35:58 -05:00
|
|
|
#include <core/collection.h>
|
2014-06-05 10:19:22 -04:00
|
|
|
#include <core/idle.h>
|
2015-12-11 09:21:10 -05:00
|
|
|
#include <core/playlist.h>
|
2013-10-27 17:25:26 -04:00
|
|
|
|
|
|
|
#include <glib.h>
|
2015-12-07 09:35:58 -05:00
|
|
|
#include <stdlib.h>
|
2016-03-21 08:33:14 -04:00
|
|
|
#include <unistd.h>
|
2013-10-27 17:25:26 -04:00
|
|
|
|
2013-11-10 17:37:35 -05:00
|
|
|
|
2015-12-07 10:05:42 -05:00
|
|
|
static struct file c_file = FILE_INIT("library.q", 0);
|
2015-12-07 10:04:08 -05:00
|
|
|
static struct queue c_queue;
|
2014-05-24 12:47:33 -04:00
|
|
|
|
2015-12-07 09:15:12 -05:00
|
|
|
struct scan_data {
|
|
|
|
struct library *sd_lib;
|
|
|
|
gchar *sd_path;
|
2014-01-01 13:34:25 -05:00
|
|
|
};
|
2013-11-10 16:09:31 -05:00
|
|
|
|
2015-12-07 09:15:12 -05:00
|
|
|
static void __scan_dir(void *);
|
2014-05-24 12:47:33 -04:00
|
|
|
|
|
|
|
|
2016-03-21 08:33:14 -04:00
|
|
|
#ifdef CONFIG_TESTING
|
2016-03-23 09:39:37 -04:00
|
|
|
bool test_collection_error = false;
|
|
|
|
static inline int __g_access(const gchar *path)
|
2016-03-21 08:33:14 -04:00
|
|
|
{
|
2016-03-23 09:39:37 -04:00
|
|
|
if (test_collection_error)
|
2016-03-21 08:33:14 -04:00
|
|
|
return -1;
|
|
|
|
return g_access(path, F_OK);
|
|
|
|
}
|
|
|
|
#else
|
2016-03-23 09:39:37 -04:00
|
|
|
#define __g_access(path) g_access(path, F_OK)
|
2016-03-21 08:33:14 -04:00
|
|
|
#endif /* CONFIG_TESTING */
|
|
|
|
|
|
|
|
|
2015-12-07 09:15:12 -05:00
|
|
|
static void __scan_dir_later(struct library *library, const gchar *dir)
|
2014-12-02 08:24:36 -05:00
|
|
|
{
|
2015-12-07 09:35:58 -05:00
|
|
|
struct scan_data *data = g_malloc(sizeof(struct scan_data));
|
2015-12-07 09:15:12 -05:00
|
|
|
|
|
|
|
data->sd_lib = library;
|
|
|
|
data->sd_path = g_strdup(dir);
|
|
|
|
|
|
|
|
/* data is freed by __scan_dir() */
|
|
|
|
idle_schedule(__scan_dir, data);
|
2014-12-02 08:24:36 -05:00
|
|
|
}
|
2013-11-10 16:09:31 -05:00
|
|
|
|
2015-12-07 09:15:12 -05:00
|
|
|
static void __scan_path(struct scan_data *scan, const gchar *name)
|
2013-11-10 16:09:31 -05:00
|
|
|
{
|
2015-12-07 09:15:12 -05:00
|
|
|
gchar *path = g_strdup_printf("%s/%s", scan->sd_path, name);
|
|
|
|
struct track *track;
|
2015-11-10 13:52:24 -05:00
|
|
|
|
2015-12-07 09:15:12 -05:00
|
|
|
if (g_file_test(path, G_FILE_TEST_IS_DIR))
|
|
|
|
__scan_dir_later(scan->sd_lib, path);
|
2015-11-10 13:52:24 -05:00
|
|
|
else {
|
2015-12-07 09:15:12 -05:00
|
|
|
track = track_add(scan->sd_lib, path);
|
|
|
|
if (track)
|
2015-12-07 10:04:08 -05:00
|
|
|
queue_add(&c_queue, track);
|
2015-11-10 13:52:24 -05:00
|
|
|
}
|
2015-12-07 09:15:12 -05:00
|
|
|
|
|
|
|
g_free(path);
|
2013-11-10 17:37:35 -05:00
|
|
|
}
|
|
|
|
|
2015-12-07 09:15:12 -05:00
|
|
|
static void __scan_dir(void *data)
|
2013-11-10 16:09:31 -05:00
|
|
|
{
|
2015-12-07 09:35:58 -05:00
|
|
|
struct scan_data *scan = data;
|
2013-11-10 16:09:31 -05:00
|
|
|
const char *name;
|
2015-12-07 09:35:58 -05:00
|
|
|
GDir *dir;
|
2013-11-10 16:09:31 -05:00
|
|
|
|
2015-12-07 09:35:58 -05:00
|
|
|
dir = g_dir_open(scan->sd_path, 0, NULL);
|
2013-11-10 16:09:31 -05:00
|
|
|
if (dir == NULL)
|
2015-12-07 09:15:12 -05:00
|
|
|
goto out;
|
2013-11-10 16:09:31 -05:00
|
|
|
|
|
|
|
name = g_dir_read_name(dir);
|
|
|
|
while (name != NULL) {
|
2015-12-07 09:15:12 -05:00
|
|
|
__scan_path(scan, name);
|
2013-11-10 16:09:31 -05:00
|
|
|
name = g_dir_read_name(dir);
|
|
|
|
}
|
2014-01-15 20:40:24 -05:00
|
|
|
|
2016-01-11 09:55:49 -05:00
|
|
|
g_dir_close(dir);
|
2015-12-05 14:27:30 -05:00
|
|
|
track_db_commit();
|
2015-12-07 09:15:12 -05:00
|
|
|
|
|
|
|
out:
|
|
|
|
/* Allocated by __scan_dir_later() */
|
|
|
|
g_free(scan->sd_path);
|
2015-12-07 09:35:58 -05:00
|
|
|
g_free(scan);
|
2013-11-10 16:09:31 -05:00
|
|
|
}
|
|
|
|
|
2015-12-07 09:15:12 -05:00
|
|
|
static void __validate_library(void *data)
|
2013-12-22 15:38:27 -05:00
|
|
|
{
|
2015-12-07 09:35:58 -05:00
|
|
|
struct library *library = data;
|
2015-11-04 12:23:00 -05:00
|
|
|
struct db_entry *dbe, *next;
|
|
|
|
struct track *track;
|
2016-03-21 08:33:14 -04:00
|
|
|
int access;
|
2015-11-12 09:38:35 -05:00
|
|
|
gchar *path;
|
2013-12-22 15:38:27 -05:00
|
|
|
|
2015-11-04 12:23:00 -05:00
|
|
|
db_for_each(dbe, next, track_db_get()) {
|
|
|
|
track = TRACK(dbe);
|
2015-10-27 17:25:18 -04:00
|
|
|
if (track->tr_library != library)
|
2013-12-22 15:38:27 -05:00
|
|
|
continue;
|
|
|
|
|
2016-03-21 08:33:14 -04:00
|
|
|
path = track_path(track);
|
2016-03-23 09:39:37 -04:00
|
|
|
access = __g_access(path);
|
2016-03-21 08:33:14 -04:00
|
|
|
g_free(path);
|
|
|
|
|
|
|
|
if (access < 0) {
|
2016-03-23 09:39:37 -04:00
|
|
|
if (collection_check_library(library) < 0)
|
|
|
|
return;
|
2015-12-07 10:04:08 -05:00
|
|
|
queue_remove_all(&c_queue, track);
|
2015-10-25 04:41:03 -04:00
|
|
|
track_remove(track);
|
2013-12-22 15:38:27 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-25 08:33:03 -05:00
|
|
|
void __collection_init_idle(void *data)
|
2013-11-03 16:03:01 -05:00
|
|
|
{
|
2015-11-04 12:23:00 -05:00
|
|
|
struct db_entry *track, *next;
|
2015-12-05 14:16:51 -05:00
|
|
|
unsigned int i, n = 0;
|
|
|
|
int field, ascending;
|
2014-05-24 12:47:33 -04:00
|
|
|
|
2015-10-25 05:06:23 -04:00
|
|
|
db_for_each(track, next, track_db_get()) {
|
2015-12-11 09:21:10 -05:00
|
|
|
if (TRACK(track)->tr_library->li_enabled &&
|
2016-02-26 15:37:27 -05:00
|
|
|
!playlist_has(PL_HIDDEN, TRACK(track)))
|
2015-12-07 10:04:08 -05:00
|
|
|
queue_add(&c_queue, TRACK(track));
|
2014-01-25 13:19:40 -05:00
|
|
|
}
|
2015-12-07 10:04:08 -05:00
|
|
|
queue_unset_flag(&c_queue, Q_ADD_FRONT);
|
2015-11-23 08:36:29 -05:00
|
|
|
|
2015-12-05 14:16:51 -05:00
|
|
|
if (file_open(&c_file, OPEN_READ))
|
2015-12-07 10:04:08 -05:00
|
|
|
file_readf(&c_file, "%u %u", &c_queue.q_flags, &n);
|
2015-12-05 14:16:51 -05:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
file_readf(&c_file, "%u %d", &field, &ascending);
|
2015-12-07 10:04:08 -05:00
|
|
|
queue_sort(&c_queue, field + 1, (i == 0) ? true : false);
|
2015-12-05 14:16:51 -05:00
|
|
|
if (ascending == false)
|
2015-12-07 10:04:08 -05:00
|
|
|
queue_sort(&c_queue, field + 1, false);
|
2015-12-05 14:16:51 -05:00
|
|
|
}
|
|
|
|
file_close(&c_file);
|
|
|
|
|
2015-12-07 10:04:08 -05:00
|
|
|
if (!c_queue.q_sort) {
|
|
|
|
queue_sort(&c_queue, COMPARE_ARTIST, true);
|
|
|
|
queue_sort(&c_queue, COMPARE_YEAR, false);
|
|
|
|
queue_sort(&c_queue, COMPARE_TRACK, false);
|
2015-11-23 08:36:29 -05:00
|
|
|
}
|
2015-11-24 08:18:31 -05:00
|
|
|
|
2015-12-07 10:04:08 -05:00
|
|
|
queue_set_flag(&c_queue, Q_SAVE_SORT);
|
|
|
|
queue_set_flag(&c_queue, Q_SAVE_FLAGS);
|
2016-02-23 07:55:56 -05:00
|
|
|
|
|
|
|
collection_update_all();
|
2015-11-24 08:18:31 -05:00
|
|
|
}
|
|
|
|
|
2016-02-25 08:33:03 -05:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* External API begins here
|
|
|
|
*/
|
|
|
|
void collection_init(struct queue_ops *ops)
|
|
|
|
{
|
|
|
|
queue_init(&c_queue, Q_ENABLED | Q_REPEAT | Q_ADD_FRONT, ops);
|
|
|
|
idle_schedule(__collection_init_idle, NULL);
|
|
|
|
}
|
|
|
|
|
2015-12-05 12:04:19 -05:00
|
|
|
void collection_deinit()
|
|
|
|
{
|
2015-12-07 10:04:08 -05:00
|
|
|
queue_deinit(&c_queue);
|
2015-12-05 12:04:19 -05:00
|
|
|
}
|
|
|
|
|
2015-12-05 13:24:26 -05:00
|
|
|
void collection_save(struct queue *queue, enum queue_flags flag)
|
2015-11-24 08:18:31 -05:00
|
|
|
{
|
2015-12-07 10:04:08 -05:00
|
|
|
GSList *cur = c_queue.q_sort;
|
2015-12-05 13:53:30 -05:00
|
|
|
int field;
|
|
|
|
|
2015-12-07 10:04:08 -05:00
|
|
|
if (&c_queue != queue)
|
2015-12-05 13:53:30 -05:00
|
|
|
return;
|
|
|
|
if (!file_open(&c_file, OPEN_WRITE))
|
|
|
|
return;
|
|
|
|
|
2015-12-07 10:04:08 -05:00
|
|
|
file_writef(&c_file, "%u %u", c_queue.q_flags, g_slist_length(cur));
|
2015-12-05 13:53:30 -05:00
|
|
|
while (cur) {
|
|
|
|
field = GPOINTER_TO_INT(cur->data);
|
|
|
|
file_writef(&c_file, " %u %d", abs(field) - 1, field > 0);
|
|
|
|
cur = g_slist_next(cur);
|
|
|
|
}
|
|
|
|
file_writef(&c_file, "\n");
|
|
|
|
file_close(&c_file);
|
2013-11-03 16:03:01 -05:00
|
|
|
}
|
|
|
|
|
2015-12-05 09:36:14 -05:00
|
|
|
struct library *collection_add(const gchar *path)
|
2013-10-27 17:25:26 -04:00
|
|
|
{
|
2015-10-23 10:21:12 -04:00
|
|
|
struct library *library = NULL;
|
2013-10-27 17:25:26 -04:00
|
|
|
|
2015-12-05 09:36:14 -05:00
|
|
|
if (g_file_test(path, G_FILE_TEST_IS_DIR) == false)
|
2014-05-24 12:47:33 -04:00
|
|
|
return library;
|
2014-01-15 20:40:24 -05:00
|
|
|
|
2015-12-05 09:36:14 -05:00
|
|
|
library = library_find(path);
|
2014-05-24 12:47:33 -04:00
|
|
|
if (library)
|
2015-12-05 10:39:34 -05:00
|
|
|
collection_update(library);
|
2014-05-24 12:47:33 -04:00
|
|
|
return library;
|
2013-10-27 17:25:26 -04:00
|
|
|
}
|
|
|
|
|
2015-12-05 10:21:24 -05:00
|
|
|
void collection_remove(struct library *library)
|
2013-10-27 17:25:26 -04:00
|
|
|
{
|
2014-05-24 12:47:33 -04:00
|
|
|
if (library) {
|
2015-12-05 11:52:23 -05:00
|
|
|
collection_set_enabled(library, false);
|
2015-10-25 04:43:39 -04:00
|
|
|
track_remove_all(library);
|
2015-09-28 09:55:29 -04:00
|
|
|
library_remove(library);
|
2014-01-16 22:23:36 -05:00
|
|
|
}
|
2013-10-27 17:25:26 -04:00
|
|
|
}
|
|
|
|
|
2015-12-05 10:39:34 -05:00
|
|
|
void collection_update(struct library *library)
|
2013-11-10 16:09:31 -05:00
|
|
|
{
|
2015-12-05 14:27:30 -05:00
|
|
|
if (!library)
|
|
|
|
return;
|
|
|
|
|
2015-12-07 09:15:12 -05:00
|
|
|
idle_schedule(__validate_library, library);
|
|
|
|
__scan_dir_later(library, library->li_path);
|
2013-11-10 16:09:31 -05:00
|
|
|
}
|
|
|
|
|
2015-12-05 10:39:34 -05:00
|
|
|
void collection_update_all()
|
2014-01-12 13:04:16 -05:00
|
|
|
{
|
2015-11-04 12:23:00 -05:00
|
|
|
struct db_entry *library, *next;
|
2014-03-09 14:58:06 -04:00
|
|
|
|
2015-10-23 13:32:20 -04:00
|
|
|
db_for_each(library, next, library_db_get())
|
2015-12-05 10:39:34 -05:00
|
|
|
collection_update(LIBRARY(library));
|
2014-01-12 13:04:16 -05:00
|
|
|
}
|
|
|
|
|
2015-12-11 08:06:49 -05:00
|
|
|
bool collection_ban(struct track *track)
|
|
|
|
{
|
2016-02-26 15:37:27 -05:00
|
|
|
bool ret = playlist_add(PL_HIDDEN, track);
|
2015-12-11 09:21:10 -05:00
|
|
|
if (ret)
|
|
|
|
queue_remove_all(&c_queue, track);
|
|
|
|
return ret;
|
2015-12-11 08:06:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
bool collection_unban(struct track *track)
|
|
|
|
{
|
2016-02-26 15:37:27 -05:00
|
|
|
bool ret = playlist_remove(PL_HIDDEN, track);
|
2015-12-11 09:21:10 -05:00
|
|
|
if (ret)
|
|
|
|
queue_add(&c_queue, track);
|
|
|
|
return ret;
|
2015-12-11 08:06:49 -05:00
|
|
|
}
|
|
|
|
|
2015-12-05 11:52:23 -05:00
|
|
|
void collection_set_enabled(struct library *library, bool enabled)
|
2014-01-18 12:32:41 -05:00
|
|
|
{
|
2015-11-04 12:23:00 -05:00
|
|
|
struct db_entry *dbe, *next;
|
|
|
|
struct track *track;
|
2014-05-24 12:47:33 -04:00
|
|
|
|
2015-10-23 14:10:59 -04:00
|
|
|
if (!library || (library->li_enabled == enabled))
|
2014-05-24 12:47:33 -04:00
|
|
|
return;
|
2016-03-23 09:39:37 -04:00
|
|
|
if (enabled && (collection_check_library(library) < 0))
|
2016-03-21 08:33:14 -04:00
|
|
|
return;
|
2014-01-18 12:32:41 -05:00
|
|
|
|
2015-10-23 14:19:42 -04:00
|
|
|
library_set_enabled(library, enabled);
|
2015-12-07 10:04:08 -05:00
|
|
|
queue_set_flag(&c_queue, Q_ADD_FRONT);
|
2014-03-29 11:44:39 -04:00
|
|
|
|
2015-11-04 12:23:00 -05:00
|
|
|
db_for_each(dbe, next, track_db_get()) {
|
|
|
|
track = TRACK(dbe);
|
2015-10-27 17:25:18 -04:00
|
|
|
if (track->tr_library == library) {
|
2015-12-11 09:21:10 -05:00
|
|
|
if (enabled) {
|
2016-02-26 15:37:27 -05:00
|
|
|
if (!playlist_has(PL_HIDDEN, track))
|
2015-12-11 09:21:10 -05:00
|
|
|
queue_add(&c_queue, track);
|
|
|
|
} else
|
2015-12-07 10:04:08 -05:00
|
|
|
queue_remove_all(&c_queue, track);
|
2014-01-18 12:32:41 -05:00
|
|
|
}
|
|
|
|
}
|
2015-12-03 10:03:52 -05:00
|
|
|
|
2015-12-07 10:04:08 -05:00
|
|
|
queue_unset_flag(&c_queue, Q_ADD_FRONT);
|
|
|
|
queue_resort(&c_queue);
|
2014-01-18 12:32:41 -05:00
|
|
|
}
|
|
|
|
|
2016-03-21 08:33:14 -04:00
|
|
|
int collection_check_library(struct library *library)
|
|
|
|
{
|
2016-03-23 09:39:37 -04:00
|
|
|
int ret = __g_access(library->li_path);
|
|
|
|
if (ret < 0) {
|
2016-03-21 08:33:14 -04:00
|
|
|
g_warning("Can't access library at %s/\n", library->li_path);
|
|
|
|
collection_set_enabled(library, false);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-12-05 12:12:01 -05:00
|
|
|
struct queue *collection_get_queue()
|
2013-10-27 17:25:26 -04:00
|
|
|
{
|
2015-12-07 10:04:08 -05:00
|
|
|
return &c_queue;
|
2013-10-27 17:25:26 -04:00
|
|
|
}
|