I18N-C += src/docs_inc.c
I18N-DOCS = $(wildcard docs/markdown/*.md)
I18N-DOCS += $(wildcard docs/class/*.md)
+I18N-DOCS += $(wildcard docs/property/*.md)
I18N-DOCS += $(wildcard docs/wizard/*.md)
MD-ROOT = $(patsubst docs/markdown/%.md,%,$(wildcard docs/markdown/*.md))
MD-CLASS = $(patsubst docs/class/%.md,%,$(wildcard docs/class/*.md))
+MD-PROP = $(patsubst docs/property/%.md,%,$(wildcard docs/property/*.md))
MD-WIZARD = $(patsubst docs/wizard/%.md,%,$(wildcard docs/wizard/*.md))
#
$(MD-TO-C) --in="docs/class/$${i}.md" \
--name="tvh_doc_$${i}_class" >> src/docs_inc.c || exit 1; \
done
+ @for i in $(MD-PROP); do \
+ echo "Markdown: docs/property/$${i}.md"; \
+ $(MD-TO-C) --in="docs/property/$${i}.md" \
+ --name="tvh_doc_$${i}_property" >> src/docs_inc.c || exit 1; \
+ done
@for i in $(MD-WIZARD); do \
echo "Markdown: docs/wizard/$${i}.md"; \
$(MD-TO-C) --in="docs/wizard/$${i}.md" \
--- /dev/null
+: Command to run after finishing a recording. The command will be run in
+ background and is executed even if a recording is aborted or an error
+ occurred. Use the %e error formatting string to check for errors, the
+ error string is “OK” if recording finished successfully.
+
+ Supported format strings:
+
+
+Format | Description | Example value
+:-----:| ----------------------------------------- | -------------
+`%f` | Full path to recording | /home/user/Videos/News.mkv
+`%b` | Basename of recording | News.mkv
+`%c` | Channel name | BBC world
+`%O` | Owner of this recording | user
+`%C` | Who created this recording | user
+`%t` | Program title | News
+`%s` | Program subtitle | Afternoon
+`%p` | Program episode | S02.E07
+`%d` | Program description | News and stories…
+`%e` | Error message | Aborted by user
+`%S` | Start time stamp of recording, UNIX epoch | 1224421200
+`%E` | Stop time stamp of recording, UNIX epoch | 1224426600
+`%r` | Number of errors during recording | 0
+`%R` | Number of data errors during recording | 6
+
+*Example usage*
+
+To use special characters (e.g. spaces), either put the string in quotes or
+escape the individual characters.
+
+```/path/to/ffmpeg -i "%f" -vcodec libx264 -acodec copy "/path/with white space/%b"```
+
return 0;
}
+static char *
+dvr_config_prop_pathname_doc(const struct property *p, const char *lang)
+{
+ extern const char *tvh_doc_postprocessor_property[];
+ return prop_md_doc(tvh_doc_postprocessor_property, lang);
+}
+
extern const char *tvh_doc_dvrconfig_class[];
const idclass_t dvr_config_class = {
.off = offsetof(dvr_config_t, dvr_retention_days),
.def.u32 = DVR_RET_ONREMOVE,
.list = dvr_config_class_retention_list,
- .opts = PO_EXPERT,
+ .opts = PO_EXPERT | PO_DOC_NLIST,
.group = 1,
},
{
.off = offsetof(dvr_config_t, dvr_removal_days),
.def.u32 = DVR_RET_FOREVER,
.list = dvr_config_class_removal_list,
+ .opts = PO_DOC_NLIST,
.group = 1,
},
{
"in the channel or DVR entry will be used."),
.off = offsetof(dvr_config_t, dvr_extra_time_pre),
.list = dvr_config_class_extra_list,
- .opts = PO_ADVANCED,
+ .opts = PO_ADVANCED | PO_DOC_NLIST,
.group = 1,
},
{
"stop time."),
.off = offsetof(dvr_config_t, dvr_extra_time_post),
.list = dvr_config_class_extra_list,
- .opts = PO_ADVANCED,
+ .opts = PO_ADVANCED | PO_DOC_NLIST,
.group = 1,
},
{
.off = offsetof(dvr_config_t, dvr_update_window),
.list = dvr_config_entry_class_update_window_list,
.def.u32 = 24*3600,
- .opts = PO_EXPERT,
+ .opts = PO_EXPERT | PO_DOC_NLIST,
.group = 1,
},
{
.desc = N_("The string allows you to manually specify the "
"full path generation using predefined "
"modifiers. See Help for full details."),
+ .doc = dvr_config_prop_pathname_doc,
.set = dvr_config_class_pathname_set,
.off = offsetof(dvr_config_t, dvr_pathname),
.opts = PO_EXPERT,
int idnode_write0 (idnode_t *self, htsmsg_t *m, int optmask, int dosave);
void idnode_save_check (idnode_t *self, int weak);
-#define idclass_serialize(idc, lang) idclass_serialize0(idc, NULL, 0, lang)
-#define idnode_serialize(in, lang) idnode_serialize0(in, NULL, 0, lang)
+#define idclass_serialize(idc, lang) idclass_serialize0(idc, NULL, 0, lang)
+#define idclass_serializedoc(idc, lang) idclass_serialize0(idc, NULL, PO_DOC, lang)
+#define idnode_serialize(in, lang) idnode_serialize0(in, NULL, 0, lang)
#define idnode_load(in, m) idnode_write0(in, m, PO_NOSAVE, 0)
#define idnode_save(in, m) idnode_read0(in, m, NULL, PO_NOSAVE | PO_USERAW, NULL)
#define idnode_update(in, m) idnode_write0(in, m, PO_RDONLY | PO_WRONCE, 1)
/* Metadata */
htsmsg_add_str(m, "caption", tvh_gettext_lang(lang, pl->name));
+ if ((optmask & PO_DOC) && pl->doc) {
+ char *s = pl->doc(pl, lang);
+ if (s) {
+ htsmsg_add_str(m, "doc", s);
+ free(s);
+ }
+ }
if (pl->desc)
htsmsg_add_str(m, "description", tvh_gettext_lang(lang, pl->desc));
if (pl->islist) {
htsmsg_add_bool(m, "multiline", 1);
if (opts & PO_PERSIST)
htsmsg_add_bool(m, "persistent", 1);
+ if ((optmask & PO_DOC) && (opts & PO_DOC_NLIST))
+ htsmsg_add_bool(m, "doc_nlist", 1);
/* Enum list */
if (pl->list) {
}
}
+/**
+ *
+ */
+char *
+prop_md_doc(const char **doc, const char *lang)
+{
+ const char *s;
+ char *r = NULL;
+ size_t l = 0;
+
+ for (; *doc; doc++) {
+ if (*doc[0] == '\xff') {
+ s = tvh_gettext_lang(lang, *doc + 1);
+ } else {
+ s = *doc;
+ }
+ if (r == NULL) {
+ r = strdup(s);
+ l = strlen(s);
+ } else {
+ l += strlen(s) + 1;
+ r = realloc(r, l);
+ strcat(r, s);
+ }
+ }
+ return r;
+}
+
+
/******************************************************************************
* Editor Configuration
*
#define PO_LORDER (1<<15) // Manage order in lists
#define PO_MULTILINE (1<<16) // Multiline string
#define PO_PERSIST (1<<17) // Persistent value (return back on save)
+#define PO_DOC (1<<18) // Use doc callback instead description if exists
+#define PO_DOC_NLIST (1<<19) // Do not show list in doc
/*
* min/max/step helpers
/* Extended options */
uint32_t (*get_opts) (void *ptr);
+ /* Documentation callback */
+ char *(*doc) ( const struct property *prop, const char *lang );
+
/* Notification callback */
void (*notify) (void *ptr, const char *lang);
return s64;
}
+char *
+prop_md_doc(const char **md, const char *lang);
+
#endif /* __TVH_PROP_H__ */
/******************************************************************************
return HTTP_STATUS_NOT_FOUND;
}
doc = ic->ic_doc;
- m = idclass_serialize(ic, lang);
+ m = idclass_serializedoc(ic, lang);
pthread_mutex_unlock(&global_lock);
s = htsmsg_get_str(m, "caption");
if (s) {
md_text(hq, ": ", " ", s);
md_nl(hq, 1);
}
- e = htsmsg_get_list(n, "enum");
- if (e) {
- HTSMSG_FOREACH(f2, e) {
- x = htsmsg_field_get_map(f2);
- if (x) {
- s = htsmsg_get_str(x, "val");
- } else {
- s = htsmsg_field_get_string(f2);
- }
- if (s) {
- md_nl(hq, 1);
- htsbuf_append(hq, " * ", 4);
- md_style(hq, "**", s);
+ s = htsmsg_get_str(n, "doc");
+ if (s) {
+ htsbuf_append_str(hq, s);
+ md_nl(hq, 1);
+ }
+ if (!htsmsg_get_bool_or_default(n, "doc_nlist", 0)) {
+ e = htsmsg_get_list(n, "enum");
+ if (e) {
+ HTSMSG_FOREACH(f2, e) {
+ x = htsmsg_field_get_map(f2);
+ if (x) {
+ s = htsmsg_get_str(x, "val");
+ } else {
+ s = htsmsg_field_get_string(f2);
+ }
+ if (s) {
+ md_nl(hq, 1);
+ htsbuf_append(hq, " * ", 4);
+ md_style(hq, "**", s);
+ }
}
+ md_nl(hq, 1);
}
- md_nl(hq, 1);
}
}
htsmsg_destroy(m);
selected: selected,
beforeedit: beforeedit,
help: function() {
- new tvheadend.help(_('DVR - Upcoming/Current Recordings'), 'dvr_upcoming.html');
+ new tvheadend.mdhelp('class/dvrentry');
}
});
tbar: [downloadButton, rerecordButton, moveButton],
selected: selected,
help: function() {
- new tvheadend.help(_('DVR - Finished Recordings'), 'dvr_finished.html');
+ new tvheadend.mdhelp('class/dvrentry');
}
});
tbar: [downloadButton, rerecordButton, moveButton],
selected: selected,
help: function() {
- new tvheadend.help(_('DVR - Failed Recordings'), 'dvr_failed.html');
+ new tvheadend.mdhelp('class/dvrentry');
}
});
},
del: true,
help: function() {
- new tvheadend.help(_('DVR'), 'config_dvr.html');
+ new tvheadend.mdhelp('class/dvrconfig');
}
});
direction: 'ASC'
},
help: function() {
- new tvheadend.help(_('DVR Autorec'), 'dvr_autorec.html');
+ new tvheadend.mdhelp('class/dvrautorec');
}
});
direction: 'ASC'
},
help: function() {
- new tvheadend.help(_('DVR Timers'), 'dvr_timerec.html');
+ new tvheadend.mdhelp('class/dvrtimerec');
}
});