Project

General

Profile

RE: XMLTV limited output/conversion ยป xmltv-reduce.patch

Reduce size of output xmltv - Em Smith, 2019-05-01 18:22

View differences:

docs/property/htsp_output_format.md
1
:
2

3
Option                           | Description
4
---------------------------------|------------
5
**All**                          | Include all information.
6
**Basic**                        | Limited information for low memory devices.
7

8
This setting can be overridden on a per-user basis, see [Access Entries](class/access).
docs/property/xmltv_output_format.md
1
:
2

3
Option                           | Description
4
---------------------------------|------------
5
**All**                          | Include all information.
6
**Basic**                        | Limited information for low memory devices.
7
**Basic Alternative (No Hash)**  | Limited information for low memory devices that don't correctly process tv channel names.
8

9
This setting can be overridden on a per-user basis, see [Access Entries](class/access).
src/access.c
292 292
    dst->aa_chtags_exclude = htsmsg_copy(src->aa_chtags_exclude);
293 293
  if (src->aa_auth)
294 294
    dst->aa_auth = strdup(src->aa_auth);
295
  dst->aa_xmltv_output_format = src->aa_xmltv_output_format;
296
  dst->aa_htsp_output_format = src->aa_htsp_output_format;
295 297
  return dst;
296 298
}
297 299

......
687 689
    else
688 690
      a->aa_rights |= ae->ae_rights;
689 691
  }
692

693
  a->aa_xmltv_output_format = ae->ae_xmltv_output_format;
694
  a->aa_htsp_output_format = ae->ae_htsp_output_format;
690 695
}
691 696

