H: This adds new attributes to the attribute table. At most 64
H: attributes may be defined.
---
-N: touch
-P: AFS_READ | AFS_WRITE
-D: Manipulate the afs entry of audio files.
-U: touch [-n=numplayed] [-l=lastplayed] [-y=lyrics_id] [-i=image_id] [-a=amp] [-v] [-p] pattern
-H: If no option is given, the lastplayed field is set to the current time
-H: and the value of the numplayed field is increased by one. Otherwise,
-H: only the given options are taken into account.
-H:
-H: Options:
-H:
-H: -n Set the numplayed count, i.e. the number of times this audio
-H: file was selected for streaming so far.
-H:
-H: -l Set the lastplayed time, i.e. the last time this audio file was
-H: selected for streaming. The argument must be a number of seconds
-H: since the epoch. Example:
-H:
-H: touch -l=$(date +%s) file
-H:
-H: sets the lastplayed time of 'file' to the current time.
-H:
-H: -y Set the lyrics ID which specifies the lyrics data file associated
-H: with the audio file.
-H:
-H: -i Like -y, but sets the image ID.
-H:
-H: -a Set the amplification value (0-255). This determines a scaling
-H: factor by which the amplitude should be multiplied in order to
-H: normalize the volume of the audio file. A value of zero means
-H: no amplification, 64 means the amplitude should be multiplied
-H: by a factor of two, 128 by three and so on.
-H:
-H: This value is used by the amp filter.
-H:
-H: -v Verbose mode. Explain what is being done.
-H:
-H: -p Pathname match. Match a slash in the path only with a slash
-H: in pattern and not by an asterisk (*) or a question mark
-H: (?) metacharacter, nor by a bracket expression ([]) containing
-H: a slash (see fnmatch(3)).
----
T: add
N: add@member@
O: int com_add@member@(struct command_context *cc);
TOUCH_FLAG_VERBOSE = 2
};
-/** Options used by com_touch(). */
-struct com_touch_options {
- /** New num_played value. */
- int32_t num_played;
- /** New last played count. */
- int64_t last_played;
- /** New lyrics id. */
- int32_t lyrics_id;
- /** New image id. */
- int32_t image_id;
- /** New amplification value. */
- int32_t amp;
- /** Command line flags (see \ref touch_flags). */
- unsigned flags;
-};
-
static int touch_audio_file(__a_unused struct osl_table *table,
struct osl_row *row, const char *name, void *data)
{
struct afs_callback_arg *aca = data;
- struct com_touch_options *cto = aca->query.data;
+ bool v_given = SERVER_CMD_OPT_GIVEN(TOUCH, VERBOSE, aca->lpr);
+ const struct lls_opt_result *r_n, *r_l, *r_i, *r_y, *r_a;
+ int ret;
struct osl_object obj;
struct afs_info old_afsi, new_afsi;
- int ret, no_options = cto->num_played < 0 && cto->last_played < 0 &&
- cto->lyrics_id < 0 && cto->image_id < 0 && cto->amp < 0;
+ bool no_options;
struct afsi_change_event_data aced;
+ r_n = SERVER_CMD_OPT_RESULT(TOUCH, NUMPLAYED, aca->lpr);
+ r_l = SERVER_CMD_OPT_RESULT(TOUCH, LASTPLAYED, aca->lpr);
+ r_i = SERVER_CMD_OPT_RESULT(TOUCH, IMAGE_ID, aca->lpr);
+ r_y = SERVER_CMD_OPT_RESULT(TOUCH, LYRICS_ID, aca->lpr);
+ r_a = SERVER_CMD_OPT_RESULT(TOUCH, AMP, aca->lpr);
+ no_options = !lls_opt_given(r_n) && !lls_opt_given(r_l) && !lls_opt_given(r_i)
+ && !lls_opt_given(r_y) && !lls_opt_given(r_a);
+
ret = get_afsi_object_of_row(row, &obj);
if (ret < 0) {
para_printf(&aca->pbout, "cannot touch %s\n", name);
if (no_options) {
new_afsi.num_played++;
new_afsi.last_played = time(NULL);
- if (cto->flags & TOUCH_FLAG_VERBOSE)
+ if (v_given)
para_printf(&aca->pbout, "%s: num_played = %u, "
"last_played = now()\n", name,
new_afsi.num_played);
} else {
- if (cto->flags & TOUCH_FLAG_VERBOSE)
+ if (lls_opt_given(r_l))
+ new_afsi.last_played = lls_uint64_val(0, r_l);
+ if (lls_opt_given(r_n))
+ new_afsi.num_played = lls_uint32_val(0, r_n);
+ if (lls_opt_given(r_i))
+ new_afsi.image_id = lls_uint32_val(0, r_i);
+ if (lls_opt_given(r_y))
+ new_afsi.lyrics_id = lls_uint32_val(0, r_y);
+ if (lls_opt_given(r_a))
+ new_afsi.amp = lls_uint32_val(0, r_a);
+ if (v_given)
para_printf(&aca->pbout, "touching %s\n", name);
- if (cto->lyrics_id >= 0)
- new_afsi.lyrics_id = cto->lyrics_id;
- if (cto->image_id >= 0)
- new_afsi.image_id = cto->image_id;
- if (cto->num_played >= 0)
- new_afsi.num_played = cto->num_played;
- if (cto->last_played >= 0)
- new_afsi.last_played = cto->last_played;
- if (cto->amp >= 0)
- new_afsi.amp = cto->amp;
}
save_afsi(&new_afsi, &obj); /* in-place update */
aced.aft_row = row;
static int com_touch_callback(struct afs_callback_arg *aca)
{
+ const struct lls_command *cmd = SERVER_CMD_CMD_PTR(TOUCH);
+ bool p_given;
+ const struct lls_opt_result *r_i, *r_y;
int ret;
- struct com_touch_options *cto = aca->query.data;
struct pattern_match_data pmd = {
.table = audio_file_table,
.loop_col_num = AFTCOL_HASH,
.match_col_num = AFTCOL_PATH,
- .patterns = {
- .data = (char *)aca->query.data
- + sizeof(struct com_touch_options),
- .size = aca->query.size
- - sizeof(struct com_touch_options)
- },
.data = aca,
.action = touch_audio_file
};
- if (cto->image_id >= 0) {
- ret = img_get_name_by_id(cto->image_id, NULL);
+
+ ret = lls_deserialize_parse_result(aca->query.data, cmd, &aca->lpr);
+ assert(ret >= 0);
+ pmd.lpr = aca->lpr;
+
+ r_i = SERVER_CMD_OPT_RESULT(TOUCH, IMAGE_ID, aca->lpr);
+ if (lls_opt_given(r_i)) {
+ uint32_t id = lls_uint32_val(0, r_i);
+ ret = img_get_name_by_id(id, NULL);
if (ret < 0) {
- para_printf(&aca->pbout, "invalid image ID: %d\n",
- cto->image_id);
+ para_printf(&aca->pbout, "invalid image ID: %u\n", id);
return ret;
}
}
- if (cto->lyrics_id >= 0) {
- ret = lyr_get_name_by_id(cto->lyrics_id, NULL);
+ r_y = SERVER_CMD_OPT_RESULT(TOUCH, LYRICS_ID, aca->lpr);
+ if (lls_opt_given(r_y)) {
+ uint32_t id = lls_uint32_val(0, r_y);
+ ret = lyr_get_name_by_id(id, NULL);
if (ret < 0) {
- para_printf(&aca->pbout, "invalid lyrics ID: %d\n",
- cto->lyrics_id);
+ para_printf(&aca->pbout, "invalid lyrics ID: %u\n", id);
return ret;
}
}
- if (cto->flags & TOUCH_FLAG_FNM_PATHNAME)
+ p_given = SERVER_CMD_OPT_GIVEN(TOUCH, PATHNAME_MATCH, aca->lpr);
+ if (p_given)
pmd.fnmatch_flags |= FNM_PATHNAME;
ret = for_each_matching_row(&pmd);
if (ret >= 0 && pmd.num_matches == 0)
ret = -E_NO_MATCH;
+ lls_free_parse_result(aca->lpr, cmd);
return ret;
}
-int com_touch(struct command_context *cc)
+static int com_touch(struct command_context *cc, struct lls_parse_result *lpr)
{
- struct com_touch_options cto = {
- .num_played = -1,
- .last_played = -1,
- .lyrics_id = -1,
- .image_id = -1,
- .amp = -1,
- };
- struct osl_object query = {.data = &cto, .size = sizeof(cto)};
- int i, ret;
-
+ const struct lls_command *cmd = SERVER_CMD_CMD_PTR(TOUCH);
+ int ret;
+ char *errctx;
- for (i = 1; i < cc->argc; i++) {
- const char *arg = cc->argv[i];
- if (arg[0] != '-')
- break;
- if (!strcmp(arg, "--")) {
- i++;
- break;
- }
- if (!strncmp(arg, "-n=", 3)) {
- ret = para_atoi32(arg + 3, &cto.num_played);
- if (ret < 0)
- return ret;
- continue;
- }
- if (!strncmp(arg, "-l=", 3)) {
- ret = para_atoi64(arg + 3, &cto.last_played);
- if (ret < 0)
- return ret;
- continue;
- }
- if (!strncmp(arg, "-y=", 3)) {
- ret = para_atoi32(arg + 3, &cto.lyrics_id);
- if (ret < 0)
- return ret;
- continue;
- }
- if (!strncmp(arg, "-i=", 3)) {
- ret = para_atoi32(arg + 3, &cto.image_id);
- if (ret < 0)
- return ret;
- continue;
- }
- if (!strncmp(arg, "-a=", 3)) {
- int32_t val;
- ret = para_atoi32(arg + 3, &val);
- if (ret < 0)
- return ret;
- if (val < 0 || val > 255)
- return -ERRNO_TO_PARA_ERROR(EINVAL);
- cto.amp = val;
- continue;
- }
- if (!strcmp(arg, "-p")) {
- cto.flags |= TOUCH_FLAG_FNM_PATHNAME;
- continue;
- }
- if (!strcmp(arg, "-v")) {
- cto.flags |= TOUCH_FLAG_VERBOSE;
- continue;
- }
- break; /* non-option starting with dash */
+ ret = lls(lls_check_arg_count(lpr, 1, INT_MAX, &errctx));
+ if (ret < 0) {
+ send_errctx(cc, errctx);
+ return ret;
}
- if (i >= cc->argc)
- return -E_AFT_SYNTAX;
- return send_option_arg_callback_request(&query, cc->argc - i,
- cc->argv + i, com_touch_callback, afs_cb_result_handler, cc);
+ return send_lls_callback_request(com_touch_callback, cmd, lpr, cc);
}
+EXPORT_SERVER_CMD_HANDLER(touch);
static int remove_audio_file(__a_unused struct osl_table *table,
struct osl_row *row, const char *name, void *data)
necessary to send SIGKILL.
[/description]
+[subcommand touch]
+ purpose = manipulate the afs information of audio files
+ non-opts-name = pattern...
+ aux_info = AFS_READ | AFS_WRITE
+ [description]
+ This command modifies the afs info structure of all rows of the audio
+ file table whose path matches at least one of the given patters.
+
+ If at least one option is given which takes a number as its argument,
+ only those fields of the afs info structure are updated which
+ correspond to the given options while all other fields stay unmodified.
+
+ If no such option is given, the lastplayed field is set to the current
+ time and the value of the numplayed field is increased by one while
+ all other fields are left unchanged. This mimics what happens when
+ the virtual streaming system selects the file for streaming.
+
+ If the file is admissible for the current mood (or contained in the
+ current playlist), its score is recomputed according to the changed
+ values.
+ [/description]
+ [option numplayed]
+ short_opt = n
+ summary = set the numplayed count manually
+ arg_type = uint32
+ arg_info = required_arg
+ typestr = num
+ [help]
+ The numplayed count of an audio file is the number of times the file
+ was selected for streaming. It is one of the inputs to the scoring
+ function which determines the order in which admissible files are
+ streamed.
+
+ The virtual streaming system increases this number automatically each
+ time it opens the file for streaming.
+ [/help]
+ [option lastplayed]
+ short_opt = l
+ summary = set the lastplayed time manually
+ arg_type = uint64
+ arg_info = required_arg
+ typestr = num
+ [help]
+ The lastplayed time of an audio file is the time when the file was
+ last opened for streaming.
+
+ Like the numplayed count, it is an input for the scoring function
+ and is updated automatically by the virtual streaming system.
+
+ The argument must be a number of seconds since the epoch. Example:
+
+ touch -l=$(date +%s) file
+
+ sets the lastplayed time of 'file' to the current time.
+ [/help]
+ [option image-id]
+ short_opt = i
+ summary = set the image id
+ arg_type = uint32
+ arg_info = required_arg
+ typestr = num
+ [help]
+ The afs info structure of each row of the audio file table contains
+ a slot for the image id of the audio file that corresponds to the
+ row. The image id stored in this slot refers to the key in the image
+ table that identifies the blob.
+
+ When a new audio file is added to the audio file table, its image
+ id starts out as zero, indicating that there is no image associated
+ with the file. Setting the image id to a non-zero number associates
+ the file with a particular blob of the image table, for example the
+ cover art of the album in jpg format.
+ [/help]
+ [option lyrics-id]
+ short_opt = y
+ summary = set the lyrics id
+ arg_type = uint32
+ arg_info = required_arg
+ typestr = num
+ [help]
+ This option works just like --image-id, but sets the lyrics ID rather
+ than the image id.
+ [/help]
+ [option amp]
+ short_opt = a
+ summary = set the amplification value (0-255)
+ arg_type = uint32
+ arg_info = required_arg
+ typestr = num
+ [help]
+ The amplification value of an audio file is a number which is stored
+ in the afs info structure.
+
+ The value determines the scaling factor by which the amplitude of
+ the decoded samples should be multiplied in order to normalize the
+ volume. A value of zero means no amplification, 64 means the amplitude
+ should be multiplied by a factor of two, 128 by three and so on.
+
+ The amp filter of para_audiod amplifies the volume according to
+ this value.
+ [/help]
+ [option verbose]
+ short_opt = v
+ summary = explain what is being done
+ [option pathname-match]
+ short_opt = p
+ summary = modify matching behaviour
+ [help]
+ Match a slash in the path only with a slash in pattern and not by an
+ asterisk (*) or a question mark (?) metacharacter, nor by a bracket
+ expression ([]) containing a slash (see fnmatch(3)).
+ [/help]
+
[subcommand version]
purpose = print the git version string of para_server
aux_info = NO_PERMISSION_REQUIRED