tmus

TUI Music Player
git clone https://git.sinitax.com/sinitax/tmus
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

cmd.c (6704B)


      1#include "cmd.h"
      2
      3#include "data.h"
      4#include "list.h"
      5#include "player.h"
      6#include "ref.h"
      7#include "tui.h"
      8#include "util.h"
      9
     10#include <asm-generic/errno-base.h>
     11#include <errno.h>
     12#include <stdbool.h>
     13#include <string.h>
     14
     15static const struct cmd *last_cmd;
     16static char *last_args;
     17
     18static void cmd_status_from_errno(int err);
     19
     20static bool cmd_save(const char *args);
     21static bool cmd_move(const char *args);
     22static bool cmd_copy(const char *args);
     23static bool cmd_reindex(const char *args);
     24static bool cmd_add_tag(const char *args);
     25static bool cmd_rm_tag(const char *args);
     26static bool cmd_rename(const char *args);
     27
     28const struct cmd commands[] = {
     29	{ "save", cmd_save },
     30	{ "move", cmd_move },
     31	{ "copy", cmd_copy },
     32	{ "reindex", cmd_reindex },
     33	{ "addtag", cmd_add_tag },
     34	{ "rmtag", cmd_rm_tag },
     35	{ "rename", cmd_rename },
     36};
     37
     38const size_t command_count = ARRLEN(commands);
     39
     40void
     41cmd_status_from_errno(int err)
     42{
     43	if (err == EACCES || err == EPERM)
     44		USER_STATUS("Missing permissions");
     45	else if (err == EEXIST)
     46		USER_STATUS("Path already exists");
     47	else
     48		USER_STATUS("Unknown error");
     49}
     50
     51bool
     52cmd_save(const char *args)
     53{
     54	struct list_link *link;
     55	struct tag *tag;
     56
     57	for (LIST_ITER(&tags, link)) {
     58		tag = LIST_UPCAST(link, struct tag, link);
     59		if (tag->index_dirty || tag->reordered)
     60			tag_save_tracks(tag);
     61	}
     62
     63	return true;
     64}
     65
     66bool
     67cmd_move(const char *name)
     68{
     69	struct list_link *link;
     70	struct track *track;
     71	struct tag *tag;
     72
     73	tag = tag_find(name);
     74	if (!tag) {
     75		USER_STATUS("Tag not found");
     76		return false;
     77	}
     78
     79	link = list_at(tracks_vis, track_nav.sel);
     80	if (!link) {
     81		USER_STATUS("No track selected");
     82		return false;
     83	}
     84	track = tracks_vis_track(link);
     85
     86	if (track->tag == tag) {
     87		USER_STATUS("Same tag");
     88		return false;
     89	}
     90
     91	if (!track_move(track, tag)) {
     92		cmd_status_from_errno(errno);
     93		return false;
     94	}
     95
     96	return true;
     97}
     98
     99bool
    100cmd_copy(const char *name)
    101{
    102	struct list_link *link;
    103	struct track *track, *new;
    104	struct tag *tag;
    105	char *newpath;
    106
    107	tag = tag_find(name);
    108	if (!tag) {
    109		USER_STATUS("Tag not found");
    110		return false;
    111	}
    112
    113	link = list_at(tracks_vis, track_nav.sel);
    114	if (!link) {
    115		USER_STATUS("No track selected");
    116		return false;
    117	}
    118	track = tracks_vis_track(link);
    119
    120	if (track->tag == tag) {
    121		USER_STATUS("Same tag");
    122		return false;
    123	}
    124
    125	newpath = aprintf("%s/%s", tag->fpath, track->name);
    126	if (path_exists(newpath)) {
    127		free(newpath);
    128		USER_STATUS("File already exists");
    129		return false;
    130	}
    131
    132	if (!dup_file(track->fpath, newpath)) {
    133		free(newpath);
    134		USER_STATUS("Failed to copy track");
    135		return false;
    136	}
    137	free(newpath);
    138
    139	new = track_add(tag, track->name);
    140	if (!new) {
    141		rm_file(track->fpath);
    142		USER_STATUS("Failed to copy track");
    143		return false;
    144	}
    145
    146	return true;
    147}
    148
    149bool
    150cmd_reindex(const char *name)
    151{
    152	struct track *track;
    153	struct list_link *link;
    154	struct tag *tag;
    155	struct ref *ref;
    156	struct list matches;
    157	struct tag *playing_tag;
    158	char *playing_name;
    159	bool status;
    160
    161	status = false;
    162	playing_tag = NULL;
    163	playing_name = NULL;
    164	list_init(&matches);
    165
    166	if (!*name) {
    167		link = list_at(&tags, tag_nav.sel);
    168		if (!link) return false;
    169		tag = LIST_UPCAST(link, struct tag, link);
    170		ref = ref_alloc(tag);
    171		list_insert_back(&matches, &ref->link);
    172	} else if (!strcmp(name, "*")) {
    173		for (LIST_ITER(&tags, link)) {
    174			tag = LIST_UPCAST(link, struct tag, link);
    175			ref = ref_alloc(tag);
    176			list_insert_back(&matches, &ref->link);
    177		}
    178	} else {
    179		for (LIST_ITER(&tags, link)) {
    180			tag = LIST_UPCAST(link, struct tag, link);
    181			if (!strcmp(tag->name, name)) {
    182				ref = ref_alloc(tag);
    183				list_insert_back(&matches, &ref->link);
    184				break;
    185			}
    186		}
    187	}
    188
    189	if (list_empty(&matches))
    190		return false;
    191
    192	/* save old playing track */
    193	if (player.track) {
    194		playing_tag = player.track->tag;
    195		playing_name = astrdup(player.track->name);
    196		player.track = NULL;
    197	}
    198
    199	/* update each tag specified */
    200	for (LIST_ITER(&matches, link)) {
    201		ref = LIST_UPCAST(link, struct ref, link);
    202		if (!tag_reindex_tracks(ref->data))
    203			goto cleanup;
    204	}
    205
    206	/* try to find old playing track among reindexed tracks */
    207	if (playing_tag) {
    208		for (LIST_ITER(&playing_tag->tracks, link)) {
    209			track = LIST_UPCAST(link, struct track, link_tt);
    210			if (!strcmp(track->name, playing_name)) {
    211				player.track = track;
    212				break;
    213			}
    214		}
    215	}
    216
    217	status = true;
    218
    219cleanup:
    220	refs_free(&matches);
    221	free(playing_name);
    222
    223	return status;
    224}
    225
    226bool
    227cmd_add_tag(const char *name)
    228{
    229	struct tag *tag;
    230
    231	tag = tag_find(name);
    232	if (tag) {
    233		USER_STATUS("Tag already exists");
    234		return false;
    235	}
    236
    237	tag = tag_create(name);
    238	if (!tag) {
    239		USER_STATUS("Failed to create tag");
    240		return false;
    241	}
    242
    243	return true;
    244}
    245
    246bool
    247cmd_rm_tag(const char *name)
    248{
    249	struct list_link *link;
    250	struct tag *tag;
    251
    252	if (!*name) {
    253		link = list_at(&tags, tag_nav.sel);
    254		if (!link) return false;
    255		tag = LIST_UPCAST(link, struct tag, link);
    256	} else  {
    257		tag = tag_find(name);
    258		if (!tag) {
    259			USER_STATUS("No such tag");
    260			return false;
    261		}
    262	}
    263
    264	if (!tag_rm(tag, true)) {
    265		USER_STATUS("Failed to remove tag");
    266		return false;
    267	}
    268
    269	return true;
    270}
    271
    272bool
    273cmd_rename(const char *name)
    274{
    275	struct list_link *link;
    276	struct track *track;
    277	struct tag *tag;
    278
    279	if (!*name) {
    280		USER_STATUS("Supply a name");
    281		return false;
    282	}
    283
    284	ASSERT(pane_sel == cmd_pane);
    285
    286	if (pane_after_cmd == track_pane) {
    287		link = list_at(tracks_vis, track_nav.sel);
    288		if (!link) return false;
    289		track = tracks_vis_track(link);
    290		if (!track_rename(track, name))
    291			return false;
    292	} else if (pane_after_cmd == tag_pane) {
    293		link = list_at(&tags, tag_nav.sel);
    294		if (!link) return false;
    295		tag = LIST_UPCAST(link, struct tag, link);
    296		if (!tag_rename(tag, name))
    297			return false;
    298	}
    299
    300	return true;
    301}
    302
    303void
    304cmd_init(void)
    305{
    306	last_cmd = NULL;
    307	last_args = NULL;
    308}
    309
    310void
    311cmd_deinit(void)
    312{
    313	free(last_args);
    314}
    315
    316bool
    317cmd_run(const char *query, bool *found)
    318{
    319	const char *sep, *args;
    320	int i, cmdlen;
    321
    322	*found = false;
    323	sep = strchr(query, ' ');
    324	cmdlen = sep ? sep - query : strlen(query);
    325	for (i = 0; i < command_count; i++) {
    326		if (!strncmp(commands[i].name, query, cmdlen)) {
    327			last_cmd = &commands[i];
    328			args = sep ? sep + 1 : "";
    329
    330			free(last_args);
    331			last_args = astrdup(args);
    332
    333			*found = true;
    334			return commands[i].func(args);
    335		}
    336	}
    337
    338	return false;
    339}
    340
    341bool
    342cmd_rerun(void)
    343{
    344	if (!last_cmd || !last_args) {
    345		USER_STATUS("No command to repeat");
    346		return false;
    347	}
    348	return last_cmd->func(last_args);
    349}
    350
    351const struct cmd *
    352cmd_get(const char *name)
    353{
    354	int i;
    355
    356	for (i = 0; i < command_count; i++) {
    357		if (!strcmp(commands[i].name, name))
    358			return &commands[i];
    359	}
    360
    361	return NULL;
    362}
    363
    364const struct cmd *
    365cmd_find(const char *name)
    366{
    367	int i;
    368
    369	for (i = 0; i < command_count; i++) {
    370		if (strcmp(commands[i].name, name))
    371			return &commands[i];
    372	}
    373
    374	return NULL;
    375}