692 697
/**
......
1412 1417
  return strtab2htsmsg(conn_limit_type_tab, 1, lang);
1413 1418
}
1414 1419

1420
static htsmsg_t *
1421
access_entry_xmltv_output_format_enum ( void *p, const char *lang )
1422
{
1423
  static struct strtab
1424
  xmltv_output_format_tab[] = {
1425
    { N_("All"),                           ACCESS_XMLTV_OUTPUT_FORMAT_ALL },
1426
    { N_("Basic"),                         ACCESS_XMLTV_OUTPUT_FORMAT_BASIC },
1427
    { N_("Basic Alternative (No Hash)"),   ACCESS_XMLTV_OUTPUT_FORMAT_BASIC_NO_HASH },
1428
  };
1429
  return strtab2htsmsg(xmltv_output_format_tab, 1, lang);
1430
}
1431

1432
static htsmsg_t *
1433
access_entry_htsp_output_format_enum ( void *p, const char *lang )
1434
{
1435
  static struct strtab
1436
  htsp_output_format_tab[] = {
1437
    { N_("All"),                           ACCESS_HTSP_OUTPUT_FORMAT_ALL },
1438
    { N_("Basic"),                         ACCESS_HTSP_OUTPUT_FORMAT_BASIC },
1439
  };
1440
  return strtab2htsmsg(htsp_output_format_tab, 1, lang);
1441
}
1442

1415 1443
htsmsg_t *
1416 1444
language_get_list ( void *obj, const char *lang )
1417 1445
{
......
1656 1684
PROP_DOC(persistent_viewlevel)
1657 1685
PROP_DOC(streaming_profile)
1658 1686
PROP_DOC(change_parameters)
1687
PROP_DOC(xmltv_output_format)
1688
PROP_DOC(htsp_output_format)
1659 1689

1660 1690
const idclass_t access_entry_class = {
1661 1691
  .ic_class      = "access",
......
1903 1933
      .rend     = access_entry_chtag_rend,
1904 1934
      .opts     = PO_ADVANCED,
1905 1935
    },
1936
    {
1937
      .type     = PT_INT,
1938
      .id       = "xmltv_output_format",
1939
      .name     = N_("Format for xmltv output"),
1940
      .desc     = N_("Specify format for xmltv output."),
1941
      .doc      = prop_doc_xmltv_output_format,
1942
      .off      = offsetof(access_entry_t, ae_xmltv_output_format),
1943
      .list     = access_entry_xmltv_output_format_enum,
1944
      .opts     = PO_ADVANCED | PO_DOC_NLIST,
1945
    },
1946
    {
1947
      .type     = PT_INT,
1948
      .id       = "htsp_output_format",
1949
      .name     = N_("Format for htsp output"),
1950
      .desc     = N_("Specify format for htsp output."),
1951
      .doc      = prop_doc_htsp_output_format,
1952
      .off      = offsetof(access_entry_t, ae_htsp_output_format),
1953
      .list     = access_entry_htsp_output_format_enum,
1954
      .opts     = PO_ADVANCED | PO_DOC_NLIST,
1955
    },
1906 1956
    {
1907 1957
      .type     = PT_STR,
1908 1958
      .id       = "comment",
src/access.h
94 94
  ACCESS_CONN_LIMIT_TYPE_DVR,
95 95
};
96 96

97
enum {
98
  ACCESS_XMLTV_OUTPUT_FORMAT_ALL = 0,
99
  ACCESS_XMLTV_OUTPUT_FORMAT_BASIC,
100
  ACCESS_XMLTV_OUTPUT_FORMAT_BASIC_NO_HASH,
101
};
102

103
enum {
104
  ACCESS_HTSP_OUTPUT_FORMAT_ALL = 0,
105
  ACCESS_HTSP_OUTPUT_FORMAT_BASIC,
106
};
107

97 108
typedef struct access_entry {
98 109
  idnode_t ae_id;
99 110

......
124 135
  int ae_conn_limit_type;
125 136
  uint32_t ae_conn_limit;
126 137
  int ae_change_conn_limit;
138
  int ae_xmltv_output_format;
139
  int ae_htsp_output_format;
127 140

128 141
  int ae_dvr;
129 142
  int ae_htsp_dvr;
......
171 184
  htsmsg_t *aa_chtags;
172 185
  int       aa_match;
173 186
  uint32_t  aa_conn_limit;
187
  uint32_t  aa_xmltv_output_format;
188
  uint32_t  aa_htsp_output_format;
174 189
  uint32_t  aa_conn_limit_streaming;
175 190
  uint32_t  aa_conn_limit_dvr;
176 191
  uint32_t  aa_conn_streaming;
src/channels.c
820 820
 * *************************************************************************/
821 821

