X-Git-Url: http://git.tuebingen.mpg.de/?a=blobdiff_plain;ds=sidebyside;f=aft.c;h=f8e8f40b5013b300dad0c05abdce189639a42731;hb=f13efdc785f972e74299420d051f264cf2da9bb4;hp=0b07fa17145bcabfb48a0dc2ac3d277b62ece897;hpb=c91ff5bca6a9161354e9baf85423d1498c832696;p=paraslash.git diff --git a/aft.c b/aft.c index 0b07fa17..f8e8f40b 100644 --- a/aft.c +++ b/aft.c @@ -1,3 +1,11 @@ +/* + * Copyright (C) 2007 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ + +/** \file aft.c Audio file table functions. */ + #include "para.h" #include "error.h" #include @@ -8,10 +16,112 @@ #include "string.h" #include "vss.h" -#define AFS_AUDIO_FILE_DIR "/home/mp3" +#define AFS_AUDIO_FILE_DIR "/home/mp3" /* FIXME: Use cwd instead */ static struct osl_table *audio_file_table; +/** The different sorting methods of the ls command. */ +enum ls_sorting_method { + /** -sp (default) */ + LS_SORT_BY_PATH, + /** -ss */ + LS_SORT_BY_SCORE, + /** -sl */ + LS_SORT_BY_LAST_PLAYED, + /** -sn */ + LS_SORT_BY_NUM_PLAYED, + /** -sf */ + LS_SORT_BY_FREQUENCY, + /** -sc */ + LS_SORT_BY_CHANNELS, + /** -si */ + LS_SORT_BY_IMAGE_ID, + /** -sy */ + LS_SORT_BY_LYRICS_ID, + /** -sb */ + LS_SORT_BY_BITRATE, + /** -sd */ + LS_SORT_BY_DURATION, + /** -sa */ + LS_SORT_BY_AUDIO_FORMAT, + /** -sh */ + LS_SORT_BY_HASH, +}; + +/** The different listing modes of the ls command. */ +enum ls_listing_mode { + /** Default listing mode. */ + LS_MODE_SHORT, + /** -l or -ll */ + LS_MODE_LONG, + /** -lv */ + LS_MODE_VERBOSE, + /** -lm */ + LS_MODE_MBOX +}; + +/** The flags accepted by the ls command. */ +enum ls_flags { + /** -p */ + LS_FLAG_FULL_PATH = 1, + /** -a */ + LS_FLAG_ADMISSIBLE_ONLY = 2, + /** -r */ + LS_FLAG_REVERSE = 4, +}; + +/** + * The size of the individual output fields of the ls command. + * + * These depend on the actual content being listed. If, for instance only files + * with duration less than an hour are being listed, then the duration with is + * made smaller because then the duration is listed as mm:ss rather than + * hh:mm:ss. + */ +struct ls_widths { + /** size of the score field. */ + unsigned short score_width; + /** size of the image id field. */ + unsigned short image_id_width; + /** size of the lyrics id field. */ + unsigned short lyrics_id_width; + /** size of the bitrate field. */ + unsigned short bitrate_width; + /** size of the frequency field. */ + unsigned short frequency_width; + /** size of the duration field. */ + unsigned short duration_width; + /** size of the num played field. */ + unsigned short num_played_width; +}; + +/** Data passed to the different compare functions (called by qsort()). */ +struct ls_data { + /** Usual audio format handler information. */ + struct audio_format_info afhi; + /** Audio file selector information. */ + struct afs_info afsi; + /** The full path of the audio file. */ + char *path; + /** The score value (if -a was given). */ + long score; + /** The sha1 hash of audio file. */ + HASH_TYPE *hash; +}; + +struct ls_options { + unsigned flags; + enum ls_sorting_method sorting; + enum ls_listing_mode mode; + char **patterns; + int num_patterns; + struct ls_widths widths; + uint32_t array_size; + uint32_t num_matching_paths; + struct ls_data *data; + struct ls_data **data_ptr; +}; + /** * Describes the layout of the mmapped-afs info struct. * @@ -376,7 +486,7 @@ int aft_get_row_of_hash(HASH_TYPE *hash, struct osl_row **row) * * \return The return value of the underlying call to osl_get_object(). */ -int get_afsi_object_of_row(const void *row, struct osl_object *obj) +int get_afsi_object_of_row(const struct osl_row *row, struct osl_object *obj) { return osl_get_object(audio_file_table, row, AFTCOL_AFSI, obj); } @@ -445,7 +555,7 @@ int get_audio_file_path_of_row(const struct osl_row *row, char **path) * * \sa get_hash_of_row(). */ -int get_hash_object_of_aft_row(const void *row, struct osl_object *obj) +static int get_hash_object_of_aft_row(const struct osl_row *row, struct osl_object *obj) { return osl_get_object(audio_file_table, row, AFTCOL_HASH, obj); } @@ -461,7 +571,7 @@ int get_hash_object_of_aft_row(const void *row, struct osl_object *obj) * \return The return value of the underlying call to * get_hash_object_of_aft_row(). */ -static int get_hash_of_row(const void *row, HASH_TYPE **hash) +static int get_hash_of_row(const struct osl_row *row, HASH_TYPE **hash) { struct osl_object obj; int ret = get_hash_object_of_aft_row(row, &obj); @@ -482,7 +592,7 @@ static int get_hash_of_row(const void *row, HASH_TYPE **hash) * * \sa get_chunk_table_of_row(). */ -int get_afhi_of_row(const void *row, struct audio_format_info *afhi) +static int get_afhi_of_row(const struct osl_row *row, struct audio_format_info *afhi) { struct osl_object obj; int ret = osl_get_object(audio_file_table, row, AFTCOL_AFHI, @@ -503,7 +613,7 @@ int get_afhi_of_row(const void *row, struct audio_format_info *afhi) * * \sa get_afhi_of_row(). */ -int get_chunk_table_of_row(const void *row, struct audio_format_info *afhi) +static int get_chunk_table_of_row(const struct osl_row *row, struct audio_format_info *afhi) { struct osl_object obj; int ret = osl_open_disk_object(audio_file_table, row, AFTCOL_CHUNKS, @@ -572,15 +682,14 @@ err: return ret; } -time_t now; - -static int get_local_time(uint64_t *seconds, char *buf, size_t size) +static int get_local_time(uint64_t *seconds, char *buf, size_t size, + time_t current_time) { struct tm t; if (!localtime_r((time_t *)seconds, &t)) return -E_LOCALTIME; - if (*seconds + 6 * 30 * 24 * 3600 > now) { + if (*seconds + 6 * 30 * 24 * 3600 > current_time) { if (!strftime(buf, size, "%b %e %k:%M", &t)) return -E_STRFTIME; return 1; @@ -654,7 +763,7 @@ static char *make_image_line(struct afs_info *afsi) } static int print_list_item(struct ls_data *d, struct ls_options *opts, - struct para_buffer *b) + struct para_buffer *b, time_t current_time) { int ret; char att_buf[65]; @@ -672,7 +781,7 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, } get_attribute_bitmap(&afsi->attributes, att_buf); ret = get_local_time(&afsi->last_played, last_played_time, - sizeof(last_played_time)); + sizeof(last_played_time), current_time); if (ret < 0) return ret; get_duration_buf(afhi->seconds_total, duration_buf, w->duration_width); @@ -734,7 +843,8 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, "channels: %d\n" "duration: %s\n" "num_played: %d\n" - "last_played: %s\n\n", + "last_played: %s\n" + "tag info: %s\n", (opts->flags & LS_FLAG_FULL_PATH)? "path" : "file", d->path, have_score? "score: " : "", score_buf, @@ -749,7 +859,8 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, afhi->channels, duration_buf, afsi->num_played, - last_played_time + last_played_time, + afhi->info_string ); free(att_line); free(lyrics_line); @@ -828,7 +939,7 @@ static int ls_path_compare(const void *a, const void *b) static int sort_matching_paths(struct ls_options *options) { size_t nmemb = options->num_matching_paths; - size_t size = sizeof(uint32_t); + size_t size = sizeof(*options->data_ptr); int (*compar)(const void *, const void *); int i; @@ -963,6 +1074,8 @@ static int com_ls_callback(const struct osl_object *query, char *p, *pattern_start = (char *)query->data + sizeof(*opts); struct para_buffer b = {.buf = NULL, .size = 0}; int i = 0, ret; + time_t current_time; + PARA_NOTICE_LOG("%d patterns\n", opts->num_patterns); if (opts->num_patterns) { @@ -989,15 +1102,16 @@ static int com_ls_callback(const struct osl_object *query, ret = sort_matching_paths(opts); if (ret < 0) goto out; + time(¤t_time); if (opts->flags & LS_FLAG_REVERSE) for (i = opts->num_matching_paths - 1; i >= 0; i--) { - ret = print_list_item(opts->data_ptr[i], opts, &b); + ret = print_list_item(opts->data_ptr[i], opts, &b, current_time); if (ret < 0) break; } else for (i = 0; i < opts->num_matching_paths; i++) { - ret = print_list_item(opts->data_ptr[i], opts, &b); + ret = print_list_item(opts->data_ptr[i], opts, &b, current_time); if (ret < 0) break; } @@ -1013,7 +1127,7 @@ out: } /* - * TODO: flags -h (sort by hash) + * TODO: flags -h (sort by hash) -lm (list in mbox format) * * long list: list hash, attributes as (xx--x-x-), file size, lastplayed * full list: list everything, including afsi, afhi, atts as clear text @@ -1117,7 +1231,6 @@ int com_afs_ls(int fd, int argc, char * const * const argv) } return -E_AFT_SYNTAX; } - time(&now); opts.flags = flags; opts.sorting = sort; opts.mode = mode; @@ -1326,7 +1439,7 @@ static int com_add_callback(const struct osl_object *query, return ret; } if (hs || pb) { /* (hs != NULL and pb != NULL) implies hs == pb */ - const void *row = pb? pb : hs; + const struct osl_row *row = pb? pb : hs; /* update afhi and chunk_table */ if (flags & ADD_FLAG_VERBOSE) PARA_DEBUG_LOG("updating audio format handler info (%zd bytes)\n", @@ -1694,6 +1807,54 @@ err: return ret; } +/* TODO: optionally fix problems by removing offending rows */ +static int check_audio_file(struct osl_row *row, void *data) +{ + char *path; + struct para_buffer *pb = data; + struct stat statbuf; + int ret = get_audio_file_path_of_row(row, &path); + struct afs_info afsi; + char *blob_name; + + if (ret < 0) { + para_printf(pb, "%s\n", PARA_STRERROR(-ret)); + return 1; + } + if (stat(path, &statbuf) < 0) + para_printf(pb, "%s: stat error (%s)\n", path, strerror(errno)); + else { + if (!S_ISREG(statbuf.st_mode)) + para_printf(pb, "%s: not a regular file\n", path); + } + ret = get_afsi_of_row(row, &afsi); + if (ret < 0) { + para_printf(pb, "%s: %s\n", path, PARA_STRERROR(-ret)); + return 1; + } + ret = lyr_get_name_by_id(afsi.lyrics_id, &blob_name); + if (ret < 0) + para_printf(pb, "%s lyrics id %u: %s\n", path, afsi.lyrics_id, + PARA_STRERROR(-ret)); + ret = img_get_name_by_id(afsi.image_id, &blob_name); + if (ret < 0) + para_printf(pb, "%s image id %u: %s\n", path, afsi.image_id, + PARA_STRERROR(-ret)); + return 1; +} + +int aft_check_callback(__a_unused const struct osl_object *query, struct osl_object *result) +{ + struct para_buffer pb = {.buf = NULL}; + + para_printf(&pb, "checking audio file table...\n"); + audio_file_loop(&pb, check_audio_file); + result->data = pb.buf; + result->size = pb.size; + return 1; + +} + /** * Close the audio file table. * @@ -1723,10 +1884,9 @@ int aft_init(struct table_info *ti, const char *db) audio_file_table_desc.dir = db; ti->desc = &audio_file_table_desc; - ret = osl_open_table(ti->desc, &ti->table); + ret = osl_open_table(ti->desc, &audio_file_table); if (ret >= 0) { unsigned num; - audio_file_table = ti->table; osl_get_num_rows(audio_file_table, &num); PARA_INFO_LOG("audio file table contains %d files\n", num); return ret;