Compare commits

..

8 Commits

Author SHA1 Message Date
Rafał Dzięgiel
4a34fb3484 clapper: discoverer: Skip items that already have tags
When tags are populated elsewhere, do not run discovery on them again.
It is possible they were discovered in more efficient maner
(e.g. from playlist data itself).

This avoid us downloading each media item separately after all
playlist items are queued.
2025-07-26 15:37:33 +02:00
Rafał Dzięgiel
d8ea220aad clapper-app: Remove claps handling code
It is now handled inside playlist demuxer, with the other playlist formats
2025-07-26 15:37:31 +02:00
Rafał Dzięgiel
dc56cb201a clapper: Support demuxing uri-list and claps files 2025-07-26 15:37:28 +02:00
Rafał Dzięgiel
07f944fb31 clapper: Update harvest common formats description 2025-07-26 15:37:26 +02:00
Rafał Dzięgiel
b2e6533c30 clapper: Store full caps in harvest
Make it possible to know which enhancer harvested this cached data
2025-07-26 15:37:24 +02:00
Rafał Dzięgiel
7a56fbfff8 clapper: Rename "uri-list-demux" element
Move as harvest URI demuxer since it is supposed to work only with
harvest data from extractable src. Also change caps media type
to "text/x-uri" which is non-standard, but we have to differentiate
single URI from harvest and URI list (one or more URIs).
2025-07-26 15:37:22 +02:00
Rafał Dzięgiel
7457ffda13 clapper: Handle parsed playlists
Handle "ClapperPlaylistParsed" messages on playbin bus by updating current media
item (playlist) to redirect to the first item in that playlist (with changed tags)
and appending remaining items to the queue after that playlist position.

This basically means that playlist gets resolved into simply adding more
items to the queue. This should also work with nested playlists within playlist.
2025-07-26 15:37:18 +02:00
Rafał Dzięgiel
bee2e08fb1 clapper: Add playlist demuxer element
Uses "Playlistable" enhancers to parse playlist and demux first URI in it
2025-07-26 15:32:32 +02:00
2 changed files with 35 additions and 32 deletions

View File