822 822
const char *
823
channel_get_name ( channel_t *ch, const char *blank )
823
channel_get_name ( const channel_t *ch, const char *blank )
824 824
{
825 825
  const char *s;
826
  idnode_list_mapping_t *ilm;
826
  const idnode_list_mapping_t *ilm;
827 827
  if (ch->ch_name && *ch->ch_name) return ch->ch_name;
828 828
  LIST_FOREACH(ilm, &ch->ch_services, ilm_in2_link)
829 829
    if ((s = service_get_channel_name((service_t *)ilm->ilm_in1)))
src/channels.h
181 181

182 182
int channel_tag_access(channel_tag_t *ct, struct access *a, int disabled);
183 183

184
const char *channel_get_name ( channel_t *ch, const char *blank );
184
const char *channel_get_name ( const channel_t *ch, const char *blank );
185 185
int channel_set_name ( channel_t *ch, const char *name );
186 186
/// User API convenience function to rename all channels that
187 187
/// match "from". Lock must be held prior to call.
src/htsp_server.c
1237 1237
  epg_episode_num_t epnum;
1238 1238
  const char *str;
1239 1239
  char buf[512];
1240
  const int of = htsp->htsp_granted_access->aa_htsp_output_format;
1240 1241

1241 1242
  /* Ignore? */
1242 1243
  if (update && e->updated <= update) return NULL;
......
1253 1254
  htsmsg_add_s64(out, "stop", e->stop);
1254 1255
  if ((str = epg_broadcast_get_title(e, lang)))
1255 1256
    htsmsg_add_str(out, "title", str);
1256
  if (htsp->htsp_version < 32) {
1257
    if ((str = epg_broadcast_get_description(e, lang))) {
1258
      htsmsg_add_str(out, "description", str);
1259
      if ((str = epg_broadcast_get_summary(e, lang)))
1260
        htsmsg_add_str(out, "summary", str);
1261
      if ((str = epg_broadcast_get_subtitle(e, lang)))
1262
        htsmsg_add_str(out, "subtitle", str);
1263
    } else if ((str = epg_broadcast_get_summary(e, lang))) {
1264
      htsmsg_add_str(out, "description", str);
1257
  /* For basic format, we want to skip the large text fields
1258
   * and go straight to doing the low-overhead fields.
1259
   */
1260
  if (of != ACCESS_HTSP_OUTPUT_FORMAT_BASIC) {
1261
    if (htsp->htsp_version < 32) {
1262
      if ((str = epg_broadcast_get_description(e, lang))) {
1263
        htsmsg_add_str(out, "description", str);
1264
        if ((str = epg_broadcast_get_summary(e, lang)))
1265
          htsmsg_add_str(out, "summary", str);
1266
        if ((str = epg_broadcast_get_subtitle(e, lang)))
1267
          htsmsg_add_str(out, "subtitle", str);
1268
      } else if ((str = epg_broadcast_get_summary(e, lang))) {
1269
        htsmsg_add_str(out, "description", str);
1270
        if ((str = epg_broadcast_get_subtitle(e, lang)))
1271
          htsmsg_add_str(out, "subtitle", str);
1272
      } else if ((str = epg_broadcast_get_subtitle(e, lang))) {
1273
        htsmsg_add_str(out, "description", str);
1274
      }
1275
    } else {
1265 1276
      if ((str = epg_broadcast_get_subtitle(e, lang)))
1266 1277
        htsmsg_add_str(out, "subtitle", str);
1267
    } else if ((str = epg_broadcast_get_subtitle(e, lang))) {
1268
      htsmsg_add_str(out, "description", str);
1278
      if ((str = epg_broadcast_get_summary(e, lang)))
1279
        htsmsg_add_str(out, "summary", str);
1280
      if ((str = epg_broadcast_get_description(e, lang)))
1281
        htsmsg_add_str(out, "description", str);
1269 1282
    }
1270
  } else {
1271
    if ((str = epg_broadcast_get_subtitle(e, lang)))
1272
      htsmsg_add_str(out, "subtitle", str);
1273
    if ((str = epg_broadcast_get_summary(e, lang)))
1274
      htsmsg_add_str(out, "summary", str);
1275
    if ((str = epg_broadcast_get_description(e, lang)))
1276
      htsmsg_add_str(out, "description", str);
1277
  }
1278 1283

1279
  if (e->credits)
1280
    htsmsg_add_msg(out, "credits", htsmsg_copy(e->credits));
1281
  if (e->category)
1282
    string_list_serialize(e->category, out, "category");
1283
  if (e->keyword)
1284
    string_list_serialize(e->keyword, out, "keyword");
1284
    if (e->credits)
1285
      htsmsg_add_msg(out, "credits", htsmsg_copy(e->credits));
1286
    if (e->category)
1287
      string_list_serialize(e->category, out, "category");
1288
    if (e->keyword)
1289
      string_list_serialize(e->keyword, out, "keyword");
1290
  }
1285 1291

1286 1292
  if (e->serieslink)
1287 1293
    htsmsg_add_str(out, "serieslinkUri", e->serieslink->uri);
src/webui/static/app/acleditor.js
15 15
                'streaming,profile,conn_limit_type,conn_limit,' +
16 16
                'dvr,htsp_anonymize,dvr_config,' +
17 17
                'channel_min,channel_max,channel_tag_exclude,' +
18
                'channel_tag,comment';
18
                'channel_tag,xmltv_output_format,htsp_output_format,comment';
19 19

20 20
    tvheadend.idnode_grid(panel, {
21 21
        id: 'access_entry',
src/webui/xmltv.c
62 62
  htsbuf_append_str(hq, "</tv>\n");
63 63
}
64 64

65

66
/** Determine name to use for the channel based on the
67
 * user's settings. This is done because some TVs have
68
 * broken parsers that require a "user readable" name
69
 * for the channel.
70
 *
71
 * @param buf Buffer that is used if we return an idnode.
72
 *
73
 * @return Buffer containing the name. This might not
74
 * be the same as the passed in temporary buffer.
75
 *
76
 */
77
static const char *
78
http_xmltv_channel_get_name(const http_connection_t *hc,
79
                            const channel_t *ch,
80
                            char *buf,
81
                            size_t buf_len)
82
{
83
  const int of = hc->hc_access->aa_xmltv_output_format;
84

85
  if (of == ACCESS_XMLTV_OUTPUT_FORMAT_BASIC_NO_HASH)
86
    return channel_get_name(ch, idnode_uuid_as_str(&ch->ch_id, buf));
87
  else
88
    return idnode_uuid_as_str(&ch->ch_id, buf);
89
}
90

91

65 92
/*
66 93
 *
67 94
 */
68 95
static void
69
http_xmltv_channel_add(htsbuf_queue_t *hq, int flags, const char *hostpath, channel_t *ch)
96
http_xmltv_channel_add(http_connection_t *hc, htsbuf_queue_t *hq, int flags, const char *hostpath, channel_t *ch)
70 97
{
71 98
  const char *icon = channel_get_icon(ch);
72 99
  char ubuf[UUID_HEX_SIZE];
73 100
  const char *tag;
74 101
  int64_t lcn;
75
  htsbuf_qprintf(hq, "<channel id=\"%s\">\n  <display-name>",
76
                 idnode_uuid_as_str(&ch->ch_id, ubuf));
102
  htsbuf_qprintf(hq, "<channel id=\"");
103
  htsbuf_append_and_escape_xml(hq, http_xmltv_channel_get_name(hc, ch, ubuf, sizeof ubuf));
104
  htsbuf_qprintf(hq, "\">\n  <display-name>");
77 105
  htsbuf_append_and_escape_xml(hq, channel_get_name(ch, ""));
78 106
  htsbuf_append_str(hq, "</display-name>\n");
79 107
  lcn = channel_get_number(ch);
......
133 161
  }
134 162
}
135 163

136
/*
137
 *
164
/// Output a start tag for the tag and include a lang="xx" _only_ if we
165
/// have more than one language. This avoids outputting lots of tags for
166
/// the common case of only having one language, so is useful for very low
167
/// memory devices.
168
#define HTTP_XMLTV_OUTPUT_START_TAG_WITH_LANG(hq,rb_tree,lang_str,tag)  \
169
  do {                                                                  \
170
    htsbuf_qprintf(hq, "  <%s", tag);                                   \
171
    if (rb_tree->entries != 1)                                          \
172
      htsbuf_qprintf(hq, " lang=\"%s\"", lang_str->lang);               \
173
    htsbuf_append_str(hq,">");                                          \
174
  } while(0)
175

176
/** Output long description fields of the programme which are
177
 * not output for basic/limited devices.
138 178
 */
139 179
static void
140
http_xmltv_programme_one(htsbuf_queue_t *hq, const char *hostpath,
141
                         channel_t *ch, epg_broadcast_t *ebc)
180
http_xmltv_programme_one_long(const http_connection_t *hc,
181
                              htsbuf_queue_t *hq, const char *hostpath,
182
                              const channel_t *ch, const epg_broadcast_t *ebc)
142 183
{
143
  epg_episode_num_t epnum;
144
  char start[32], stop[32], ubuf[UUID_HEX_SIZE];
145 184
  lang_str_ele_t *lse;
146 185
  epg_genre_t *genre;
147 186
  char buf[64];
148 187

149
  if (ebc->title == NULL) return;
150
  http_xmltv_time(start, ebc->start);
151
  http_xmltv_time(stop, ebc->stop);
152
  htsbuf_qprintf(hq, "<programme start=\"%s\" stop=\"%s\" channel=\"%s\">\n",
153
                 start, stop, idnode_uuid_as_str(&ch->ch_id, ubuf));
154
  RB_FOREACH(lse, ebc->title, link) {
155
    htsbuf_qprintf(hq, "  <title lang=\"%s\">", lse->lang);
156
    htsbuf_append_and_escape_xml(hq, lse->str);
157
    htsbuf_append_str(hq, "</title>\n");
158
  }
159 188
  if (ebc->subtitle)
160 189
    RB_FOREACH(lse, ebc->subtitle, link) {
161
      htsbuf_qprintf(hq, "  <sub-title lang=\"%s\">", lse->lang);
162
      htsbuf_append_and_escape_xml(hq, lse->str);
163
      htsbuf_append_str(hq, "</sub-title>\n");
190
      /* Ignore empty sub-titles */
191
      if (!strempty(lse->str)) {
192
          HTTP_XMLTV_OUTPUT_START_TAG_WITH_LANG(hq, ebc->subtitle, lse, "sub-title");
193
          htsbuf_append_and_escape_xml(hq, lse->str);
194
          htsbuf_append_str(hq, "</sub-title>\n");
195
        }
164 196
    }
197

165 198
  if (ebc->description)
166 199
    RB_FOREACH(lse, ebc->description, link) {
167
      htsbuf_qprintf(hq, "  <desc lang=\"%s\">", lse->lang);
200
      HTTP_XMLTV_OUTPUT_START_TAG_WITH_LANG(hq, ebc->description, lse, "desc");
168 201
      htsbuf_append_and_escape_xml(hq, lse->str);
169 202
      htsbuf_append_str(hq, "</desc>\n");
170 203
    }
171 204
  else if (ebc->summary)
172 205
    RB_FOREACH(lse, ebc->summary, link) {
173
      htsbuf_qprintf(hq, "  <desc lang=\"%s\">", lse->lang);
206
      HTTP_XMLTV_OUTPUT_START_TAG_WITH_LANG(hq, ebc->summary, lse, "desc");
174 207
      htsbuf_append_and_escape_xml(hq, lse->str);
175 208
      htsbuf_append_str(hq, "</desc>\n");
176 209
    }
......
195 228
    }
196 229
  }
197 230
  _http_xmltv_programme_write_string_list(hq, ebc->keyword, "keyword");
231
}
232

