diff options
| author | Louis Burda <quent.burda@gmail.com> | 2022-02-27 13:59:28 +0100 |
|---|---|---|
| committer | Louis Burda <quent.burda@gmail.com> | 2022-02-27 13:59:28 +0100 |
| commit | 66dd37c0018bd958ea1a644e3552bce66b13f658 (patch) | |
| tree | a55e352da7926abc235a1e1c040f64f2c5a4c388 /src/data.c | |
| parent | 5d8e3d19823a3c193b0ad4e8d8fd3ccdf8f77c80 (diff) | |
| download | tmus-66dd37c0018bd958ea1a644e3552bce66b13f658.tar.gz tmus-66dd37c0018bd958ea1a644e3552bce66b13f658.zip | |
Switch from mostly ref based tracking to multi-link architecture
Diffstat (limited to 'src/data.c')
| -rw-r--r-- | src/data.c | 628 |
1 files changed, 354 insertions, 274 deletions
@@ -3,9 +3,6 @@ #include "player.h" #include "list.h" #include "log.h" -#include "ref.h" -#include "track.h" -#include "tag.h" #include "tui.h" #include <fts.h> @@ -18,88 +15,21 @@ const char *datadir; -struct list tracks; -struct list tags; -struct list tags_sel; +struct list tracks; /* struct track (link) */ +struct list tags; /* struct track (link) */ +struct list tags_sel; /* struct tag (link_sel) */ -void -data_load(void) -{ - struct dirent *ent; - struct tag *tag; - struct stat st; - char *path; - DIR *dir; - - list_init(&tracks); - list_init(&tags); - list_init(&tags_sel); - - datadir = getenv("TMUS_DATA"); - if (!datadir) ERROR("TMUS_DATA not set!\n"); - - dir = opendir(datadir); - if (!dir) ERROR("Failed to access dir: %s\n", datadir); - - while ((ent = readdir(dir))) { - if (!strcmp(ent->d_name, ".")) - continue; - if (!strcmp(ent->d_name, "..")) - continue; - - path = aprintf("%s/%s", datadir, ent->d_name); - OOM_CHECK(path); - - if (!stat(path, &st) && S_ISDIR(st.st_mode)) { - tag = tag_alloc(datadir, ent->d_name); - OOM_CHECK(tag); - tracks_load(tag); - list_push_back(&tags, LINK(tag)); - } - - free(path); - } - closedir(dir); - - list_sort(&tracks, track_fid_compare); -} - -void -data_save(void) -{ - struct link *iter; - struct tag *tag; - - for (LIST_ITER(&tags, iter)) { - tag = UPCAST(iter, struct tag); - tracks_save(tag); - } -} - -void -data_free(void) -{ - struct link *track_link; - struct link *tag_link; - struct tag *tag; - - log_info("MAIN: data_free()\n"); +static int get_fid(const char *path); - refs_free(&tracks); - refs_free(&tags_sel); +static struct tag *tag_alloc(const char *path, const char *fname); +static void tag_free(struct tag *tag); - while (!list_empty(&tags)) { - tag_link = list_pop_front(&tags); +static struct track *track_alloc(const char *path, const char *fname); +static void track_free(struct track *t); +static int track_name_compare(struct link *a, struct link *b); - tag = UPCAST(tag_link, struct tag); - while (!list_empty(&tag->tracks)) { - track_link = list_pop_front(&tag->tracks); - track_free(UPCAST(track_link, struct ref)->data); - ref_free(UPCAST(track_link, struct ref)); - } - tag_free(tag); - } -} +static void tracks_load(struct tag *tag); +static void tracks_save(struct tag *tag); int get_fid(const char *path) @@ -108,168 +38,86 @@ get_fid(const char *path) return stat(path, &st) ? -1 : st.st_ino; } -int -track_fid_compare(struct link *a, struct link *b) -{ - struct track *ta, *tb; - - ta = UPCAST(a, struct ref)->data; - tb = UPCAST(b, struct ref)->data; - - return ta->fid - tb->fid; -} - -void -index_update(struct tag *tag) +struct tag * +tag_alloc(const char *path, const char *fname) { - struct dirent *ent; - struct stat st; - char *path; - FILE *file; - DIR *dir; - int fid; + struct tag *tag; - path = aprintf("%s/index", tag->fpath); - OOM_CHECK(path); + tag = malloc(sizeof(struct tag)); + ASSERT(tag != NULL); - dir = opendir(tag->fpath); - if (!dir) ERROR("Failed to access dir: %s\n", tag->fpath); + tag->fpath = aprintf("%s/%s", path, fname); + ASSERT(tag->fpath != NULL); - file = fopen(path, "w+"); - if (!file) ERROR("Failed to create file: %s\n", path); - free(path); + tag->name = strdup(fname); + ASSERT(tag->name != NULL); - while ((ent = readdir(dir))) { - if (!strcmp(ent->d_name, ".")) - continue; - if (!strcmp(ent->d_name, "..")) - continue; - if (!strcmp(ent->d_name, "index")) - continue; + tag->link = LINK_EMPTY; + tag->link_sel = LINK_EMPTY; - /* skip files without extension */ - if (!strchr(ent->d_name + 1, '.')) - continue; + list_init(&tag->tracks); - path = aprintf("%s/%s", tag->fpath, ent->d_name); - OOM_CHECK(path); - fid = get_fid(path); - free(path); - - fprintf(file, "%i:%s\n", fid, ent->d_name); - } + return tag; +} - closedir(dir); - fclose(file); +void +tag_free(struct tag *tag) +{ + free(tag->fpath); + free(tag->name); + list_clear(&tag->tracks); + free(tag); } -bool -tracks_update(struct tag *tag) +struct track * +track_alloc(const char *dir, const char *fname) { - struct dirent *ent; - struct stat st; - struct link *link; - struct ref *ref; struct track *track; - char *path; - DIR *dir; - int fid; - - dir = opendir(tag->fpath); - if (!dir) return false; - while (!list_empty(&tag->tracks)) { - link = list_pop_front(&tag->tracks); - ref = UPCAST(link, struct ref); - track = ref->data; - ref_free(ref); - for (LIST_ITER(&tracks, link)) { - ref = UPCAST(link, struct ref); - if (ref->data == track) { - link = link_pop(link); - ref_free(ref); - break; - } - } - if (player.track == track) - player.track = NULL; - track_free(track); - } + track = malloc(sizeof(struct track)); + ASSERT(track != NULL); - while ((ent = readdir(dir))) { - if (!strcmp(ent->d_name, ".")) - continue; - if (!strcmp(ent->d_name, "..")) - continue; - if (!strcmp(ent->d_name, "index")) - continue; + track->fpath = aprintf("%s/%s", dir, fname); + ASSERT(track->fpath != NULL); - /* skip files without extension */ - if (!strchr(ent->d_name + 1, '.')) - continue; + track->name = strdup(fname); + ASSERT(track->name != NULL); - path = aprintf("%s/%s", tag->fpath, ent->d_name); - OOM_CHECK(path); + track->tag = NULL; - fid = get_fid(path); + track->link = LINK_EMPTY; + track->link_pl = LINK_EMPTY; + track->link_tt = LINK_EMPTY; + track->link_pq = LINK_EMPTY; + track->link_hs = LINK_EMPTY; - track = track_alloc(tag->fpath, ent->d_name, fid); - OOM_CHECK(track); - - ref = ref_alloc(tag); - OOM_CHECK(ref); - list_push_back(&track->tags, LINK(ref)); - - ref = ref_alloc(track); - OOM_CHECK(ref); - list_push_back(&tag->tracks, LINK(ref)); - - ref = ref_alloc(track); - OOM_CHECK(ref); - list_push_back(&tracks, LINK(ref)); - - free(path); - } - - list_sort(&tracks, track_fid_compare); - - playlist_update(); - - closedir(dir); - return true; + return track; } void -playlist_update(void) +track_free(struct track *t) { - struct link *link, *link2; - struct track *track; - struct ref *ref; - struct tag *tag; + free(t->fpath); + free(t->name); + free(t); +} - refs_free(&player.playlist); - for (LIST_ITER(&tags_sel, link)) { - tag = UPCAST(link, struct ref)->data; - for (LIST_ITER(&tag->tracks, link2)) { - track = UPCAST(link2, struct ref)->data; - ref = ref_alloc(track); - ASSERT(ref != NULL); - list_push_back(&player.playlist, LINK(ref)); - } - } +int +track_name_compare(struct link *a, struct link *b) +{ + struct track *ta, *tb; + + ta = UPCAST(a, struct track, link); + tb = UPCAST(b, struct track, link); + + return strcmp(ta->name, tb->name); } void tracks_load(struct tag *tag) { char linebuf[1024]; - struct link *link; - struct track *track; - struct track *track2; - struct ref *ref; char *index_path; - char *track_name, *sep; - int track_fid; FILE *file; index_path = aprintf("%s/index", tag->fpath); @@ -283,28 +131,10 @@ tracks_load(struct tag *tag) } while (fgets(linebuf, sizeof(linebuf), file)) { - sep = strchr(linebuf, '\n'); - if (sep) *sep = '\0'; - - sep = strchr(linebuf, ':'); - if (!sep) ERROR("Syntax error in index file: %s\n", index_path); - *sep = '\0'; - - track_fid = atoi(linebuf); - track_name = sep + 1; - track = track_alloc(tag->fpath, track_name, track_fid); - - ref = ref_alloc(tag); - OOM_CHECK(ref); - list_push_back(&track->tags, LINK(ref)); - - ref = ref_alloc(track); - OOM_CHECK(ref); - list_push_back(&tag->tracks, LINK(ref)); - - ref = ref_alloc(track); - OOM_CHECK(ref); - list_push_back(&tracks, LINK(ref)); + if (!*linebuf) continue; + if (linebuf[strlen(linebuf) - 1] == '\n') + linebuf[strlen(linebuf) - 1] = '\0'; + track_add(tag, linebuf); } fclose(file); @@ -333,8 +163,8 @@ tracks_save(struct tag *tag) } for (LIST_ITER(&tag->tracks, link)) { - track = UPCAST(link, struct ref)->data; - fprintf(file, "%i:%s\n", track->fid, track->name); + track = UPCAST(link, struct track, link_tt); + fprintf(file, "%s\n", track->name); } fclose(file); @@ -342,36 +172,6 @@ tracks_save(struct tag *tag) } bool -track_rm(struct track *track) -{ - struct link *link; - struct ref *ref; - struct tag *tag; - - if (!rm_file(track->fpath)) { - CMD_SET_STATUS("Failed to remove track"); - return false; - } - - refs_rm(&tracks, track); - - for (LIST_ITER(&track->tags, link)) { - ref = UPCAST(link, struct ref); - tag = ref->data; - refs_rm(&tag->tracks, track); - } - - refs_rm(&player.playlist, track); - - if (player.track == track) - player.track = NULL; - - track_free(track); - - return true; -} - -bool make_dir(const char *path) { return mkdir(path, S_IRWXU | S_IRWXG) == 0; @@ -428,7 +228,7 @@ copy_file(const char *src, const char *dst) { FILE *in, *out; char buf[4096]; - int len, nread; + int nread; bool ok; ok = false; @@ -457,25 +257,305 @@ cleanup: } bool +dup_file(const char *src, const char *dst) +{ + /* TODO add option for hard link dup if possible */ + return copy_file(src, dst); +} + +bool move_file(const char *src, const char *dst) { return rename(src, dst) == 0; } +void +index_update(struct tag *tag) +{ + struct dirent *ent; + char *index_path; + FILE *file; + DIR *dir; + + dir = opendir(tag->fpath); + if (!dir) ERROR("Failed to access dir: %s\n", tag->fpath); + + index_path = aprintf("%s/index", tag->fpath); + OOM_CHECK(index_path); + + file = fopen(index_path, "w+"); + if (!file) ERROR("Failed to create index file in dir %s\n", tag->name); + free(index_path); + + while ((ent = readdir(dir))) { + if (!strcmp(ent->d_name, ".")) + continue; + if (!strcmp(ent->d_name, "..")) + continue; + + /* skip files without extension */ + if (!strchr(ent->d_name + 1, '.')) + continue; + + fprintf(file, "%s\n", ent->d_name); + } + + closedir(dir); + fclose(file); +} + +bool +tracks_update(struct tag *tag) +{ + struct link *link; + struct track *track; + struct dirent *ent; + DIR *dir; + + dir = opendir(tag->fpath); + if (!dir) return false; + + while (!list_empty(&tag->tracks)) { + link = list_pop_front(&tag->tracks); + track = UPCAST(link, struct track, link_tt); + track_rm(track, false); + } + + while ((ent = readdir(dir))) { + if (!strcmp(ent->d_name, ".")) + continue; + if (!strcmp(ent->d_name, "..")) + continue; + + /* skip files without extension */ + if (!strchr(ent->d_name + 1, '.')) + continue; + + track_add(tag, ent->d_name); + } + + closedir(dir); + + return true; +} + +struct track * +tracks_vis_track(struct link *link) +{ + if (tracks_vis == &player.playlist) { + return UPCAST(link, struct track, link_pl); + } else { + return UPCAST(link, struct track, link_tt); + } +} + +void +playlist_clear(void) +{ + while (!list_empty(&player.playlist)) + list_pop_front(&player.playlist); +} + +void +playlist_update(bool exec) +{ + static bool update = false; + struct link *link, *link2; + struct track *track; + struct tag *tag; + + if (!exec) { + update = true; + return; + } + + if (!update) return; + update = false; + + playlist_clear(); + + for (LIST_ITER(&tags_sel, link)) { + tag = UPCAST(link, struct tag, link_sel); + for (LIST_ITER(&tag->tracks, link2)) { + track = UPCAST(link2, struct track, link_tt); + link_pop(&track->link_pl); + list_push_back(&player.playlist, &track->link_pl); + } + } +} + struct tag * -tag_find(const char *query) +tag_add(const char *fname) { - struct link *iter; struct tag *tag; - for (LIST_ITER(&tags, iter)) { - tag = UPCAST(iter, struct tag); - if (!strcmp(tag->name, query)) { + /* add to tags list */ + tag = tag_alloc(datadir, fname); + OOM_CHECK(tag); + list_push_back(&tags, &tag->link); + + return tag; +} + +struct tag * +tag_find(const char *name) +{ + struct link *link; + struct tag *tag; + + for (LIST_ITER(&tags, link)) { + tag = UPCAST(link, struct tag, link); + if (!strcmp(tag->name, name)) return tag; - } } return NULL; } +bool +tag_rm(struct tag *tag, bool sync_fs) +{ + struct link *link; + struct track *track; + + /* remove contained tracks */ + while (!list_empty(&tag->tracks)) { + link = list_pop_front(&tag->tracks); + track = UPCAST(link, struct track, link_tt); + if (!track_rm(track, sync_fs)) + return false; + } + + /* delete dir and remaining non-track files */ + if (sync_fs && !rm_dir(tag->fpath, true)) + return false; + + /* remove from selected */ + link_pop(&tag->link_sel); + + /* remove from tags list */ + link_pop(&tag->link); + + tag_free(tag); + + return true; +} + +struct track * +track_add(struct tag *tag, const char *fname) +{ + struct track *track; + + track = track_alloc(tag->fpath, fname); + OOM_CHECK(track); + + track->tag = tag; + + /* insert track into sorted tracks list */ + list_push_back(&tracks, &track->link); + + /* add to tag's tracks list */ + list_push_back(&tag->tracks, &track->link_tt); + + /* if track's tag is selected, update playlist */ + if (link_inuse(&tag->link_sel)) + playlist_update(false); + + return track; +} + +bool +track_rm(struct track *track, bool sync_fs) +{ + if (sync_fs && !rm_file(track->fpath)) + return false; + + /* remove from tracks list */ + link_pop(&track->link); + + /* remove from tag's track list */ + link_pop(&track->link_tt); + + /* remove from playlist */ + link_pop(&track->link_pl); + + /* remove from player queue */ + link_pop(&track->link_pq); + + /* remove the reference as last used track */ + if (player.track == track) + player.track = NULL; + + track_free(track); + + return true; +} + +void +data_load(void) +{ + struct dirent *ent; + struct tag *tag; + struct stat st; + char *path; + DIR *dir; + + list_init(&tracks); + list_init(&tags); + list_init(&tags_sel); + + datadir = getenv("TMUS_DATA"); + if (!datadir) ERROR("TMUS_DATA not set!\n"); + + dir = opendir(datadir); + if (!dir) ERROR("Failed to access dir: %s\n", datadir); + + while ((ent = readdir(dir))) { + if (!strcmp(ent->d_name, ".")) + continue; + if (!strcmp(ent->d_name, "..")) + continue; + + path = aprintf("%s/%s", datadir, ent->d_name); + OOM_CHECK(path); + + if (!stat(path, &st) && S_ISDIR(st.st_mode)) { + tag = tag_add(ent->d_name); + tracks_load(tag); + } + + free(path); + } + + closedir(dir); +} + +void +data_save(void) +{ + struct link *link; + struct tag *tag; + + for (LIST_ITER(&tags, link)) { + tag = UPCAST(link, struct tag, link); + tracks_save(tag); + } +} + +void +data_free(void) +{ + struct link *link; + struct tag *tag; + + list_clear(&player.playlist); + list_clear(&player.queue); + list_clear(&player.history); + + while (!list_empty(&tags)) { + link = list_pop_front(&tags); + tag = UPCAST(link, struct tag, link); + tag_rm(tag, false); + } +} |
