2 * Copyright (C) 2012 Toni Gundogdu <legatvs@gmail.com>
4 * This file is part of quvi <http://quvi.sourceforge.net/>.
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU Affero General Public
8 * License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
16 * You should have received a copy of the GNU Affero General
17 * Public License along with this program. If not, see
18 * <http://www.gnu.org/licenses/>.
24 #include <glib/gi18n.h>
29 typedef enum {TSTRING
, TDOUBLE
} PropertyType
;
31 struct _media_xchg_table_s
33 const QuviMediaProperty qmp
;
34 const PropertyType type
;
38 static const struct _media_xchg_table_s media_xchg_table
[] =
40 {QUVI_MEDIA_PROPERTY_START_TIME_MS
, TDOUBLE
, "%s"},
41 {QUVI_MEDIA_PROPERTY_THUMBNAIL_URL
, TSTRING
, "%T"},
42 {QUVI_MEDIA_PROPERTY_DURATION_MS
, TDOUBLE
, "%d"},
43 {QUVI_MEDIA_STREAM_PROPERTY_URL
, TSTRING
, "%u"},
44 {QUVI_MEDIA_STREAM_PROPERTY_ID
, TSTRING
, "%I"},
45 {QUVI_MEDIA_PROPERTY_TITLE
, TSTRING
, "%t"},
46 {QUVI_MEDIA_PROPERTY_ID
, TSTRING
, "%i"},
50 static const gchar
*default_str
= N_("default");
52 /* Return a media property value. */
53 static gchar
*_qm_get(quvi_media_t qm
, const gint i
)
57 switch (media_xchg_table
[i
].type
)
62 quvi_media_get(qm
, media_xchg_table
[i
].qmp
, &s
);
64 if (s
!= NULL
&& strlen(s
) >0)
72 quvi_media_get(qm
, media_xchg_table
[i
].qmp
, &d
);
73 return (g_strdup_printf("%.0f", d
));
78 g_warning("[%s] invalid media xchg table type (%d)",
79 __func__
, media_xchg_table
[i
].type
);
82 return ((r
== NULL
) ? g_strdup(default_str
):r
);
85 /* Regexp eval-callback. */
86 static gboolean
_eval_cb(const GMatchInfo
*i
, GString
*r
, gpointer p
)
90 m
= g_match_info_fetch(i
, 0);
91 s
= g_hash_table_lookup((GHashTable
*) p
, m
);
92 g_string_append(r
, s
);
98 /* Append a sequence to the replace-pattern. */
99 static void _pattern_append(GString
*p
, const gchar
*s
)
102 g_string_append(p
, "|");
103 g_string_append(p
, s
);
106 /* Return a new regex cache. */
107 static GSList
*_regex_cache_new(const gchar
**output_regex
)
113 if (output_regex
== NULL
)
116 for (i
=0, r
=NULL
; output_regex
[i
] != NULL
; ++i
)
118 op
= lutil_regex_op_new(output_regex
[i
], NULL
);
120 r
= g_slist_prepend(r
, op
);
122 return (g_slist_reverse(r
));
125 /* Release regex cache. */
126 static void _regex_cache_free(GSList
*l
)
131 lutil_slist_free_full(l
, (GFunc
) lutil_regex_op_free
);
134 /* Apply regex onto the media property value. */
135 static gchar
*_apply_regex(GSList
*l
, const gchar
*seq
, gchar
*s
)
140 lutil_regex_op_t op
= (lutil_regex_op_t
) curr
->data
;
141 if (g_strcmp0(op
->sequence
, seq
) ==0)
143 gchar
*r
= lutil_regex_op_apply(op
, s
);
150 curr
= g_slist_next(curr
);
155 /* Return a new sequence handle. */
156 static lutil_xchg_seq_t
_new(GSList
**regex_cache
, const gchar
**output_regex
,
157 const lutil_cb_printerr xperr
, GString
**p
)
159 lutil_xchg_seq_t x
= g_new0(struct _lutil_xchg_seq_s
, 1);
161 x
->htable
= g_hash_table_new_full(g_str_hash
, g_str_equal
, NULL
, g_free
);
164 *regex_cache
= _regex_cache_new(output_regex
);
165 *p
= g_string_new(NULL
);
170 /* Insert media property value into hash table. */
171 static void _insert(lutil_xchg_seq_t x
, GSList
*regex_cache
,
172 const gchar
*seq
, gchar
*s
, GString
*p
)
177 if (regex_cache
!= NULL
)
178 s
= _apply_regex(regex_cache
, seq
, s
);
180 g_hash_table_insert(x
->htable
, (gchar
*) seq
, s
);
181 _pattern_append(p
, seq
);
184 /* Create a new regex instance used to replace the sequences. */
185 static lutil_xchg_seq_t
_new_regex(lutil_xchg_seq_t x
, GString
*p
, GSList
*c
)
189 x
->re
= g_regex_new(p
->str
, 0, 0, &e
);
192 x
->printerr(_("while creating sequence regex: %s"), e
->message
);
193 lutil_xchg_seq_free(x
);
198 g_string_free(p
, TRUE
);
199 _regex_cache_free(c
);
204 /* Return a new sequence handle. */
205 lutil_xchg_seq_t
lutil_xchg_seq_new(const lutil_xchg_seq_opts_t xopts
)
212 g_assert(xopts
->xperr
!= NULL
);
213 g_assert(xopts
->qm
!= NULL
);
215 x
= _new(&c
, xopts
->output_regex
, xopts
->xperr
, &p
);
217 for (i
=0; media_xchg_table
[i
].seq
!= NULL
; ++i
)
218 _insert(x
, c
, media_xchg_table
[i
].seq
, _qm_get(xopts
->qm
,i
), p
);
220 if (xopts
->file_ext
!= NULL
)
221 _insert(x
, c
, "%e", g_strdup(xopts
->file_ext
), p
);
223 if (xopts
->fpath
!= NULL
)
224 _insert(x
, c
, "%f", g_strdup(xopts
->fpath
), p
);
226 return (_new_regex(x
, p
, c
));
229 /* Return a new sequence handle -- without quvi_media_t and quvi_metainfo_t */
230 lutil_xchg_seq_t
lutil_xchg_seq_noq_new(lutil_xchg_seq_noq_t noq
,
231 const lutil_cb_printerr xperr
,
232 const gchar
**output_regex
)
240 g_assert(xperr
!= NULL
);
241 g_assert(noq
!= NULL
);
243 x
= _new(&c
, output_regex
, xperr
, &p
);
245 for (i
=0; noq
[i
].seq
!= NULL
; ++i
)
247 s
= g_strdup( (noq
[i
].val
==NULL
|| strlen(s
) ==0)
250 _insert(x
, c
, noq
[i
].seq
, s
, p
);
252 return (_new_regex(x
, p
, c
));
255 /* Free sequence handle. */
256 void lutil_xchg_seq_free(lutil_xchg_seq_t p
)
261 g_hash_table_destroy(p
->htable
);
262 g_regex_unref(p
->re
);
265 memset(p
, 0, sizeof(struct _lutil_xchg_seq_s
));
268 /* Replace the sequences in the given string (g_free the returned string). */
269 gchar
*lutil_xchg_seq_apply(lutil_xchg_seq_t p
, const gchar
*s
)
277 r
= g_regex_replace_eval(p
->re
, s
, -1, 0, 0, _eval_cb
, p
->htable
, &e
);
280 p
->printerr(_("while replacing sequences: %s"), e
->message
);
287 /* vim: set ts=2 sw=2 tw=72 expandtab: */