233
/*
234
 *
235
 */
236
static void
237
http_xmltv_programme_one(const http_connection_t *hc,
238
                         htsbuf_queue_t *hq, const char *hostpath,
239
                         const channel_t *ch, const epg_broadcast_t *ebc)
240
{
241
  epg_episode_num_t epnum;
242
  char start[32], stop[32], ubuf[UUID_HEX_SIZE];
243
  lang_str_ele_t *lse;
244
  const int of = hc->hc_access->aa_xmltv_output_format;
245

246
  if (ebc->title == NULL) return;
247
  http_xmltv_time(start, ebc->start);
248
  http_xmltv_time(stop, ebc->stop);
249
  htsbuf_qprintf(hq, "<programme start=\"%s\" stop=\"%s\" channel=\"",
250
                 start, stop);
251
  htsbuf_append_and_escape_xml(hq, http_xmltv_channel_get_name(hc, ch, ubuf, sizeof ubuf));
252
  htsbuf_qprintf(hq, "\">\n");
253
  RB_FOREACH(lse, ebc->title, link) {
254
    HTTP_XMLTV_OUTPUT_START_TAG_WITH_LANG(hq, ebc->title, lse, "title");
255
    htsbuf_append_and_escape_xml(hq, lse->str);
256
    htsbuf_append_str(hq, "</title>\n");
257
  }
258

259
  /* Basic formats are for low-memory devices that
260
   * only want very basic information.
261
   */
262
  if (of != ACCESS_XMLTV_OUTPUT_FORMAT_BASIC &&
263
      of != ACCESS_XMLTV_OUTPUT_FORMAT_BASIC_NO_HASH) {
264
    http_xmltv_programme_one_long(hc, hq, hostpath, ch, ebc);
265
  }
198 266

199 267
  /* We can't use epg_broadcast_epnumber_format since we need a specific
200 268
   * format whereas that can return an arbitrary text string.
......
216 284
 *
217 285
 */
218 286
static void
219
http_xmltv_programme_add(htsbuf_queue_t *hq, const char *hostpath, channel_t *ch)
287
http_xmltv_programme_add(const http_connection_t *hc, htsbuf_queue_t *hq, const char *hostpath, channel_t *ch)
220 288
{
221 289
  epg_broadcast_t *ebc;
222 290

223 291
  RB_FOREACH(ebc, &ch->ch_epg_schedule, sched_link)
224
    http_xmltv_programme_one(hq, hostpath, ch, ebc);
292
    http_xmltv_programme_one(hc, hq, hostpath, ch, ebc);
225 293
}
226 294

227 295
/**
......
237 305

238 306
  http_get_hostpath(hc, hostpath, sizeof(hostpath));
239 307
  http_xmltv_begin(&hc->hc_reply);
240
  http_xmltv_channel_add(&hc->hc_reply, flags, hostpath, channel);
241
  http_xmltv_programme_add(&hc->hc_reply, hostpath, channel);
308
  http_xmltv_channel_add(hc, &hc->hc_reply, flags, hostpath, channel);
309
  http_xmltv_programme_add(hc, &hc->hc_reply, hostpath, channel);
242 310
  http_xmltv_end(&hc->hc_reply);
243 311
  return 0;
244 312
}
......
264 332
    ch = (channel_t *)ilm->ilm_in2;
265 333
    if (http_access_verify_channel(hc, ACCESS_STREAMING, ch))
266 334
      continue;
267
    http_xmltv_channel_add(&hc->hc_reply, flags, hostpath, ch);
335
    http_xmltv_channel_add(hc, &hc->hc_reply, flags, hostpath, ch);
268 336
  }
269 337
  LIST_FOREACH(ilm, &tag->ct_ctms, ilm_in1_link) {
270 338
    ch = (channel_t *)ilm->ilm_in2;
271 339
    if (http_access_verify_channel(hc, ACCESS_STREAMING, ch))
272 340
      continue;
273
    http_xmltv_programme_add(&hc->hc_reply, hostpath, ch);
341
    http_xmltv_programme_add(hc, &hc->hc_reply, hostpath, ch);
274 342
  }
275 343
  http_xmltv_end(&hc->hc_reply);
276 344

......
295 363
  CHANNEL_FOREACH(ch) {
296 364
    if (http_access_verify_channel(hc, ACCESS_STREAMING, ch))
297 365
      continue;
298
    http_xmltv_channel_add(&hc->hc_reply, flags, hostpath, ch);
366
    http_xmltv_channel_add(hc, &hc->hc_reply, flags, hostpath, ch);
299 367
  }
300 368
  CHANNEL_FOREACH(ch) {
301 369
    if (http_access_verify_channel(hc, ACCESS_STREAMING, ch))
302 370
      continue;
303
    http_xmltv_programme_add(&hc->hc_reply, hostpath, ch);
371
    http_xmltv_programme_add(hc, &hc->hc_reply, hostpath, ch);
304 372
  }
305 373
  http_xmltv_end(&hc->hc_reply);
306 374

    (1-1/1)