@@ -131,7 +131,7 @@ _run_discovery (ClapperDiscoverer *self)
ClapperDiscovererDiscoveryMode discovery_mode; ClapperDiscovererDiscoveryMode discovery_mode;
GstTagList *tags; GstTagList *tags;
const gchar *uri; const gchar *uri;
gboolean had_tags, success = FALSE; gboolean empty_tags, success = FALSE;
if (self->pending_items->len == 0) { if (self->pending_items->len == 0) {
GST_DEBUG_OBJECT (self, "No more pending items"); GST_DEBUG_OBJECT (self, "No more pending items");
@@ -160,10 +160,10 @@ _run_discovery (ClapperDiscoverer *self)
} }
tags = clapper_media_item_get_tags (item); tags = clapper_media_item_get_tags (item);
had_tags = !gst_tag_list_is_empty (tags); empty_tags = gst_tag_list_is_empty (tags);
gst_tag_list_unref (tags); gst_tag_list_unref (tags);
if (had_tags) { if (!empty_tags) {
GST_DEBUG_OBJECT (self, "Queued %" GST_PTR_FORMAT GST_DEBUG_OBJECT (self, "Queued %" GST_PTR_FORMAT
" already has tags, ignoring discovery", item); " already has tags, ignoring discovery", item);
goto finish; goto finish;

View File

@@ -63,23 +63,24 @@ static GstStaticCaps clapper_claps_caps = GST_STATIC_CAPS (CLAPPER_CLAPS_MEDIA_T
static void static void
clapper_playlist_type_find (GstTypeFind *tf, ClapperEnhancerProxy *proxy) clapper_playlist_type_find (GstTypeFind *tf, ClapperEnhancerProxy *proxy)
{ {
const gchar *prefix, *contains, *regex, *data; const gchar *prefix, *contains, *regex, *module_name;
guint prob = 0;
if (!clapper_enhancer_proxy_get_target_creation_allowed (proxy))
return;
if ((prefix = clapper_enhancer_proxy_get_extra_data (proxy, "X-Data-Prefix"))) { if ((prefix = clapper_enhancer_proxy_get_extra_data (proxy, "X-Data-Prefix"))) {
size_t len = strlen (prefix); size_t len = strlen (prefix);
data = (const gchar *) gst_type_find_peek (tf, 0, (guint) len); const gchar *data = (const gchar *) gst_type_find_peek (tf, 0, (guint) len);
if (!data || memcmp (data, prefix, len) != 0) if (!data || memcmp (data, prefix, len) != 0)
return; return;
prob += 40;
} }
contains = clapper_enhancer_proxy_get_extra_data (proxy, "X-Data-Contains"); contains = clapper_enhancer_proxy_get_extra_data (proxy, "X-Data-Contains");
regex = clapper_enhancer_proxy_get_extra_data (proxy, "X-Data-Regex"); regex = clapper_enhancer_proxy_get_extra_data (proxy, "X-Data-Regex");
if (contains || regex) { if (contains || regex) {
const gchar *data;
guint data_size = DATA_CHUNK_SIZE; guint data_size = DATA_CHUNK_SIZE;
if (!(data = (const gchar *) gst_type_find_peek (tf, 0, data_size))) { if (!(data = (const gchar *) gst_type_find_peek (tf, 0, data_size))) {
@@ -96,12 +97,9 @@ clapper_playlist_type_find (GstTypeFind *tf, ClapperEnhancerProxy *proxy)
return; return;
} }
if (contains) { if (contains && !g_strstr_len (data, data_size, contains))
if (!g_strstr_len (data, data_size, contains)) return;
return;
prob += 50;
}
if (regex) { if (regex) {
GRegex *reg; GRegex *reg;
GError *error = NULL; GError *error = NULL;
@@ -119,22 +117,15 @@ clapper_playlist_type_find (GstTypeFind *tf, ClapperEnhancerProxy *proxy)
if (!matched) if (!matched)
return; return;
prob += 50;
} }
} }
if (prob > 0) { module_name = clapper_enhancer_proxy_get_module_name (proxy);
const gchar *module_name = clapper_enhancer_proxy_get_module_name (proxy); GST_INFO ("Suggesting likely type: " CLAPPER_PLAYLIST_MEDIA_TYPE
", enhancer: %s", module_name);
if (prob > 100) gst_type_find_suggest_simple (tf, GST_TYPE_FIND_LIKELY,
prob = 100; CLAPPER_PLAYLIST_MEDIA_TYPE, "enhancer", G_TYPE_STRING, module_name, NULL);
GST_INFO ("Type find prob of %s: %u%%", module_name, prob);
gst_type_find_suggest_simple (tf, prob, CLAPPER_PLAYLIST_MEDIA_TYPE,
"enhancer", G_TYPE_STRING, module_name, NULL);
}
} }
/* Finds text file of full file paths. Claps file might also use URIs, /* Finds text file of full file paths. Claps file might also use URIs,
@@ -266,7 +257,7 @@ _parse_uri_list (ClapperPlaylistDemux *self, GUri *uri, GstBuffer *buffer,
} }
if (G_LIKELY (item != NULL)) if (G_LIKELY (item != NULL))
g_list_store_append (playlist, G_OBJECT (item)); g_list_store_append (playlist, (GObject *) item);
/* Advance to the next line */ /* Advance to the next line */
ptr = nl ? (nl + 1) : end; ptr = nl ? (nl + 1) : end;
@@ -324,7 +315,7 @@ _handle_playlist (ClapperPlaylistDemux *self, GListStore *playlist, GCancellable
if (G_UNLIKELY (item == NULL)) { if (G_UNLIKELY (item == NULL)) {
GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ, GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ,
("%s", "This playlist appears to be empty"), (NULL)); ("This playlist appears to be empty"), (NULL));
return FALSE; return FALSE;
} }
@@ -334,7 +325,7 @@ _handle_playlist (ClapperPlaylistDemux *self, GListStore *playlist, GCancellable
if (G_UNLIKELY (!success)) { if (G_UNLIKELY (!success)) {
GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ, GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ,
("%s", "Resolved item URI was rejected"), (NULL)); ("Resolved item URI was rejected"), (NULL));
return FALSE; return FALSE;
} }
@@ -346,7 +337,7 @@ _handle_playlist (ClapperPlaylistDemux *self, GListStore *playlist, GCancellable
gst_message_new_element (GST_OBJECT_CAST (self), structure)); gst_message_new_element (GST_OBJECT_CAST (self), structure));
} }
return success; return TRUE;
} }
static gboolean static gboolean
@@ -354,12 +345,17 @@ clapper_playlist_demux_process_buffer (ClapperUriBaseDemux *uri_bd,
GstBuffer *buffer, GCancellable *cancellable) GstBuffer *buffer, GCancellable *cancellable)
{ {
ClapperPlaylistDemux *self = CLAPPER_PLAYLIST_DEMUX_CAST (uri_bd); ClapperPlaylistDemux *self = CLAPPER_PLAYLIST_DEMUX_CAST (uri_bd);
GstQuery *query = gst_query_new_uri (); GstPad *sink_pad;
GstQuery *query;
GUri *uri = NULL; GUri *uri = NULL;
GListStore *playlist; GListStore *playlist;
GError *error = NULL; GError *error = NULL;
gboolean handled;
if (gst_pad_peer_query (GST_ELEMENT_CAST (self)->sinkpads->data, query)) { sink_pad = gst_element_get_static_pad (GST_ELEMENT_CAST (self), "sink");
query = gst_query_new_uri ();
if (gst_pad_peer_query (sink_pad, query)) {
gchar *query_uri; gchar *query_uri;
gst_query_parse_uri (query, &query_uri); gst_query_parse_uri (query, &query_uri);
@@ -370,7 +366,9 @@ clapper_playlist_demux_process_buffer (ClapperUriBaseDemux *uri_bd,
g_free (query_uri); g_free (query_uri);
} }
} }
gst_query_unref (query); gst_query_unref (query);
gst_object_unref (sink_pad);
if (G_UNLIKELY (uri == NULL)) { if (G_UNLIKELY (uri == NULL)) {
GST_ERROR_OBJECT (self, "Could not query source URI"); GST_ERROR_OBJECT (self, "Could not query source URI");
@@ -413,6 +411,8 @@ clapper_playlist_demux_process_buffer (ClapperUriBaseDemux *uri_bd,
"Unsupported media type in caps"); "Unsupported media type in caps");
} }
g_uri_unref (uri);
if (!playlist) { if (!playlist) {
GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ, GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ,
("%s", error->message), (NULL)); ("%s", error->message), (NULL));
@@ -421,7 +421,10 @@ clapper_playlist_demux_process_buffer (ClapperUriBaseDemux *uri_bd,
return FALSE; return FALSE;
} }
return _handle_playlist (self, playlist, cancellable); handled = _handle_playlist (self, playlist, cancellable);
g_object_unref (playlist);
return handled;
} }
static void static void