6 Commits

Author SHA1 Message Date
Rafał Dzięgiel
aa0be37cb9 New translations clapper-app.pot (Arabic) 2025-06-14 19:10:30 +02:00
Rafał Dzięgiel
9aee805b6d New translations clapper-app.pot (Arabic) 2025-06-14 17:48:59 +02:00
Rafał Dzięgiel
6ee406c11d New translations clapper-gtk.pot (Arabic) 2025-06-14 17:48:58 +02:00
Rafał Dzięgiel
fcc41b2e9c New translations clapper-app.pot (Persian) 2025-05-18 16:52:10 +02:00
Rafał Dzięgiel
fb8ee8497a New translations clapper-gtk.pot (Chinese Simplified) 2025-05-08 09:56:58 +02:00
Rafał Dzięgiel
3ba2611901 New translations clapper-app.pot (Chinese Simplified) 2025-05-01 15:53:00 +02:00
187 changed files with 1560 additions and 6813 deletions

View File

@@ -2,7 +2,7 @@
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
<https://fsf.org/>
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -55,7 +55,7 @@ modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
@@ -111,7 +111,7 @@ modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
@@ -158,7 +158,7 @@ Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
@@ -216,7 +216,7 @@ instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
@@ -267,7 +267,7 @@ Library will still fall under Section 6.)
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
@@ -329,7 +329,7 @@ restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
@@ -370,7 +370,7 @@ subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
@@ -422,7 +422,7 @@ conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
@@ -456,7 +456,7 @@ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
@@ -484,7 +484,9 @@ convey the exclusion of warranty; and each file should have at least the
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <https://www.gnu.org/licenses/>.
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
Also add information on how to contact you by electronic and paper mail.
@@ -493,9 +495,10 @@ school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
library `Frob' (a library for tweaking knobs) written by James Random
Hacker.
<signature of Moe Ghoul>, 1 April 1990
Moe Ghoul, President of Vice
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@@ -11,7 +11,7 @@ project('clapper', 'c',
glib_req = '>= 2.76.0'
gst_req = '>= 1.24.0'
gtk4_req = '>= 4.10.0'
adw_req = '>= 1.5.0'
adw_req = '>= 1.4.0'
clapper_version = meson.project_version().split('-')[0]
version_array = clapper_version.split('.')

View File

@@ -72,43 +72,6 @@ _open_subtitles_cb (GtkFileDialog *dialog, GAsyncResult *result, ClapperMediaIte
gst_object_unref (item); // Borrowed reference
}
static void
_on_select_file_dir_finish (GFile *file, AdwActionRow *action_row, GError *error)
{
if (G_LIKELY (error == NULL)) {
gchar *path = g_file_get_path (file);
adw_action_row_set_subtitle (action_row, path);
g_free (path);
} else {
if (error->domain != GTK_DIALOG_ERROR || error->code != GTK_DIALOG_ERROR_DISMISSED) {
g_printerr ("Error: %s\n",
(error->message) ? error->message : "Could not open file dialog");
}
g_error_free (error);
}
g_clear_object (&file);
g_object_unref (action_row); // Borrowed reference
}
static void
_select_file_cb (GtkFileDialog *dialog, GAsyncResult *result, AdwActionRow *action_row)
{
GError *error = NULL;
GFile *file = gtk_file_dialog_open_finish (dialog, result, &error);
_on_select_file_dir_finish (file, action_row, error);
}
static void
_select_dir_cb (GtkFileDialog *dialog, GAsyncResult *result, AdwActionRow *action_row)
{
GError *error = NULL;
GFile *file = gtk_file_dialog_select_folder_finish (dialog, result, &error);
_on_select_file_dir_finish (file, action_row, error);
}
static void
_dialog_add_mime_types (GtkFileDialog *dialog, const gchar *filter_name,
const gchar *const *mime_types)
@@ -181,35 +144,3 @@ clapper_app_file_dialog_open_subtitles (GtkApplication *gtk_app, ClapperMediaIte
g_object_unref (dialog);
}
void
clapper_app_file_dialog_select_prefs_file (GtkApplication *gtk_app, AdwActionRow *action_row)
{
GtkWindow *window = gtk_application_get_active_window (gtk_app);
GtkFileDialog *dialog = gtk_file_dialog_new ();
gtk_file_dialog_set_modal (dialog, TRUE);
gtk_file_dialog_set_title (dialog, "Select File");
gtk_file_dialog_open (dialog, window, NULL,
(GAsyncReadyCallback) _select_file_cb,
g_object_ref (action_row));
g_object_unref (dialog);
}
void
clapper_app_file_dialog_select_prefs_dir (GtkApplication *gtk_app, AdwActionRow *action_row)
{
GtkWindow *window = gtk_application_get_active_window (gtk_app);
GtkFileDialog *dialog = gtk_file_dialog_new ();
gtk_file_dialog_set_modal (dialog, TRUE);
gtk_file_dialog_set_title (dialog, "Select Folder");
gtk_file_dialog_select_folder (dialog, window, NULL,
(GAsyncReadyCallback) _select_dir_cb,
g_object_ref (action_row));
g_object_unref (dialog);
}

View File

@@ -19,7 +19,6 @@
#include <glib.h>
#include <gtk/gtk.h>
#include <adwaita.h>
#include <clapper/clapper.h>
G_BEGIN_DECLS
@@ -30,10 +29,4 @@ void clapper_app_file_dialog_open_files (GtkApplication *gtk_app);
G_GNUC_INTERNAL
void clapper_app_file_dialog_open_subtitles (GtkApplication *gtk_app, ClapperMediaItem *item);
G_GNUC_INTERNAL
void clapper_app_file_dialog_select_prefs_file (GtkApplication *gtk_app, AdwActionRow *action_row);
G_GNUC_INTERNAL
void clapper_app_file_dialog_select_prefs_dir (GtkApplication *gtk_app, AdwActionRow *action_row);
G_END_DECLS

View File

@@ -23,7 +23,6 @@
#include "clapper-app-preferences-window.h"
#include "clapper-app-application.h"
#include "clapper-app-file-dialog.h"
#include "clapper-app-utils.h"
#define GST_CAT_DEFAULT clapper_app_preferences_window_debug
@@ -42,14 +41,6 @@ struct _ClapperAppPreferencesWindow
AdwSpinRow *subtitle_offset_spin_row;
GtkFontDialogButton *font_dialog_button;
GtkStack *enhancers_stack;
GtkWidget *browse_enhancers_page;
GtkWidget *no_enhancers_page;
AdwNavigationPage *enhancers_subpage;
AdwComboRow *enhancers_combo_row;
AdwPreferencesGroup *enhancer_config_group;
AdwNavigationPage *plugins_subpage;
AdwComboRow *plugins_combo_row;
AdwComboRow *features_combo_row;
@@ -57,8 +48,6 @@ struct _ClapperAppPreferencesWindow
GSettings *settings;
GList *enhancer_pspec_rows;
GList *features;
GtkStringList *plugins_list;
@@ -78,19 +67,6 @@ typedef struct
gboolean updated;
} ClapperAppPreferencesIterRanksData;
typedef struct
{
GSettings *settings;
const gchar *key;
} ClapperAppPreferencesResetData;
typedef struct
{
GSettings *settings;
GParamSpec *pspec;
guint flag;
} ClapperAppPreferencesFlagMapData;
enum
{
PROP_0,
@@ -100,347 +76,6 @@ enum
static GParamSpec *param_specs[PROP_LAST] = { NULL, };
static void
_flag_map_data_free (ClapperAppPreferencesFlagMapData *data)
{
GST_TRACE ("Destroying flag map data: %p", data);
g_object_unref (data->settings);
g_free (data);
}
static void
_reset_button_closure (ClapperAppPreferencesResetData *data, GClosure *closure)
{
GST_TRACE ("Destroying reset button data: %p", data);
g_object_unref (data->settings);
g_free (data);
}
static void
_reset_button_clicked_cb (GtkButton *button, ClapperAppPreferencesResetData *data)
{
g_settings_reset (data->settings, data->key);
}
static void
file_selection_row_activated_cb (AdwActionRow *action_row, GParamSpec *pspec)
{
GtkApplication *gtk_app;
GtkWidget *window;
if (!(window = gtk_widget_get_ancestor (GTK_WIDGET (action_row), GTK_TYPE_WINDOW))) {
GST_ERROR ("Could not get a hold of parent window");
return;
}
gtk_app = gtk_window_get_application (GTK_WINDOW (window));
if (pspec->flags & CLAPPER_ENHANCER_PARAM_FILEPATH)
clapper_app_file_dialog_select_prefs_file (gtk_app, action_row);
else
clapper_app_file_dialog_select_prefs_dir (gtk_app, action_row);
}
static gboolean
_get_enum_mapping (GValue *value, GVariant *variant, GParamSpec *pspec)
{
GEnumClass *enum_class = G_ENUM_CLASS (g_type_class_peek (pspec->value_type));
const gchar *selected_str = g_variant_get_string (variant, NULL);
guint i, selected = 0;
for (i = 0; i < enum_class->n_values; ++i) {
if (g_strcmp0 (selected_str, enum_class->values[i].value_nick) == 0) {
selected = i;
break;
}
}
g_value_set_uint (value, selected);
return TRUE;
}
static GVariant *
_set_enum_mapping (GValue *value, GVariantType *exp_type, GParamSpec *pspec)
{
GEnumClass *enum_class = G_ENUM_CLASS (g_type_class_peek (pspec->value_type));
guint selected = g_value_get_uint (value);
if (G_UNLIKELY (selected == GTK_INVALID_LIST_POSITION))
selected = 0;
return g_variant_new_string (enum_class->values[selected].value_nick);
}
static gboolean
_get_flag_mapping (GValue *value, GVariant *variant, ClapperAppPreferencesFlagMapData *data)
{
guint flags = g_settings_get_flags (data->settings, data->pspec->name);
g_value_set_boolean (value, (flags & data->flag));
return TRUE;
}
static GVariant *
_set_flag_mapping (GValue *value, GVariantType *exp_type, ClapperAppPreferencesFlagMapData *data)
{
GFlagsClass *flags_class = G_FLAGS_CLASS (g_type_class_peek (data->pspec->value_type));
GStrvBuilder *builder;
GVariant *variant;
gchar **strv;
gboolean active = g_value_get_boolean (value);
guint i, flags = g_settings_get_flags (data->settings, data->pspec->name);
if (active)
flags |= data->flag;
else
flags &= ~(data->flag);
builder = g_strv_builder_new ();
for (i = 0; i < flags_class->n_values; ++i) {
if (flags & flags_class->values[i].value)
g_strv_builder_add (builder, flags_class->values[i].value_nick);
}
strv = g_strv_builder_end (builder);
g_strv_builder_unref (builder);
variant = g_variant_new_strv ((const gchar *const *) strv, -1);
g_strfreev (strv);
return variant;
}
static gboolean
_add_enhancer_config_row (ClapperAppPreferencesWindow *self, GParamSpec *pspec,
GSettings *enhancer_settings)
{
GtkWidget *row = NULL, *reset_button;
ClapperAppPreferencesResetData *reset_data;
const gchar *bind_prop = NULL;
gboolean is_enum = FALSE, is_flags = FALSE;
switch (pspec->value_type) {
case G_TYPE_BOOLEAN:{
row = adw_switch_row_new ();
break;
}
case G_TYPE_INT:{
GParamSpecInt *p = (GParamSpecInt *) pspec;
row = adw_spin_row_new_with_range (p->minimum, p->maximum, 1);
break;
}
case G_TYPE_UINT:{
GParamSpecUInt *p = (GParamSpecUInt *) pspec;
row = adw_spin_row_new_with_range (p->minimum, p->maximum, 1);
break;
}
case G_TYPE_DOUBLE:{
GParamSpecDouble *p = (GParamSpecDouble *) pspec;
row = adw_spin_row_new_with_range (p->minimum, p->maximum, 0.25);
break;
}
case G_TYPE_STRING:{
if (pspec->flags & (CLAPPER_ENHANCER_PARAM_FILEPATH | CLAPPER_ENHANCER_PARAM_DIRPATH)) {
GtkWidget *image;
image = gtk_image_new_from_icon_name ("document-open-symbolic");
gtk_widget_set_margin_end (image, 10); // matches other rows
row = adw_action_row_new ();
adw_action_row_add_suffix (ADW_ACTION_ROW (row), image);
adw_action_row_set_activatable_widget (ADW_ACTION_ROW (row), image);
g_signal_connect (row, "activated",
G_CALLBACK (file_selection_row_activated_cb), pspec);
} else {
row = adw_entry_row_new ();
}
break;
}
default:{
if ((is_enum = G_IS_PARAM_SPEC_ENUM (pspec))) {
GtkExpression *expression;
AdwEnumListModel *enum_model;
row = adw_combo_row_new ();
expression = gtk_property_expression_new (ADW_TYPE_ENUM_LIST_ITEM, NULL, "nick");
adw_combo_row_set_expression (ADW_COMBO_ROW (row), expression);
enum_model = adw_enum_list_model_new (pspec->value_type);
adw_combo_row_set_model (ADW_COMBO_ROW (row), G_LIST_MODEL (enum_model));
gtk_expression_unref (expression);
g_object_unref (enum_model);
break;
} else if ((is_flags = G_IS_PARAM_SPEC_FLAGS (pspec))) {
GFlagsClass *flags_class = G_FLAGS_CLASS (g_type_class_peek (pspec->value_type));
guint i;
row = adw_expander_row_new ();
for (i = 0; i < flags_class->n_values; ++i) {
GtkWidget *flag_row = adw_switch_row_new ();
ClapperAppPreferencesFlagMapData *fm_data;
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (flag_row),
flags_class->values[i].value_nick);
fm_data = g_new (ClapperAppPreferencesFlagMapData, 1);
fm_data->settings = g_object_ref (enhancer_settings);
fm_data->pspec = pspec;
fm_data->flag = flags_class->values[i].value;
GST_TRACE ("Created flag map data: %p", fm_data);
g_settings_bind_with_mapping (enhancer_settings, pspec->name, flag_row,
"active", G_SETTINGS_BIND_DEFAULT,
(GSettingsBindGetMapping) _get_flag_mapping,
(GSettingsBindSetMapping) _set_flag_mapping,
fm_data, (GDestroyNotify) _flag_map_data_free);
adw_expander_row_add_row (ADW_EXPANDER_ROW (row), flag_row);
}
break;
}
g_warning ("Unsupported enhancer \"%s\" property type: %s",
pspec->name, g_type_name (pspec->value_type));
return FALSE;
}
}
reset_button = gtk_button_new_from_icon_name ("view-refresh-symbolic");
gtk_widget_set_tooltip_text (reset_button, _("Restore default"));
gtk_widget_set_halign (reset_button, GTK_ALIGN_CENTER);
gtk_widget_set_valign (reset_button, GTK_ALIGN_CENTER);
gtk_widget_add_css_class (reset_button, "circular");
gtk_widget_set_tooltip_text (row, g_param_spec_get_blurb (pspec));
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), g_param_spec_get_nick (pspec));
if (ADW_IS_SWITCH_ROW (row)) {
bind_prop = "active";
} else if (ADW_IS_SPIN_ROW (row)) {
bind_prop = "value";
adw_spin_row_set_numeric (ADW_SPIN_ROW (row), TRUE);
} else if (ADW_IS_ENTRY_ROW (row)) {
bind_prop = "text";
} else if (ADW_IS_COMBO_ROW (row)) {
bind_prop = "selected";
} else if (ADW_IS_ACTION_ROW (row)) {
bind_prop = "subtitle";
} else if (!is_flags) { // In case of flags we bind individual widgets
g_assert_not_reached ();
return FALSE;
}
if (ADW_IS_ENTRY_ROW (row))
adw_entry_row_add_prefix (ADW_ENTRY_ROW (row), reset_button);
else if (ADW_IS_ACTION_ROW (row))
adw_action_row_add_prefix (ADW_ACTION_ROW (row), reset_button);
else if (ADW_IS_EXPANDER_ROW (row))
adw_expander_row_add_prefix (ADW_EXPANDER_ROW (row), reset_button);
if (is_enum) {
g_settings_bind_with_mapping (enhancer_settings, pspec->name, row,
bind_prop, G_SETTINGS_BIND_DEFAULT,
(GSettingsBindGetMapping) _get_enum_mapping,
(GSettingsBindSetMapping) _set_enum_mapping,
pspec, NULL);
} else if (!is_flags) {
g_settings_bind (enhancer_settings, pspec->name, row,
bind_prop, G_SETTINGS_BIND_DEFAULT);
}
reset_data = g_new (ClapperAppPreferencesResetData, 1);
reset_data->settings = g_object_ref (enhancer_settings);
reset_data->key = pspec->name;
GST_TRACE ("Created reset button data: %p", reset_data);
g_signal_connect_data (reset_button, "clicked",
G_CALLBACK (_reset_button_clicked_cb), reset_data,
(GClosureNotify) _reset_button_closure, G_CONNECT_DEFAULT);
adw_preferences_group_add (self->enhancer_config_group, row);
self->enhancer_pspec_rows = g_list_append (self->enhancer_pspec_rows, row);
return TRUE;
}
static void
selected_enhancer_changed_cb (AdwComboRow *combo_row,
GParamSpec *pspec G_GNUC_UNUSED, ClapperAppPreferencesWindow *self)
{
guint selected = adw_combo_row_get_selected (combo_row);
/* Remove old rows */
if (self->enhancer_pspec_rows) {
GList *el;
for (el = self->enhancer_pspec_rows; el; el = g_list_next (el))
adw_preferences_group_remove (self->enhancer_config_group, GTK_WIDGET (el->data));
g_clear_list (&self->enhancer_pspec_rows, NULL);
}
/* Add new rows */
if (selected != GTK_INVALID_LIST_POSITION) {
ClapperEnhancerProxyList *proxies = clapper_get_global_enhancer_proxies ();
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_peek_proxy (proxies, selected);
GParamSpec **pspecs;
guint n_pspecs;
gboolean has_props = FALSE;
if ((pspecs = clapper_enhancer_proxy_get_target_properties (proxy, &n_pspecs))) {
GSettings *enhancer_settings = NULL;
guint i;
for (i = 0; i < n_pspecs; ++i) {
if (pspecs[i]->flags & CLAPPER_ENHANCER_PARAM_GLOBAL) {
if (!enhancer_settings)
enhancer_settings = clapper_enhancer_proxy_get_settings (proxy);
if (enhancer_settings)
has_props |= _add_enhancer_config_row (self, pspecs[i], enhancer_settings);
}
}
g_clear_object (&enhancer_settings);
}
if (!has_props) {
GtkWidget *row = adw_action_row_new ();
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), _("No configurable properties"));
adw_preferences_group_add (self->enhancer_config_group, row);
self->enhancer_pspec_rows = g_list_append (self->enhancer_pspec_rows, row);
}
}
}
static void
enhancers_config_activated_cb (AdwActionRow *action_row, ClapperAppPreferencesWindow *self)
{
/* If no model set yet */
if (!adw_combo_row_get_model (self->enhancers_combo_row)) {
ClapperEnhancerProxyList *proxies = clapper_get_global_enhancer_proxies ();
adw_combo_row_set_model (self->enhancers_combo_row, G_LIST_MODEL (proxies));
adw_combo_row_set_selected (self->enhancers_combo_row, GTK_INVALID_LIST_POSITION);
GST_DEBUG ("Populated names combo row in enhancers subpage");
if (clapper_enhancer_proxy_list_get_n_proxies (proxies) > 0)
gtk_stack_set_visible_child (self->enhancers_stack, self->browse_enhancers_page);
else
gtk_stack_set_visible_child (self->enhancers_stack, self->no_enhancers_page);
}
adw_preferences_window_push_subpage (ADW_PREFERENCES_WINDOW (self), self->enhancers_subpage);
}
/* Sort by plugin name and if the same, sort by element name */
static gint
_compare_plugins_cb (gconstpointer ptr_a, gconstpointer ptr_b)
@@ -666,12 +301,6 @@ _make_plugin_features_string_list (ClapperAppPreferencesWindow *self, const gcha
return features_list;
}
static gboolean
list_has_selection_closure (ClapperAppPreferencesWindow *self, guint selected)
{
return (selected != GTK_INVALID_LIST_POSITION);
}
static GtkStringList *
ranking_features_model_closure (ClapperAppPreferencesWindow *self, GtkStringObject *string_obj)
{
@@ -914,7 +543,6 @@ clapper_app_preferences_window_finalize (GObject *object)
g_object_unref (self->settings);
g_clear_list (&self->enhancer_pspec_rows, NULL);
g_clear_object (&self->plugins_list);
if (self->features)
@@ -970,14 +598,6 @@ clapper_app_preferences_window_class_init (ClapperAppPreferencesWindowClass *kla
gtk_widget_class_bind_template_child (widget_class, ClapperAppPreferencesWindow, subtitle_offset_spin_row);
gtk_widget_class_bind_template_child (widget_class, ClapperAppPreferencesWindow, font_dialog_button);
gtk_widget_class_bind_template_child (widget_class, ClapperAppPreferencesWindow, enhancers_stack);
gtk_widget_class_bind_template_child (widget_class, ClapperAppPreferencesWindow, browse_enhancers_page);
gtk_widget_class_bind_template_child (widget_class, ClapperAppPreferencesWindow, no_enhancers_page);
gtk_widget_class_bind_template_child (widget_class, ClapperAppPreferencesWindow, enhancers_subpage);
gtk_widget_class_bind_template_child (widget_class, ClapperAppPreferencesWindow, enhancers_combo_row);
gtk_widget_class_bind_template_child (widget_class, ClapperAppPreferencesWindow, enhancer_config_group);
gtk_widget_class_bind_template_child (widget_class, ClapperAppPreferencesWindow, plugins_subpage);
gtk_widget_class_bind_template_child (widget_class, ClapperAppPreferencesWindow, plugins_combo_row);
gtk_widget_class_bind_template_child (widget_class, ClapperAppPreferencesWindow, features_combo_row);
@@ -985,13 +605,9 @@ clapper_app_preferences_window_class_init (ClapperAppPreferencesWindowClass *kla
gtk_widget_class_bind_template_callback (widget_class, seek_method_name_closure);
gtk_widget_class_bind_template_callback (widget_class, enhancers_config_activated_cb);
gtk_widget_class_bind_template_callback (widget_class, selected_enhancer_changed_cb);
gtk_widget_class_bind_template_callback (widget_class, plugin_ranking_activated_cb);
gtk_widget_class_bind_template_callback (widget_class, plugin_ranking_unrealize_cb);
gtk_widget_class_bind_template_callback (widget_class, list_has_selection_closure);
gtk_widget_class_bind_template_callback (widget_class, ranking_features_model_closure);
gtk_widget_class_bind_template_callback (widget_class, add_override_button_sensitive_closure);
gtk_widget_class_bind_template_callback (widget_class, add_override_button_clicked_cb);

View File

@@ -86,7 +86,9 @@ typedef struct
gint64 last_tick;
} ClapperAppWindowResizeData;
#if CLAPPER_HAVE_MPRIS
static guint16 instance_count = 0;
#endif
static inline GQuark
clapper_app_window_extra_options_get_quark (void)
@@ -1250,28 +1252,16 @@ clapper_app_window_constructed (GObject *object)
#if (CLAPPER_HAVE_MPRIS || CLAPPER_HAVE_SERVER || CLAPPER_HAVE_DISCOVERER)
ClapperFeature *feature = NULL;
#endif
#if (!CLAPPER_HAVE_MPRIS || !CLAPPER_HAVE_SERVER || !CLAPPER_HAVE_DISCOVERER)
ClapperEnhancerProxyList *proxies = clapper_player_get_enhancer_proxies (player);
ClapperEnhancerProxy *proxy;
#endif
#if CLAPPER_HAVE_MPRIS
gchar mpris_name[45];
g_snprintf (mpris_name, sizeof (mpris_name),
"org.mpris.MediaPlayer2.Clapper.instance%" G_GUINT16_FORMAT, instance_count++);
#endif
self->settings = g_settings_new (CLAPPER_APP_ID);
self->last_volume = PERCENTAGE_ROUND (g_settings_get_double (self->settings, "volume"));
#if !CLAPPER_HAVE_MPRIS
if ((proxy = clapper_enhancer_proxy_list_get_proxy_by_module (proxies, "clapper-mpris"))) {
clapper_enhancer_proxy_set_locally (proxy,
"own-name", mpris_name,
"identity", CLAPPER_APP_NAME,
"desktop-entry", CLAPPER_APP_ID,
"queue-controllable", TRUE, NULL);
gst_object_unref (proxy);
}
#else
#if CLAPPER_HAVE_MPRIS
feature = CLAPPER_FEATURE (clapper_mpris_new (
mpris_name, CLAPPER_APP_NAME, CLAPPER_APP_ID));
clapper_mpris_set_queue_controllable (CLAPPER_MPRIS (feature), TRUE);

View File

@@ -21,10 +21,10 @@ window.info .subcontent streamlist preferencesgroup {
window.preferences .subcontent {
margin: 16px;
}
window.preferences .configsubpage .subcontent popover {
window.preferences .pluginssubpage .subcontent popover {
min-width: 264px;
}
window.preferences .configsubpage .subcontent button.pill {
window.preferences .pluginssubpage .subcontent button.pill {
margin-top: 8px;
margin-bottom: 8px;
}

View File

@@ -1,11 +1,10 @@
appstream_cli = find_program('appstreamcli', required: false)
if appstream_cli.found()
appstream_util = find_program('appstream-util', required: false)
if appstream_util.found()
test('Validate appstream file',
appstream_cli,
appstream_util,
args: [
'validate',
'--no-net',
'--explain',
'validate-relax',
'--nonet',
join_paths(meson.current_source_dir(), 'metainfo', 'com.github.rafostar.Clapper.metainfo.xml'),
]
)

View File

@@ -31,10 +31,8 @@
gint
main (gint argc, gchar **argv)
{
GApplication *application;
ClapperEnhancerProxyList *proxies;
const gchar *clapper_ldir;
guint i, n_proxies;
GApplication *application;
gint status;
#ifdef G_OS_WIN32
@@ -66,15 +64,6 @@ main (gint argc, gchar **argv)
resolution = clapper_app_utils_win_hi_res_clock_start ();
#endif
proxies = clapper_get_global_enhancer_proxies ();
n_proxies = clapper_enhancer_proxy_list_get_n_proxies (proxies);
/* Allow usage of all enhancers */
for (i = 0; i < n_proxies; ++i) {
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_peek_proxy (proxies, i);
clapper_enhancer_proxy_set_target_creation_allowed (proxy, TRUE);
}
application = clapper_app_application_new ();
status = g_application_run (application, argc, argv);

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-15 12:47+0100\n"
"PO-Revision-Date: 2025-02-15 12:10\n"
"PO-Revision-Date: 2025-06-14 17:10\n"
"Last-Translator: \n"
"Language-Team: Arabic\n"
"Language: ar_SA\n"
@@ -20,30 +20,30 @@ msgstr ""
#. Translators: Do NOT translate app name!
#: src/bin/clapper-app/data/applications/com.github.rafostar.Clapper.desktop.in:4
msgid "Clapper"
msgstr ""
msgstr "كلابر"
#: src/bin/clapper-app/data/applications/com.github.rafostar.Clapper.desktop.in:5
msgid "Multimedia Player"
msgstr ""
msgstr "مشغل وسائط متعددة"
#: src/bin/clapper-app/data/applications/com.github.rafostar.Clapper.desktop.in:6
msgid "Play videos and music"
msgstr ""
msgstr "شغِّل الفيديوهات والموسيقى"
#. Translators: Search terms to find this application. Do NOT translate the semicolons!
#: src/bin/clapper-app/data/applications/com.github.rafostar.Clapper.desktop.in:16
msgid "Video;Movie;Film;Clip;Series;Player;Playlist;DVD;TV;Disc;"
msgstr ""
msgstr "الفيديوهات;الفيلم;الأفلام;المقطع;المقاطع;المسلسلات;المشغلات;قائمة تشغيل;DVD;دي في دي;التلفاز;القرص;Clapper;"
#: src/bin/clapper-app/data/applications/com.github.rafostar.Clapper.desktop.in:22
#: src/bin/clapper-app/ui/clapper-app-headerbar.ui:183
msgid "New Window"
msgstr ""
msgstr "نافذة جديدة"
#: src/bin/clapper-app/ui/clapper-app-audio-stream-list-item.ui:14
#: src/bin/clapper-app/ui/clapper-app-video-stream-list-item.ui:14
msgid "Codec"
msgstr ""
msgstr "المرماز"
#: src/bin/clapper-app/ui/clapper-app-audio-stream-list-item.ui:24
msgid "Channels"
@@ -65,23 +65,23 @@ msgstr ""
#: src/bin/clapper-app/ui/clapper-app-audio-stream-list-item.ui:70
#: src/bin/clapper-app/ui/clapper-app-subtitle-stream-list-item.ui:24
msgid "Language"
msgstr ""
msgstr "اللغة"
#: src/bin/clapper-app/ui/clapper-app-headerbar.ui:189
#: src/bin/clapper-app/ui/clapper-app-initial-state.ui:80
msgid "Preferences"
msgstr "الإعدادات"
msgstr "التفضيلات"
#: src/bin/clapper-app/ui/clapper-app-headerbar.ui:193
#: src/bin/clapper-app/ui/clapper-app-initial-state.ui:84
msgid "Keyboard Shortcuts"
msgstr ""
msgstr "اختصارات لوحة المفاتيح"
#. TRANSLATORS: Please do not translate application name
#: src/bin/clapper-app/ui/clapper-app-headerbar.ui:200
#: src/bin/clapper-app/ui/clapper-app-initial-state.ui:91
msgid "About Clapper"
msgstr "حول Clapper"
msgstr "عَنْ «كلابر»"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:10
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:11
@@ -90,19 +90,19 @@ msgstr "عام"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:13
msgid "New window"
msgstr ""
msgstr "نافذة جديدة"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:19
msgid "Open preferences"
msgstr ""
msgstr "افتح التفضيلات"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:25
msgid "Show shortcuts"
msgstr "إظهار الاختصارات"
msgstr "أظهِر الاختصارات"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:31
msgid "Toggle fullscreen"
msgstr "تبديل ملء الشاشة"
msgstr "بدِّل ملء الشاشة"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:32
msgid "Double tap | Double click"
@@ -122,7 +122,7 @@ msgstr ""
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:51
msgid "Quit"
msgstr "خروج"
msgstr "اخرج"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:59
#: src/bin/clapper-app/ui/clapper-app-info-window.ui:32
@@ -133,13 +133,13 @@ msgstr "الوسائط"
#: src/bin/clapper-app/ui/clapper-app-initial-state.ui:55
#: src/bin/clapper-app/ui/clapper-app-queue-list.ui:178
msgid "Add Files…"
msgstr ""
msgstr "أضِف ملفات…"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:68
#: src/bin/clapper-app/ui/clapper-app-initial-state.ui:65
#: src/bin/clapper-app/ui/clapper-app-queue-list.ui:182
msgid "Add URI…"
msgstr ""
msgstr "أضِف URI…"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:76
msgid "Queue"
@@ -148,12 +148,12 @@ msgstr ""
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:80
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:87
msgid "Next item"
msgstr "المحتوى التالي"
msgstr "العنصر التالي"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:94
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:101
msgid "Previous item"
msgstr "المحتوى السابق"
msgstr "العنصر السابق"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:107
msgid "Change progression mode"
@@ -162,11 +162,11 @@ msgstr ""
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:115
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:76
msgid "Playback"
msgstr "المشغل"
msgstr "التشغيل"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:118
msgid "Toggle play"
msgstr "بَدْءّ / إيقاف"
msgstr "بدِّل التشغيل"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:119
msgid "Tap | Left click"
@@ -175,7 +175,7 @@ msgstr ""
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:126
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:134
msgid "Seek forward"
msgstr "التقدم للأمام"
msgstr "تقدَم للأمام"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:127
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:151
@@ -190,11 +190,11 @@ msgstr ""
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:142
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:150
msgid "Seek backward"
msgstr "الرجوع للوراء"
msgstr "عُد للوراء"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:157
msgid "Volume up"
msgstr "رفع مستوى الصوت"
msgstr "ارفع شدة الصوت"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:158
msgid "Scroll up"
@@ -202,7 +202,7 @@ msgstr ""
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:164
msgid "Volume down"
msgstr "خفض مستوى الصوت"
msgstr "اخفض شدة الصوت"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:165
msgid "Scroll down"
@@ -210,7 +210,7 @@ msgstr ""
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:171
msgid "Toggle mute"
msgstr "كتم الصوت"
msgstr "بدِّل الكتم"
#: src/bin/clapper-app/ui/clapper-app-help-overlay.ui:177
msgid "Speed up"
@@ -232,7 +232,7 @@ msgstr "الفصل السابق"
#: src/bin/clapper-app/ui/clapper-app-info-window.ui:13
msgid "Info"
msgstr ""
msgstr "معلومات"
#: src/bin/clapper-app/ui/clapper-app-info-window.ui:35
#: src/bin/clapper-app/ui/clapper-app-subtitle-stream-list-item.ui:14
@@ -254,7 +254,7 @@ msgstr ""
#: src/bin/clapper-app/ui/clapper-app-info-window.ui:84
#: src/bin/clapper-app/clapper-app-list-item-utils.c:36
msgid "Video"
msgstr ""
msgstr "الفيديو"
#: src/bin/clapper-app/ui/clapper-app-info-window.ui:107
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:80
@@ -266,7 +266,7 @@ msgstr "الصوت"
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:100
#: src/bin/clapper-app/clapper-app-list-item-utils.c:42
msgid "Subtitles"
msgstr "التَّرْجَمَةً"
msgstr "الترجَمة"
#: src/bin/clapper-app/ui/clapper-app-info-window.ui:155
msgid "Video Playback"
@@ -309,11 +309,11 @@ msgstr ""
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:15
msgid "Seeking"
msgstr "الوضع"
msgstr "السعي"
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:18
msgid "Method"
msgstr ""
msgstr "الطريقة"
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:19
msgid "A preferred method used for seeking"
@@ -349,15 +349,15 @@ msgstr "النسبة المئوية"
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:63
msgid "Features"
msgstr ""
msgstr "الميزات"
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:66
msgid "Server"
msgstr "الخادم"
msgstr "الخادوم"
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:67
msgid "Control player remotely"
msgstr "التحكم بالوسائط عن بعد"
msgstr "يتحكم بالوسائط عن بعد"
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:83
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:103
@@ -374,7 +374,7 @@ msgstr ""
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:118
msgid "Default font"
msgstr "الخط الافتراضي"
msgstr "الخط المبدئي"
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:119
msgid "Text font used for subtitles when media does not explicitly specify one"
@@ -382,15 +382,15 @@ msgstr ""
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:137
msgid "Tweaks"
msgstr "تعديلات"
msgstr "التطويعات"
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:144
msgid "Plugin ranking"
msgstr "أعدادات الإضافات"
msgstr "منازل الملحقات"
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:145
msgid "Alter default ranks of GStreamer plugins"
msgstr "تغيير الأعدادات الافتراضية للأضافات GStreamer"
msgstr "يغيِّر المنازل المبدئية لملحقات GStreamer"
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:164
msgid "Plugin Ranking"
@@ -443,11 +443,11 @@ msgstr ""
#: src/bin/clapper-app/ui/clapper-app-uri-dialog.ui:18
msgid "Enter or drop URI here"
msgstr "أدخل أو الصق URI هنا"
msgstr "أدخِل أو أسقِط URI هنا"
#: src/bin/clapper-app/ui/clapper-app-uri-dialog.ui:22
msgid "Cancel"
msgstr "إلغاء"
msgstr "ألغِ"
#: src/bin/clapper-app/ui/clapper-app-video-stream-list-item.ui:24
msgid "Resolution"
@@ -464,7 +464,8 @@ msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/bin/clapper-app/clapper-app-about-window.c:47
msgid "translator-credits"
msgstr "Yousef Fawaz"
msgstr "Yousef Fawaz\n"
"أحمد النجماوي <iramosu@protonmail.com>"
#: src/bin/clapper-app/clapper-app-application.c:696
msgid "Create a new window"
@@ -512,7 +513,7 @@ msgstr ""
#: src/bin/clapper-app/clapper-app-info-window.c:86
msgid "Hardware"
msgstr ""
msgstr "العتاد"
#: src/bin/clapper-app/clapper-app-info-window.c:86
msgid "Software"
@@ -520,7 +521,7 @@ msgstr ""
#: src/bin/clapper-app/clapper-app-preferences-window.c:441
msgid "Accurate"
msgstr "دَقيق"
msgstr "دقيق"
#: src/bin/clapper-app/clapper-app-preferences-window.c:443
msgid "Normal"

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-15 12:47+0100\n"
"PO-Revision-Date: 2025-02-15 13:14\n"
"PO-Revision-Date: 2025-05-18 14:52\n"
"Last-Translator: \n"
"Language-Team: Persian\n"
"Language: fa_IR\n"
@@ -305,7 +305,7 @@ msgstr "جریان‌های زیرنویس"
#: src/bin/clapper-app/ui/clapper-app-initial-state.ui:46
msgid "Start by adding media to playback queue"
msgstr "آغزا با افزودن رسانه به صف پخش"
msgstr "آغاز با افزودن رسانه به صف پخش"
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:15
msgid "Seeking"
@@ -402,7 +402,7 @@ msgstr "افزایه‌های موجود"
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:183
msgid "Select a plugin and its feature to override rank for. When multiple elements have similiar capabilities, the one with highest value is preferred."
msgstr "گزینش افزایه و ویژگیش برای پایمالی رتبه دهیش. هنگامی که چندین عنصر قابلیت‌ّای مشابهی دارند، آنی که بیش‌ترین رتبه را دارد ترجیح داده می‌شود."
msgstr "گزینش افزایه و ویژگیش برای پایمالی رتبه دهیش. هنگامی که چندین عنصر قابلیت‌های مشابهی دارند، آنی که بیش‌ترین رتبه را دارد ترجیح داده می‌شود."
#: src/bin/clapper-app/ui/clapper-app-preferences-window.ui:186
msgid "Plugin"

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-15 12:47+0100\n"
"PO-Revision-Date: 2025-02-15 12:11\n"
"PO-Revision-Date: 2025-05-01 13:52\n"
"Last-Translator: \n"
"Language-Team: Chinese Simplified\n"
"Language: zh_CN\n"
@@ -33,7 +33,7 @@ msgstr "播放视频和音乐"
#. Translators: Search terms to find this application. Do NOT translate the semicolons!
#: src/bin/clapper-app/data/applications/com.github.rafostar.Clapper.desktop.in:16
msgid "Video;Movie;Film;Clip;Series;Player;Playlist;DVD;TV;Disc;"
msgstr ""
msgstr "视频电影影片短片连续剧播放器播放列表DVD电视唱片"
#: src/bin/clapper-app/data/applications/com.github.rafostar.Clapper.desktop.in:22
#: src/bin/clapper-app/ui/clapper-app-headerbar.ui:183

View File

@@ -136,24 +136,6 @@
<object class="AdwPreferencesPage">
<property name="title" translatable="yes">Tweaks</property>
<property name="icon-name">applications-engineering-symbolic</property>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="no">Clapper</property>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Enhancers</property>
<property name="subtitle" translatable="yes">Browse and configure properties of available enhancers</property>
<property name="activatable">true</property>
<signal name="activated" handler="enhancers_config_activated_cb"/>
<child>
<object class="GtkImage">
<property name="icon_name">go-next-symbolic</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="no">GStreamer</property>
@@ -178,124 +160,6 @@
<class name="preferences"/>
</style>
</template>
<object class="AdwNavigationPage" id="enhancers_subpage">
<property name="title" translatable="yes">Clapper Enhancers</property>
<property name="child">
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar"/>
</child>
<property name="content">
<object class="GtkScrolledWindow">
<child>
<object class="AdwClamp">
<style>
<class name="subcontent"/>
</style>
<child>
<object class="GtkStack" id="enhancers_stack">
<child>
<object class="GtkBox" id="browse_enhancers_page">
<property name="orientation">vertical</property>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Available enhancers</property>
<property name="description" translatable="yes">Select an enhancer plugin to view its information and properties to configure.</property>
<child>
<object class="AdwComboRow" id="enhancers_combo_row">
<property name="title" translatable="yes">Enhancer</property>
<property name="enable-search">true</property>
<property name="expression">
<lookup type="ClapperEnhancerProxy" name="friendly-name"/>
</property>
<signal name="notify::selected" handler="selected_enhancer_changed_cb"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<binding name="visible">
<closure type="gboolean" function="list_has_selection_closure">
<lookup name="selected">enhancers_combo_row</lookup>
</closure>
</binding>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Information</property>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Module</property>
<binding name="subtitle">
<lookup name="module-name" type="ClapperEnhancerProxy">
<lookup name="selected-item">enhancers_combo_row</lookup>
</lookup>
</binding>
<style>
<class name="property"/>
</style>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Description</property>
<binding name="subtitle">
<lookup name="description" type="ClapperEnhancerProxy">
<lookup name="selected-item">enhancers_combo_row</lookup>
</lookup>
</binding>
<style>
<class name="property"/>
</style>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Version</property>
<binding name="subtitle">
<lookup name="version" type="ClapperEnhancerProxy">
<lookup name="selected-item">enhancers_combo_row</lookup>
</lookup>
</binding>
<style>
<class name="property"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup" id="enhancer_config_group">
<property name="title" translatable="yes">Properties</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="AdwStatusPage" id="no_enhancers_page">
<property name="vexpand">true</property>
<property name="hexpand">true</property>
<property name="icon-name">edit-find-symbolic</property>
<property name="title" translatable="yes">No Clapper Enhancers Found</property>
<property name="description" translatable="yes">Install some to add more cool functionalities to the player!</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</property>
<signal name="unrealize" handler="plugin_ranking_unrealize_cb"/>
<style>
<class name="configsubpage"/>
</style>
</object>
<object class="AdwNavigationPage" id="plugins_subpage">
<property name="title" translatable="yes">Plugin Ranking</property>
<property name="child">
@@ -376,7 +240,7 @@
</property>
<signal name="unrealize" handler="plugin_ranking_unrealize_cb"/>
<style>
<class name="configsubpage"/>
<class name="pluginssubpage"/>
</style>
</object>
</interface>

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <clapper/clapper.h>

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "clapper-gtk-buffering-paintable-private.h"

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <clapper/clapper.h>

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -176,6 +176,7 @@ if build_gir
clappergtk_enums,
],
extra_args: [
gir_init_section,
'--quiet',
'--warn-all',
'-DCLAPPER_GTK_COMPILATION',

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-01-07 19:03+0100\n"
"PO-Revision-Date: 2025-01-07 18:31\n"
"PO-Revision-Date: 2025-06-14 15:48\n"
"Last-Translator: \n"
"Language-Team: Arabic\n"
"Language: ar_SA\n"
@@ -20,7 +20,7 @@ msgstr ""
#: src/lib/clapper-gtk/ui/clapper-gtk-extra-menu-button.ui:9
#: src/lib/clapper-gtk/clapper-gtk-extra-menu-button.c:228
msgid "Video"
msgstr ""
msgstr "الفيديو"
#: src/lib/clapper-gtk/ui/clapper-gtk-extra-menu-button.ui:17
#: src/lib/clapper-gtk/clapper-gtk-extra-menu-button.c:229
@@ -30,50 +30,50 @@ msgstr "الصوت"
#: src/lib/clapper-gtk/ui/clapper-gtk-extra-menu-button.ui:25
#: src/lib/clapper-gtk/clapper-gtk-extra-menu-button.c:230
msgid "Subtitles"
msgstr "التَّرْجَمَةً"
msgstr "الترجَمة"
#: src/lib/clapper-gtk/ui/clapper-gtk-extra-menu-button.ui:28
msgid "Show Subtitles"
msgstr ""
msgstr "اعرض الترجَمة"
#: src/lib/clapper-gtk/ui/clapper-gtk-extra-menu-button.ui:32
msgid "Open…"
msgstr ""
msgstr "افتح…"
#: src/lib/clapper-gtk/ui/clapper-gtk-extra-menu-button.ui:75
msgid "Mute"
msgstr ""
msgstr "اكتم"
#: src/lib/clapper-gtk/ui/clapper-gtk-extra-menu-button.ui:119
msgid "Reset"
msgstr ""
msgstr "صفِّر"
#: src/lib/clapper-gtk/ui/clapper-gtk-video-placeholder.ui:25
msgid "External video output"
msgstr ""
msgstr "مخرج الفيديو الخارجي"
#: src/lib/clapper-gtk/ui/clapper-gtk-video-placeholder.ui:37
msgid "Used video sink cannot be embedded within application window"
msgstr ""
msgstr "لا يمكن تضمين بالوعة الفيديو المستخدمة في نافذة التطبيق"
#: src/lib/clapper-gtk/clapper-gtk-status.c:79
msgid "Unplayable Content"
msgstr ""
msgstr "محتوى غير قابل للتشغيل"
#. TRANSLATORS: Please do not try to translate "GStreamer" (it is a library name).
#: src/lib/clapper-gtk/clapper-gtk-status.c:89
#, c-format
msgid "Your GStreamer installation is missing a plugin: %s"
msgstr ""
msgstr "يفتقد تنصيبك لـGStreamer ملحقًا: %s"
#: src/lib/clapper-gtk/clapper-gtk-status.c:90
msgid "Missing Plugin"
msgstr ""
msgstr "ملحق مفقود"
#: src/lib/clapper-gtk/clapper-gtk-stream-check-button.c:82
#: src/lib/clapper-gtk/clapper-gtk-stream-check-button.c:126
msgid "Undetermined"
msgstr "غير محدّد"
msgstr "غير محدَّد"
#: src/lib/clapper-gtk/clapper-gtk-stream-check-button.c:82
msgid "Channels"
@@ -81,9 +81,9 @@ msgstr "قنوات"
#: src/lib/clapper-gtk/clapper-gtk-title-label.c:91
msgid "No media"
msgstr ""
msgstr "لا وسائط"
#: src/lib/clapper-gtk/clapper-gtk-title-label.c:103
msgid "Unknown title"
msgstr ""
msgstr "عنوان مجهول"

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-01-07 19:03+0100\n"
"PO-Revision-Date: 2025-01-07 18:32\n"
"PO-Revision-Date: 2025-05-08 07:56\n"
"Last-Translator: \n"
"Language-Team: Chinese Simplified\n"
"Language: zh_CN\n"
@@ -50,11 +50,11 @@ msgstr "重置"
#: src/lib/clapper-gtk/ui/clapper-gtk-video-placeholder.ui:25
msgid "External video output"
msgstr ""
msgstr "外部视频输出"
#: src/lib/clapper-gtk/ui/clapper-gtk-video-placeholder.ui:37
msgid "Used video sink cannot be embedded within application window"
msgstr ""
msgstr "已使用的视频接受器不能嵌入到应用程序窗口"
#: src/lib/clapper-gtk/clapper-gtk-status.c:79
msgid "Unplayable Content"

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <gio/gio.h>

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -1,45 +0,0 @@
/* Clapper Playback Library
* Copyright (C) 2025 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined(__CLAPPER_INSIDE__) && !defined(CLAPPER_COMPILATION)
#error "Only <clapper/clapper.h> can be included directly."
#endif
#include <glib.h>
#include <glib-object.h>
#include <clapper/clapper-visibility.h>
#include <clapper/clapper-enhancer-proxy-list.h>
G_BEGIN_DECLS
CLAPPER_API
void clapper_init (int *argc, char **argv[]);
CLAPPER_API
gboolean clapper_init_check (int *argc, char **argv[]);
CLAPPER_DEPRECATED
gboolean clapper_enhancer_check (GType iface_type, const gchar *scheme, const gchar *host, const gchar **name);
CLAPPER_API
ClapperEnhancerProxyList * clapper_get_global_enhancer_proxies (void);
G_END_DECLS

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -1,107 +0,0 @@
/* Clapper Playback Library
* Copyright (C) 2025 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <glib.h>
#include <glib-object.h>
G_BEGIN_DECLS
G_GNUC_INTERNAL
void clapper_cache_initialize (void);
G_GNUC_INTERNAL
gboolean clapper_cache_is_disabled (void);
G_GNUC_INTERNAL
GMappedFile * clapper_cache_open (const gchar *filename, const gchar **data, GError **error);
G_GNUC_INTERNAL
gboolean clapper_cache_read_boolean (const gchar **data);
G_GNUC_INTERNAL
gint clapper_cache_read_int (const gchar **data);
G_GNUC_INTERNAL
guint clapper_cache_read_uint (const gchar **data);
G_GNUC_INTERNAL
gint64 clapper_cache_read_int64 (const gchar **data);
G_GNUC_INTERNAL
gdouble clapper_cache_read_double (const gchar **data);
G_GNUC_INTERNAL
const gchar * clapper_cache_read_string (const gchar **data);
G_GNUC_INTERNAL
const guint8 * clapper_cache_read_data (const gchar **data, gsize *size);
G_GNUC_INTERNAL
GType clapper_cache_read_enum (const gchar **data);
G_GNUC_INTERNAL
GType clapper_cache_read_flags (const gchar **data);
G_GNUC_INTERNAL
GType clapper_cache_read_iface (const gchar **data);
G_GNUC_INTERNAL
GParamSpec * clapper_cache_read_pspec (const gchar **data);
G_GNUC_INTERNAL
GByteArray * clapper_cache_create (void);
G_GNUC_INTERNAL
void clapper_cache_store_boolean (GByteArray *bytes, gboolean val);
G_GNUC_INTERNAL
void clapper_cache_store_int (GByteArray *bytes, gint val);
G_GNUC_INTERNAL
void clapper_cache_store_uint (GByteArray *bytes, guint val);
G_GNUC_INTERNAL
void clapper_cache_store_int64 (GByteArray *bytes, gint64 val);
G_GNUC_INTERNAL
void clapper_cache_store_double (GByteArray *bytes, gdouble val);
G_GNUC_INTERNAL
void clapper_cache_store_string (GByteArray *bytes, const gchar *val);
G_GNUC_INTERNAL
void clapper_cache_store_data (GByteArray *bytes, const guint8 *val, gsize val_size);
G_GNUC_INTERNAL
void clapper_cache_store_enum (GByteArray *bytes, GType enum_type);
G_GNUC_INTERNAL
void clapper_cache_store_flags (GByteArray *bytes, GType flags_type);
G_GNUC_INTERNAL
gboolean clapper_cache_store_iface (GByteArray *bytes, GType iface);
G_GNUC_INTERNAL
gboolean clapper_cache_store_pspec (GByteArray *bytes, GParamSpec *pspec);
G_GNUC_INTERNAL
gboolean clapper_cache_write (const gchar *filename, GByteArray *bytes, GError **error);
G_END_DECLS

View File

@@ -1,541 +0,0 @@
/* Clapper Playback Library
* Copyright (C) 2025 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
*/
#include "clapper-cache-private.h"
#include "clapper-version.h"
#include "clapper-extractable.h"
#include "clapper-reactable.h"
#define CLAPPER_CACHE_HEADER "CLAPPER"
typedef enum
{
CLAPPER_CACHE_IFACE_EXTRACTABLE = 1,
CLAPPER_CACHE_IFACE_REACTABLE,
} ClapperCacheIfaces;
static GArray *enum_registry = NULL;
static GArray *flags_registry = NULL;
static gboolean cache_disabled = FALSE;
void
clapper_cache_initialize (void)
{
const gchar *env = g_getenv ("CLAPPER_DISABLE_CACHE");
if (G_LIKELY (!env || !g_str_has_prefix (env, "1"))) {
enum_registry = g_array_new (FALSE, TRUE, sizeof (GEnumValue *));
flags_registry = g_array_new (FALSE, TRUE, sizeof (GFlagsValue *));
} else {
cache_disabled = TRUE;
}
}
gboolean
clapper_cache_is_disabled (void)
{
return cache_disabled;
}
GMappedFile *
clapper_cache_open (const gchar *filename, const gchar **data, GError **error)
{
GMappedFile *file;
if (G_UNLIKELY (cache_disabled))
return NULL;
if (!(file = g_mapped_file_new (filename, FALSE, error)))
return NULL;
if (G_UNLIKELY (g_mapped_file_get_length (file) == 0)) {
g_mapped_file_unref (file);
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
"File is empty");
return NULL;
}
*data = g_mapped_file_get_contents (file);
/* Header name check */
if (G_UNLIKELY (g_strcmp0 (*data, CLAPPER_CACHE_HEADER) != 0)) {
g_mapped_file_unref (file);
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
"Invalid file header");
return NULL;
}
*data += strlen (*data) + 1;
/* Header version check */
if (clapper_cache_read_uint (data) != CLAPPER_VERSION_HEX) {
g_mapped_file_unref (file);
/* Just different version, so no error set */
return NULL;
}
return file;
}
inline gboolean
clapper_cache_read_boolean (const gchar **data)
{
gboolean val = *(const gboolean *) *data;
*data += sizeof (gboolean);
return val;
}
inline gint
clapper_cache_read_int (const gchar **data)
{
gint val = *(const gint *) *data;
*data += sizeof (gint);
return val;
}
inline guint
clapper_cache_read_uint (const gchar **data)
{
guint val = *(const guint *) *data;
*data += sizeof (guint);
return val;
}
inline gint64
clapper_cache_read_int64 (const gchar **data)
{
gint64 val = *(const gint64 *) *data;
*data += sizeof (gint64);
return val;
}
inline gdouble
clapper_cache_read_double (const gchar **data)
{
gdouble val = *(const gdouble *) *data;
*data += sizeof (gdouble);
return val;
}
inline const gchar *
clapper_cache_read_string (const gchar **data)
{
const gboolean is_null = clapper_cache_read_boolean (data);
const gchar *str = NULL;
if (!is_null) {
str = *data;
*data += strlen (str) + 1;
}
return str;
}
inline const guint8 *
clapper_cache_read_data (const gchar **data, gsize *size)
{
const guint8 *val = NULL;
*size = *(const gsize *) *data;
*data += sizeof (gsize);
if (G_LIKELY (*size > 0)) {
val = (const guint8 *) *data;
*data += *size;
}
return val;
}
inline GType
clapper_cache_read_enum (const gchar **data)
{
GType type;
const gchar *enum_name;
guint i, n_values;
enum_name = clapper_cache_read_string (data);
n_values = clapper_cache_read_uint (data);
/* If not registered yet */
if ((type = g_type_from_name (enum_name)) == 0) {
GEnumValue *values = g_new0 (GEnumValue, n_values + 1);
for (i = 0; i < n_values; ++i) {
values[i].value = clapper_cache_read_int (data);
values[i].value_name = g_intern_string (clapper_cache_read_string (data));
values[i].value_nick = g_intern_string (clapper_cache_read_string (data));
}
g_array_append_val (enum_registry, values); // store statically
type = g_enum_register_static (g_intern_string (enum_name),
g_array_index (enum_registry, GEnumValue *, enum_registry->len - 1));
} else {
/* Skip over data */
for (i = 0; i < n_values; ++i) {
clapper_cache_read_int (data); // value
clapper_cache_read_string (data); // value_name
clapper_cache_read_string (data); // value_nick
}
}
return type;
}
inline GType
clapper_cache_read_flags (const gchar **data)
{
GType type;
const gchar *flags_name;
guint i, n_values;
flags_name = clapper_cache_read_string (data);
n_values = clapper_cache_read_uint (data);
/* If not registered yet */
if ((type = g_type_from_name (flags_name)) == 0) {
GFlagsValue *values = g_new0 (GFlagsValue, n_values + 1);
for (i = 0; i < n_values; ++i) {
values[i].value = clapper_cache_read_int (data);
values[i].value_name = g_intern_string (clapper_cache_read_string (data));
values[i].value_nick = g_intern_string (clapper_cache_read_string (data));
}
g_array_append_val (flags_registry, values); // store statically
type = g_flags_register_static (g_intern_string (flags_name),
g_array_index (flags_registry, GFlagsValue *, flags_registry->len - 1));
} else {
/* Skip over data */
for (i = 0; i < n_values; ++i) {
clapper_cache_read_int (data); // value
clapper_cache_read_string (data); // value_name
clapper_cache_read_string (data); // value_nick
}
}
return type;
}
GType
clapper_cache_read_iface (const gchar **data)
{
gint iface_id = clapper_cache_read_int (data);
switch (iface_id) {
case CLAPPER_CACHE_IFACE_EXTRACTABLE:
return CLAPPER_TYPE_EXTRACTABLE;
case CLAPPER_CACHE_IFACE_REACTABLE:
return CLAPPER_TYPE_REACTABLE;
default:
return 0;
}
}
GParamSpec *
clapper_cache_read_pspec (const gchar **data)
{
GParamSpec *pspec;
GType value_type;
const gchar *name, *nick, *blurb;
GParamFlags flags;
value_type = *(const GType *) *data;
*data += sizeof (GType);
name = clapper_cache_read_string (data);
nick = clapper_cache_read_string (data);
blurb = clapper_cache_read_string (data);
flags = *(const GParamFlags *) *data;
*data += sizeof (GParamFlags);
/* NOTE: C does not guarantee order in which function arguments
* are evaluated, so read into variables and then create pspec */
switch (value_type) {
case G_TYPE_BOOLEAN:
pspec = g_param_spec_boolean (name, nick, blurb,
clapper_cache_read_boolean (data), flags);
break;
case G_TYPE_INT:{
gint minimum = clapper_cache_read_int (data);
gint maximum = clapper_cache_read_int (data);
gint default_value = clapper_cache_read_int (data);
pspec = g_param_spec_int (name, nick, blurb,
minimum, maximum, default_value, flags);
break;
}
case G_TYPE_UINT:{
guint minimum = clapper_cache_read_uint (data);
guint maximum = clapper_cache_read_uint (data);
guint default_value = clapper_cache_read_uint (data);
pspec = g_param_spec_uint (name, nick, blurb,
minimum, maximum, default_value, flags);
break;
}
case G_TYPE_DOUBLE:{
gdouble minimum = clapper_cache_read_double (data);
gdouble maximum = clapper_cache_read_double (data);
gdouble default_value = clapper_cache_read_double (data);
pspec = g_param_spec_double (name, nick, blurb,
minimum, maximum, default_value, flags);
break;
}
case G_TYPE_STRING:
pspec = g_param_spec_string (name, nick, blurb,
clapper_cache_read_string (data), flags);
break;
case G_TYPE_ENUM:{
GType enum_type = clapper_cache_read_enum (data);
gint default_value = clapper_cache_read_int (data);
pspec = g_param_spec_enum (name, nick, blurb,
enum_type, default_value, flags);
break;
}
case G_TYPE_FLAGS:{
GType flags_type = clapper_cache_read_flags (data);
guint default_value = clapper_cache_read_uint (data);
pspec = g_param_spec_flags (name, nick, blurb,
flags_type, default_value, flags);
break;
}
default:
return NULL;
}
return g_param_spec_ref_sink (pspec);
}
GByteArray *
clapper_cache_create (void)
{
GByteArray *bytes;
if (G_UNLIKELY (cache_disabled))
return NULL;
bytes = g_byte_array_new ();
/* NOTE: We do not store whether string is NULL here, since it never is */
g_byte_array_append (bytes, (const guint8 *) CLAPPER_CACHE_HEADER, 8); // 7 + 1
clapper_cache_store_uint (bytes, CLAPPER_VERSION_HEX);
return bytes;
}
inline void
clapper_cache_store_boolean (GByteArray *bytes, gboolean val)
{
g_byte_array_append (bytes, (const guint8 *) &val, sizeof (gboolean));
}
inline void
clapper_cache_store_int (GByteArray *bytes, gint val)
{
g_byte_array_append (bytes, (const guint8 *) &val, sizeof (gint));
}
inline void
clapper_cache_store_uint (GByteArray *bytes, guint val)
{
g_byte_array_append (bytes, (const guint8 *) &val, sizeof (guint));
}
inline void
clapper_cache_store_int64 (GByteArray *bytes, gint64 val)
{
g_byte_array_append (bytes, (const guint8 *) &val, sizeof (gint64));
}
inline void
clapper_cache_store_double (GByteArray *bytes, gdouble val)
{
g_byte_array_append (bytes, (const guint8 *) &val, sizeof (gdouble));
}
inline void
clapper_cache_store_string (GByteArray *bytes, const gchar *val)
{
/* Distinguish empty string from NULL */
const gboolean is_null = (val == NULL);
clapper_cache_store_boolean (bytes, is_null);
if (!is_null)
g_byte_array_append (bytes, (const guint8 *) val, strlen (val) + 1);
}
inline void
clapper_cache_store_data (GByteArray *bytes, const guint8 *val, gsize val_size)
{
g_byte_array_append (bytes, (const guint8 *) &val_size, sizeof (gsize));
if (G_LIKELY (val_size > 0))
g_byte_array_append (bytes, val, val_size);
}
inline void
clapper_cache_store_enum (GByteArray *bytes, GType enum_type)
{
GEnumClass *enum_class = G_ENUM_CLASS (g_type_class_peek (enum_type));
guint i;
clapper_cache_store_string (bytes, g_type_name (enum_type));
clapper_cache_store_uint (bytes, enum_class->n_values);
for (i = 0; i < enum_class->n_values; ++i) {
clapper_cache_store_int (bytes, enum_class->values[i].value);
clapper_cache_store_string (bytes, enum_class->values[i].value_name);
clapper_cache_store_string (bytes, enum_class->values[i].value_nick);
}
}
inline void
clapper_cache_store_flags (GByteArray *bytes, GType flags_type)
{
GFlagsClass *flags_class = G_FLAGS_CLASS (g_type_class_peek (flags_type));
guint i;
clapper_cache_store_string (bytes, g_type_name (flags_type));
clapper_cache_store_uint (bytes, flags_class->n_values);
for (i = 0; i < flags_class->n_values; ++i) {
clapper_cache_store_int (bytes, flags_class->values[i].value);
clapper_cache_store_string (bytes, flags_class->values[i].value_name);
clapper_cache_store_string (bytes, flags_class->values[i].value_nick);
}
}
gboolean
clapper_cache_store_iface (GByteArray *bytes, GType iface)
{
gint iface_id = 0;
if (iface == CLAPPER_TYPE_EXTRACTABLE)
iface_id = CLAPPER_CACHE_IFACE_EXTRACTABLE;
else if (iface == CLAPPER_TYPE_REACTABLE)
iface_id = CLAPPER_CACHE_IFACE_REACTABLE;
else
return FALSE;
clapper_cache_store_int (bytes, iface_id);
return TRUE;
}
gboolean
clapper_cache_store_pspec (GByteArray *bytes, GParamSpec *pspec)
{
GParamFlags flags;
const gboolean is_enum = G_IS_PARAM_SPEC_ENUM (pspec);
const gboolean is_flags = (!is_enum && G_IS_PARAM_SPEC_FLAGS (pspec));
if (is_enum) {
GType enum_type = G_TYPE_ENUM;
g_byte_array_append (bytes, (const guint8 *) &enum_type, sizeof (GType));
} else if (is_flags) {
GType flags_type = G_TYPE_FLAGS;
g_byte_array_append (bytes, (const guint8 *) &flags_type, sizeof (GType));
} else {
g_byte_array_append (bytes, (const guint8 *) &pspec->value_type, sizeof (GType));
}
clapper_cache_store_string (bytes, g_param_spec_get_name (pspec));
clapper_cache_store_string (bytes, g_param_spec_get_nick (pspec));
clapper_cache_store_string (bytes, g_param_spec_get_blurb (pspec));
flags = pspec->flags;
flags &= ~G_PARAM_STATIC_STRINGS; // Data read from cache is never static
g_byte_array_append (bytes, (const guint8 *) &flags, sizeof (GParamFlags));
switch (pspec->value_type) {
case G_TYPE_BOOLEAN:{
GParamSpecBoolean *p = (GParamSpecBoolean *) pspec;
clapper_cache_store_boolean (bytes, p->default_value);
break;
}
case G_TYPE_INT:{
GParamSpecInt *p = (GParamSpecInt *) pspec;
clapper_cache_store_int (bytes, p->minimum);
clapper_cache_store_int (bytes, p->maximum);
clapper_cache_store_int (bytes, p->default_value);
break;
}
case G_TYPE_UINT:{
GParamSpecUInt *p = (GParamSpecUInt *) pspec;
clapper_cache_store_uint (bytes, p->minimum);
clapper_cache_store_uint (bytes, p->maximum);
clapper_cache_store_uint (bytes, p->default_value);
break;
}
case G_TYPE_DOUBLE:{
GParamSpecDouble *p = (GParamSpecDouble *) pspec;
clapper_cache_store_double (bytes, p->minimum);
clapper_cache_store_double (bytes, p->maximum);
clapper_cache_store_double (bytes, p->default_value);
break;
}
case G_TYPE_STRING:{
GParamSpecString *p = (GParamSpecString *) pspec;
clapper_cache_store_string (bytes, p->default_value);
break;
}
default:{
if (is_enum) {
GParamSpecEnum *p = (GParamSpecEnum *) pspec;
clapper_cache_store_enum (bytes, pspec->value_type);
clapper_cache_store_int (bytes, p->default_value);
break;
} else if (is_flags) {
GParamSpecFlags *p = (GParamSpecFlags *) pspec;
clapper_cache_store_flags (bytes, pspec->value_type);
clapper_cache_store_uint (bytes, p->default_value);
break;
}
return FALSE;
}
}
return TRUE;
}
gboolean
clapper_cache_write (const gchar *filename, GByteArray *bytes, GError **error)
{
gchar *dirname = g_path_get_dirname (filename);
gboolean has_dir;
has_dir = (g_mkdir_with_parents (dirname, 0755) == 0);
g_free (dirname);
if (!has_dir) {
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
"Could not create directory to store cache content");
return FALSE;
}
/* Using "g_file_set_contents" to replace file atomically */
return g_file_set_contents (filename, (const gchar *) bytes->data, bytes->len, error);
}

View File

@@ -1,44 +0,0 @@
/* Clapper Playback Library
* Copyright (C) 2025 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <glib.h>
#include <glib-object.h>
#include "clapper-enhancer-proxy-list.h"
#include "clapper-enhancer-proxy.h"
G_BEGIN_DECLS
G_GNUC_INTERNAL
ClapperEnhancerProxyList * clapper_enhancer_proxy_list_new_named (const gchar *name);
G_GNUC_INTERNAL
void clapper_enhancer_proxy_list_take_proxy (ClapperEnhancerProxyList *list, ClapperEnhancerProxy *proxy);
G_GNUC_INTERNAL
void clapper_enhancer_proxy_list_fill_from_global_proxies (ClapperEnhancerProxyList *list);
G_GNUC_INTERNAL
void clapper_enhancer_proxy_list_sort (ClapperEnhancerProxyList *list);
G_GNUC_INTERNAL
gboolean clapper_enhancer_proxy_list_has_proxy_with_interface (ClapperEnhancerProxyList *list, GType iface_type);
G_END_DECLS

View File

@@ -1,351 +0,0 @@
/* Clapper Playback Library
* Copyright (C) 2025 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
*/
/**
* ClapperEnhancerProxyList:
*
* A list of enhancer proxies.
*
* Since: 0.10
*/
#include <gio/gio.h>
#include "clapper-basic-functions.h"
#include "clapper-enhancer-proxy-list-private.h"
#include "clapper-enhancer-proxy-private.h"
#define GST_CAT_DEFAULT clapper_enhancer_proxy_list_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
struct _ClapperEnhancerProxyList
{
GstObject parent;
GPtrArray *proxies;
};
enum
{
PROP_0,
PROP_N_PROXIES,
PROP_LAST
};
static void clapper_enhancer_proxy_list_model_iface_init (GListModelInterface *iface);
#define parent_class clapper_enhancer_proxy_list_parent_class
G_DEFINE_TYPE_WITH_CODE (ClapperEnhancerProxyList, clapper_enhancer_proxy_list, GST_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, clapper_enhancer_proxy_list_model_iface_init));
static GParamSpec *param_specs[PROP_LAST] = { NULL, };
static GType
clapper_enhancer_proxy_list_model_get_item_type (GListModel *model)
{
return CLAPPER_TYPE_ENHANCER_PROXY;
}
static guint
clapper_enhancer_proxy_list_model_get_n_items (GListModel *model)
{
return CLAPPER_ENHANCER_PROXY_LIST_CAST (model)->proxies->len;
}
static gpointer
clapper_enhancer_proxy_list_model_get_item (GListModel *model, guint index)
{
ClapperEnhancerProxyList *self = CLAPPER_ENHANCER_PROXY_LIST_CAST (model);
ClapperEnhancerProxy *proxy = NULL;
if (G_LIKELY (index < self->proxies->len))
proxy = gst_object_ref (g_ptr_array_index (self->proxies, index));
return proxy;
}
static void
clapper_enhancer_proxy_list_model_iface_init (GListModelInterface *iface)
{
iface->get_item_type = clapper_enhancer_proxy_list_model_get_item_type;
iface->get_n_items = clapper_enhancer_proxy_list_model_get_n_items;
iface->get_item = clapper_enhancer_proxy_list_model_get_item;
}
/*
* clapper_enhancer_proxy_list_new_named:
* @name: (nullable): name of the #GstObject
*
* Returns: (transfer full): a new #ClapperEnhancerProxyList instance
*/
ClapperEnhancerProxyList *
clapper_enhancer_proxy_list_new_named (const gchar *name)
{
ClapperEnhancerProxyList *list;
list = g_object_new (CLAPPER_TYPE_ENHANCER_PROXY_LIST,
"name", name, NULL);
gst_object_ref_sink (list);
return list;
}
void
clapper_enhancer_proxy_list_take_proxy (ClapperEnhancerProxyList *self, ClapperEnhancerProxy *proxy)
{
g_ptr_array_add (self->proxies, proxy);
gst_object_set_parent (GST_OBJECT_CAST (proxy), GST_OBJECT_CAST (self));
}
/*
* clapper_enhancer_proxy_list_fill_from_global_proxies:
*
* Fill list with unconfigured proxies from global proxies list.
*/
void
clapper_enhancer_proxy_list_fill_from_global_proxies (ClapperEnhancerProxyList *self)
{
ClapperEnhancerProxyList *global_list = clapper_get_global_enhancer_proxies ();
static guint _list_id = 0;
guint i;
for (i = 0; i < global_list->proxies->len; ++i) {
ClapperEnhancerProxy *proxy, *proxy_copy;
gchar obj_name[64];
proxy = clapper_enhancer_proxy_list_peek_proxy (global_list, i);
/* Name newly created proxy, very useful for debugging. Keep index per
* list, so it will be the same as the player that proxy belongs to. */
g_snprintf (obj_name, sizeof (obj_name), "%s-proxy%u",
clapper_enhancer_proxy_get_friendly_name (proxy), _list_id);
proxy_copy = clapper_enhancer_proxy_copy (proxy, obj_name);
clapper_enhancer_proxy_list_take_proxy (self, proxy_copy);
}
_list_id++;
}
static gint
_sort_values_by_name (ClapperEnhancerProxy *proxy_a, ClapperEnhancerProxy *proxy_b)
{
return g_ascii_strcasecmp (
clapper_enhancer_proxy_get_friendly_name (proxy_a),
clapper_enhancer_proxy_get_friendly_name (proxy_b));
}
/*
* clapper_enhancer_proxy_list_sort:
*
* Sort all list elements by enhancer friendly name.
*/
void
clapper_enhancer_proxy_list_sort (ClapperEnhancerProxyList *self)
{
g_ptr_array_sort_values (self->proxies, (GCompareFunc) _sort_values_by_name);
}
/*
* clapper_enhancer_proxy_list_has_proxy_with_interface:
* @iface_type: an interface #GType
*
* Check if any enhancer implementing given interface type is available.
*
* Returns: whether any enhancer proxy was found.
*/
gboolean
clapper_enhancer_proxy_list_has_proxy_with_interface (ClapperEnhancerProxyList *self, GType iface_type)
{
guint i;
for (i = 0; i < self->proxies->len; ++i) {
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_peek_proxy (self, i);
if (clapper_enhancer_proxy_target_has_interface (proxy, iface_type))
return TRUE;
}
return FALSE;
}
/**
* clapper_enhancer_proxy_list_get_proxy:
* @list: a #ClapperEnhancerProxyList
* @index: an enhancer proxy index
*
* Get the #ClapperEnhancerProxy at index.
*
* This behaves the same as [method@Gio.ListModel.get_item], and is here
* for code uniformity and convenience to avoid type casting by user.
*
* Returns: (transfer full) (nullable): The #ClapperEnhancerProxy at @index.
*
* Since: 0.10
*/
ClapperEnhancerProxy *
clapper_enhancer_proxy_list_get_proxy (ClapperEnhancerProxyList *self, guint index)
{
g_return_val_if_fail (CLAPPER_IS_ENHANCER_PROXY_LIST (self), NULL);
return g_list_model_get_item (G_LIST_MODEL (self), index);
}
/**
* clapper_enhancer_proxy_list_peek_proxy: (skip)
* @list: a #ClapperEnhancerProxyList
* @index: an enhancer proxy index
*
* Get the #ClapperEnhancerProxy at index.
*
* Similar to [method@Clapper.EnhancerProxyList.get_proxy], but does not take
* a new reference on proxy.
*
* Proxies in a list are only removed when a [class@Clapper.Player] instance
* they originate from is destroyed, so do not use returned object afterwards
* unless you take an additional reference on it.
*
* Returns: (transfer none) (nullable): The #ClapperEnhancerProxy at @index.
*
* Since: 0.10
*/
ClapperEnhancerProxy *
clapper_enhancer_proxy_list_peek_proxy (ClapperEnhancerProxyList *self, guint index)
{
g_return_val_if_fail (CLAPPER_IS_ENHANCER_PROXY_LIST (self), NULL);
return g_ptr_array_index (self->proxies, index);
}
/**
* clapper_enhancer_proxy_list_get_proxy_by_module:
* @list: a #ClapperEnhancerProxyList
* @module_name: an enhancer module name
*
* Get the #ClapperEnhancerProxy by module name as defined in its plugin file.
*
* A convenience function to find a #ClapperEnhancerProxy by its unique
* module name in the list.
*
* Returns: (transfer full) (nullable): The #ClapperEnhancerProxy with requested module name.
*
* Since: 0.10
*/
ClapperEnhancerProxy *
clapper_enhancer_proxy_list_get_proxy_by_module (ClapperEnhancerProxyList *self, const gchar *module_name)
{
guint i;
g_return_val_if_fail (CLAPPER_IS_ENHANCER_PROXY_LIST (self), NULL);
g_return_val_if_fail (module_name != NULL, NULL);
for (i = 0; i < self->proxies->len; ++i) {
ClapperEnhancerProxy *proxy = g_ptr_array_index (self->proxies, i);
if (strcmp (clapper_enhancer_proxy_get_module_name (proxy), module_name) == 0)
return gst_object_ref (proxy);
}
return NULL;
}
/**
* clapper_enhancer_proxy_list_get_n_proxies:
* @list: a #ClapperEnhancerProxyList
*
* Get the number of proxies in #ClapperEnhancerProxyList.
*
* This behaves the same as [method@Gio.ListModel.get_n_items], and is here
* for code uniformity and convenience to avoid type casting by user.
*
* Returns: The number of proxies in #ClapperEnhancerProxyList.
*
* Since: 0.10
*/
guint
clapper_enhancer_proxy_list_get_n_proxies (ClapperEnhancerProxyList *self)
{
g_return_val_if_fail (CLAPPER_IS_ENHANCER_PROXY_LIST (self), 0);
return g_list_model_get_n_items (G_LIST_MODEL (self));
}
static void
_proxy_remove_func (ClapperEnhancerProxy *proxy)
{
gst_object_unparent (GST_OBJECT_CAST (proxy));
gst_object_unref (proxy);
}
static void
clapper_enhancer_proxy_list_init (ClapperEnhancerProxyList *self)
{
self->proxies = g_ptr_array_new_with_free_func ((GDestroyNotify) _proxy_remove_func);
}
static void
clapper_enhancer_proxy_list_finalize (GObject *object)
{
ClapperEnhancerProxyList *self = CLAPPER_ENHANCER_PROXY_LIST_CAST (object);
GST_TRACE_OBJECT (self, "Finalize");
g_ptr_array_unref (self->proxies);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
clapper_enhancer_proxy_list_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
ClapperEnhancerProxyList *self = CLAPPER_ENHANCER_PROXY_LIST_CAST (object);
switch (prop_id) {
case PROP_N_PROXIES:
g_value_set_uint (value, clapper_enhancer_proxy_list_get_n_proxies (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clapper_enhancer_proxy_list_class_init (ClapperEnhancerProxyListClass *klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperenhancerproxylist", 0,
"Clapper Enhancer Proxy List");
gobject_class->get_property = clapper_enhancer_proxy_list_get_property;
gobject_class->finalize = clapper_enhancer_proxy_list_finalize;
/**
* ClapperEnhancerProxyList:n-proxies:
*
* Number of proxies in the list.
*
* Since: 0.10
*/
param_specs[PROP_N_PROXIES] = g_param_spec_uint ("n-proxies",
NULL, NULL, 0, G_MAXUINT, 0,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
}

View File

@@ -1,52 +0,0 @@
/* Clapper Playback Library
* Copyright (C) 2025 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined(__CLAPPER_INSIDE__) && !defined(CLAPPER_COMPILATION)
#error "Only <clapper/clapper.h> can be included directly."
#endif
#include <glib.h>
#include <glib-object.h>
#include <gst/gst.h>
#include <clapper/clapper-visibility.h>
#include <clapper/clapper-enhancer-proxy.h>
G_BEGIN_DECLS
#define CLAPPER_TYPE_ENHANCER_PROXY_LIST (clapper_enhancer_proxy_list_get_type())
#define CLAPPER_ENHANCER_PROXY_LIST_CAST(obj) ((ClapperEnhancerProxyList *)(obj))
CLAPPER_API
G_DECLARE_FINAL_TYPE (ClapperEnhancerProxyList, clapper_enhancer_proxy_list, CLAPPER, ENHANCER_PROXY_LIST, GstObject)
CLAPPER_API
ClapperEnhancerProxy * clapper_enhancer_proxy_list_get_proxy (ClapperEnhancerProxyList *list, guint index);
CLAPPER_API
ClapperEnhancerProxy * clapper_enhancer_proxy_list_peek_proxy (ClapperEnhancerProxyList *list, guint index);
CLAPPER_API
ClapperEnhancerProxy * clapper_enhancer_proxy_list_get_proxy_by_module (ClapperEnhancerProxyList *list, const gchar *module_name);
CLAPPER_API
guint clapper_enhancer_proxy_list_get_n_proxies (ClapperEnhancerProxyList *list);
G_END_DECLS

View File

@@ -1,56 +0,0 @@
/* Clapper Playback Library
* Copyright (C) 2025 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <glib.h>
#include <glib-object.h>
#include <gst/gst.h>
#include "clapper-enhancer-proxy.h"
G_BEGIN_DECLS
G_GNUC_INTERNAL
ClapperEnhancerProxy * clapper_enhancer_proxy_new_global_take (GObject *peas_info); // Using parent type for building without libpeas
G_GNUC_INTERNAL
ClapperEnhancerProxy * clapper_enhancer_proxy_copy (ClapperEnhancerProxy *src_proxy, const gchar *copy_name);
G_GNUC_INTERNAL
gboolean clapper_enhancer_proxy_fill_from_cache (ClapperEnhancerProxy *proxy);
G_GNUC_INTERNAL
gboolean clapper_enhancer_proxy_fill_from_instance (ClapperEnhancerProxy *proxy, GObject *enhancer);
G_GNUC_INTERNAL
void clapper_enhancer_proxy_export_to_cache (ClapperEnhancerProxy *proxy);
G_GNUC_INTERNAL
GObject * clapper_enhancer_proxy_get_peas_info (ClapperEnhancerProxy *proxy);
G_GNUC_INTERNAL
gboolean clapper_enhancer_proxy_has_locally_set (ClapperEnhancerProxy *proxy, const gchar *property_name);
G_GNUC_INTERNAL
GstStructure * clapper_enhancer_proxy_make_current_config (ClapperEnhancerProxy *proxy);
G_GNUC_INTERNAL
void clapper_enhancer_proxy_apply_config_to_enhancer (ClapperEnhancerProxy *proxy, const GstStructure *config, GObject *enhancer);
G_END_DECLS

File diff suppressed because it is too large Load Diff

View File

@@ -1,85 +0,0 @@
/* Clapper Playback Library
* Copyright (C) 2025 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined(__CLAPPER_INSIDE__) && !defined(CLAPPER_COMPILATION)
#error "Only <clapper/clapper.h> can be included directly."
#endif
#include <glib.h>
#include <glib-object.h>
#include <gio/gio.h>
#include <gst/gst.h>
#include <clapper/clapper-visibility.h>
G_BEGIN_DECLS
#define CLAPPER_TYPE_ENHANCER_PROXY (clapper_enhancer_proxy_get_type())
#define CLAPPER_ENHANCER_PROXY_CAST(obj) ((ClapperEnhancerProxy *)(obj))
CLAPPER_API
G_DECLARE_FINAL_TYPE (ClapperEnhancerProxy, clapper_enhancer_proxy, CLAPPER, ENHANCER_PROXY, GstObject)
CLAPPER_API
const gchar * clapper_enhancer_proxy_get_friendly_name (ClapperEnhancerProxy *proxy);
CLAPPER_API
const gchar * clapper_enhancer_proxy_get_module_name (ClapperEnhancerProxy *proxy);
CLAPPER_API
const gchar * clapper_enhancer_proxy_get_module_dir (ClapperEnhancerProxy *proxy);
CLAPPER_API
const gchar * clapper_enhancer_proxy_get_description (ClapperEnhancerProxy *proxy);
CLAPPER_API
const gchar * clapper_enhancer_proxy_get_version (ClapperEnhancerProxy *proxy);
CLAPPER_API
const gchar * clapper_enhancer_proxy_get_extra_data (ClapperEnhancerProxy *proxy, const gchar *key);
CLAPPER_API
gboolean clapper_enhancer_proxy_extra_data_lists_value (ClapperEnhancerProxy *proxy, const gchar *key, const gchar *value);
CLAPPER_API
GType * clapper_enhancer_proxy_get_target_interfaces (ClapperEnhancerProxy *proxy, guint *n_interfaces);
CLAPPER_API
gboolean clapper_enhancer_proxy_target_has_interface (ClapperEnhancerProxy *proxy, GType iface_type);
CLAPPER_API
GParamSpec ** clapper_enhancer_proxy_get_target_properties (ClapperEnhancerProxy *proxy, guint *n_properties);
CLAPPER_API
GSettings * clapper_enhancer_proxy_get_settings (ClapperEnhancerProxy *proxy);
CLAPPER_API
void clapper_enhancer_proxy_set_locally (ClapperEnhancerProxy *proxy, const gchar *first_property_name, ...) G_GNUC_NULL_TERMINATED;
CLAPPER_API
void clapper_enhancer_proxy_set_locally_with_table (ClapperEnhancerProxy *proxy, GHashTable *table);
CLAPPER_API
void clapper_enhancer_proxy_set_target_creation_allowed (ClapperEnhancerProxy *proxy, gboolean allowed);
CLAPPER_API
gboolean clapper_enhancer_proxy_get_target_creation_allowed (ClapperEnhancerProxy *proxy);
G_END_DECLS

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
@@ -21,15 +22,21 @@
#include <glib.h>
#include <glib-object.h>
#include "clapper-enhancer-proxy-list.h"
#include "clapper-enhancer-proxy.h"
G_BEGIN_DECLS
G_GNUC_INTERNAL
void clapper_enhancers_loader_initialize (ClapperEnhancerProxyList *proxies);
void clapper_enhancers_loader_initialize (void);
G_GNUC_INTERNAL
GObject * clapper_enhancers_loader_create_enhancer (ClapperEnhancerProxy *proxy, GType iface_type);
gboolean clapper_enhancers_loader_has_enhancers (GType iface_type);
G_GNUC_INTERNAL
gchar ** clapper_enhancers_loader_get_schemes (GType iface_type);
G_GNUC_INTERNAL
gboolean clapper_enhancers_loader_check (GType iface_type, const gchar *scheme, const gchar *host, const gchar **name);
G_GNUC_INTERNAL
GObject * clapper_enhancers_loader_create_enhancer_for_uri (GType iface_type, GUri *uri);
G_END_DECLS

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
@@ -27,14 +28,11 @@ static HMODULE _enhancers_dll_handle = NULL;
#endif
#include "clapper-enhancers-loader-private.h"
#include "clapper-enhancer-proxy-list-private.h"
#include "clapper-enhancer-proxy-private.h"
// Supported interfaces
#include "clapper-extractable.h"
#include "clapper-reactable.h"
#include <clapper-functionalities-availability.h>
#define ENHANCER_INTERFACES "X-Interfaces"
#define ENHANCER_SCHEMES "X-Schemes"
#define ENHANCER_HOSTS "X-Hosts"
#define ENHANCER_IFACE_NAME_FROM_TYPE(type) (g_type_name (type) + 7) // strip "Clapper" prefix
#define GST_CAT_DEFAULT clapper_enhancers_loader_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
@@ -54,39 +52,16 @@ _import_enhancers (const gchar *enhancers_path)
g_strfreev (dir_paths);
}
static GObject *
_force_create_enhancer (ClapperEnhancerProxy *proxy, GType iface_type)
{
GObject *enhancer = NULL;
PeasPluginInfo *info = (PeasPluginInfo *) clapper_enhancer_proxy_get_peas_info (proxy);
g_mutex_lock (&load_lock);
if (!peas_plugin_info_is_loaded (info) && !peas_engine_load_plugin (_engine, info)) {
GST_ERROR ("Could not load enhancer: %s", peas_plugin_info_get_module_name (info));
} else if (!peas_engine_provides_extension (_engine, info, iface_type)) {
GST_LOG ("No \"%s\" enhancer in module: %s", g_type_name (iface_type),
peas_plugin_info_get_module_name (info));
} else {
enhancer = peas_engine_create_extension (_engine, info, iface_type, NULL);
}
g_mutex_unlock (&load_lock);
return enhancer;
}
/*
* clapper_enhancers_loader_initialize:
*
* Initializes #PeasEngine with directories that store enhancers.
*/
void
clapper_enhancers_loader_initialize (ClapperEnhancerProxyList *proxies)
clapper_enhancers_loader_initialize (void)
{
const gchar *enhancers_path;
gchar *custom_path = NULL;
guint i, n_items;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperenhancersloader", 0,
"Clapper Enhancer Loader");
@@ -99,8 +74,9 @@ clapper_enhancers_loader_initialize (ClapperEnhancerProxyList *proxies)
win_base_dir = g_win32_get_package_installation_directory_of_module (
_enhancers_dll_handle);
/* FIXME: Avoid hardcoded major version */
custom_path = g_build_filename (win_base_dir,
"lib", CLAPPER_API_NAME, "enhancers", NULL);
"lib", "clapper-0.0", "enhancers", NULL);
enhancers_path = custom_path; // assign temporarily
g_free (win_base_dir);
@@ -128,102 +104,321 @@ clapper_enhancers_loader_initialize (ClapperEnhancerProxyList *proxies)
_import_enhancers (enhancers_path);
}
n_items = g_list_model_get_n_items ((GListModel *) _engine);
for (i = 0; i < n_items; ++i) {
PeasPluginInfo *info = (PeasPluginInfo *) g_list_model_get_item ((GListModel *) _engine, i);
ClapperEnhancerProxy *proxy;
gboolean filled;
if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= GST_LEVEL_INFO) {
GListModel *list = (GListModel *) _engine;
guint i, n_items = g_list_model_get_n_items (list);
/* FIXME: 1.0: Remove together with features code and manager.
* These would clash with each other, so avoid loading these
* as enhancers when also compiled as part of the library. */
#if (CLAPPER_HAVE_MPRIS || CLAPPER_HAVE_DISCOVERER || CLAPPER_HAVE_SERVER)
guint f_index;
const gchar *module_name = peas_plugin_info_get_module_name (info);
const gchar *ported_features[] = {
#if CLAPPER_HAVE_MPRIS
"clapper-mpris",
#endif
#if CLAPPER_HAVE_DISCOVERER
"clapper-discoverer",
#endif
#if CLAPPER_HAVE_SERVER
"clapper-server",
#endif
};
for (f_index = 0; f_index < G_N_ELEMENTS (ported_features); ++f_index) {
if (strcmp (module_name, ported_features[f_index]) == 0) {
GST_INFO ("Skipped \"%s\" enhancer module, since its"
" loaded from deprecated feature object", module_name);
g_clear_object (&info);
}
for (i = 0; i < n_items; ++i) {
PeasPluginInfo *info = (PeasPluginInfo *) g_list_model_get_item (list, i);
GST_INFO ("Found enhancer: %s (%s)", peas_plugin_info_get_name (info),
peas_plugin_info_get_external_data (info, ENHANCER_INTERFACES));
g_object_unref (info);
}
if (!info) // cleared when exists as feature
continue;
#endif
/* Clapper supports only 1 proxy per plugin. Each plugin can
* ship 1 class, but it can implement more than 1 interface. */
proxy = clapper_enhancer_proxy_new_global_take ((GObject *) info);
/* Try to fill missing data from cache (fast).
* Otherwise make an instance and fill missing data from it (slow). */
if (!(filled = clapper_enhancer_proxy_fill_from_cache (proxy))) {
GObject *enhancer;
const GType main_types[] = { CLAPPER_TYPE_EXTRACTABLE, CLAPPER_TYPE_REACTABLE };
guint j;
/* We cannot ask libpeas for "any" of our main interfaces, so try each one until found */
for (j = 0; j < G_N_ELEMENTS (main_types); ++j) {
if ((enhancer = _force_create_enhancer (proxy, main_types[j]))) {
filled = clapper_enhancer_proxy_fill_from_instance (proxy, enhancer);
g_object_unref (enhancer);
clapper_enhancer_proxy_export_to_cache (proxy);
break;
}
}
}
if (G_LIKELY (filled)) {
GST_INFO ("Found enhancer: \"%s\" (%s)",
clapper_enhancer_proxy_get_friendly_name (proxy),
clapper_enhancer_proxy_get_module_name (proxy));
clapper_enhancer_proxy_list_take_proxy (proxies, proxy);
} else {
GST_WARNING ("Enhancer init failed: \"%s\" (%s)",
clapper_enhancer_proxy_get_friendly_name (proxy),
clapper_enhancer_proxy_get_module_name (proxy));
gst_object_unref (proxy);
}
GST_INFO ("Clapper enhancers initialized, found: %u", n_items);
}
clapper_enhancer_proxy_list_sort (proxies);
GST_INFO ("Clapper enhancers initialized, found: %u",
clapper_enhancer_proxy_list_get_n_proxies (proxies));
g_free (custom_path);
}
static inline gboolean
_is_name_listed (const gchar *name, const gchar *list_str)
{
gsize name_len = strlen (name);
guint i = 0;
while (list_str[i] != '\0') {
guint end = i;
while (list_str[end] != ';' && list_str[end] != '\0')
++end;
/* Compare letters count until separator and prefix of whole string */
if (end - i == name_len && g_str_has_prefix (list_str + i, name))
return TRUE;
i = end;
/* Move to the next letter after ';' */
if (list_str[i] != '\0')
++i;
}
return FALSE;
}
/*
* clapper_enhancers_loader_create_enhancer:
* @iface_type: a requested #GType
* @info: a #PeasPluginInfo
* clapper_enhancers_loader_get_info:
* @iface_type: an interface #GType
* @scheme: an URI scheme
* @host: (nullable): an URI host
*
* Creates a new enhancer object using @info.
* Returns: (transfer full) (nullable): available #PeasPluginInfo or %NULL.
*/
static PeasPluginInfo *
clapper_enhancers_loader_get_info (GType iface_type, const gchar *scheme, const gchar *host)
{
GListModel *list = (GListModel *) _engine;
PeasPluginInfo *found_info = NULL;
guint i, n_plugins = g_list_model_get_n_items (list);
const gchar *iface_name;
gboolean is_https;
if (n_plugins == 0) {
GST_INFO ("No Clapper enhancers found");
return NULL;
}
iface_name = ENHANCER_IFACE_NAME_FROM_TYPE (iface_type);
/* Strip common subdomains, so plugins do not
* have to list all combinations */
if (host) {
if (g_str_has_prefix (host, "www."))
host += 4;
else if (g_str_has_prefix (host, "m."))
host += 2;
}
GST_INFO ("Enhancer check, iface: %s, scheme: %s, host: %s",
iface_name, scheme, GST_STR_NULL (host));
is_https = (g_str_has_prefix (scheme, "http")
&& (scheme[4] == '\0' || (scheme[4] == 's' && scheme[5] == '\0')));
if (!host && is_https)
return NULL;
for (i = 0; i < n_plugins; ++i) {
PeasPluginInfo *info = (PeasPluginInfo *) g_list_model_get_item (list, i);
const gchar *iface_names, *schemes, *hosts;
if (!(iface_names = peas_plugin_info_get_external_data (info, ENHANCER_INTERFACES))) {
GST_DEBUG ("Skipping enhancer without interfaces: %s", peas_plugin_info_get_name (info));
g_object_unref (info);
continue;
}
if (!_is_name_listed (iface_name, iface_names)) {
g_object_unref (info);
continue;
}
if (!(schemes = peas_plugin_info_get_external_data (info, ENHANCER_SCHEMES))) {
GST_DEBUG ("Skipping enhancer without schemes: %s", peas_plugin_info_get_name (info));
g_object_unref (info);
continue;
}
if (!_is_name_listed (scheme, schemes)) {
g_object_unref (info);
continue;
}
if (is_https) {
if (!(hosts = peas_plugin_info_get_external_data (info, ENHANCER_HOSTS))) {
GST_DEBUG ("Skipping enhancer without hosts: %s", peas_plugin_info_get_name (info));
g_object_unref (info);
continue;
}
if (!_is_name_listed (host, hosts)) {
g_object_unref (info);
continue;
}
}
found_info = info;
break;
}
return found_info;
}
/*
* clapper_enhancers_loader_has_enhancers:
* @iface_type: an interface #GType
*
* Check if any enhancer implementing given interface type is available.
*
* Returns: whether any valid enhancer was found.
*/
gboolean
clapper_enhancers_loader_has_enhancers (GType iface_type)
{
GListModel *list = (GListModel *) _engine;
const gchar *iface_name = ENHANCER_IFACE_NAME_FROM_TYPE (iface_type);
guint i, n_plugins;
GST_DEBUG ("Checking for any enhancers of type: \"%s\"", iface_name);
n_plugins = g_list_model_get_n_items (list);
for (i = 0; i < n_plugins; ++i) {
PeasPluginInfo *info = (PeasPluginInfo *) g_list_model_get_item (list, i);
const gchar *iface_names;
if (!(iface_names = peas_plugin_info_get_external_data (info, ENHANCER_INTERFACES))) {
g_object_unref (info);
continue;
}
if (!_is_name_listed (iface_name, iface_names)) {
g_object_unref (info);
continue;
}
/* Additional validation */
if (!peas_plugin_info_get_external_data (info, ENHANCER_SCHEMES)
|| !peas_plugin_info_get_external_data (info, ENHANCER_HOSTS)) {
g_object_unref (info);
continue;
}
GST_DEBUG ("Found valid enhancers of type: \"%s\"", iface_name);
g_object_unref (info);
return TRUE;
}
GST_DEBUG ("No available enhancers of type: \"%s\"", iface_name);
return FALSE;
}
/*
* clapper_enhancers_loader_get_schemes:
* @iface_type: an interface #GType
*
* Get all supported schemes for a given interface type.
* The returned array consists of unique strings (no duplicates).
*
* Returns: (transfer full): all supported schemes by enhancers of type.
*/
gchar **
clapper_enhancers_loader_get_schemes (GType iface_type)
{
GListModel *list = (GListModel *) _engine;
GSList *found_schemes = NULL, *fs;
const gchar *iface_name = ENHANCER_IFACE_NAME_FROM_TYPE (iface_type);
gchar **schemes_strv;
guint i, n_plugins, n_schemes;
GST_DEBUG ("Checking supported URI schemes for \"%s\"", iface_name);
n_plugins = g_list_model_get_n_items (list);
for (i = 0; i < n_plugins; ++i) {
PeasPluginInfo *info = (PeasPluginInfo *) g_list_model_get_item (list, i);
const gchar *iface_names, *schemes;
gchar **tmp_strv;
gint j;
if (!(iface_names = peas_plugin_info_get_external_data (info, ENHANCER_INTERFACES))) {
g_object_unref (info);
continue;
}
if (!_is_name_listed (iface_name, iface_names)) {
g_object_unref (info);
continue;
}
if (!(schemes = peas_plugin_info_get_external_data (info, ENHANCER_SCHEMES))) {
g_object_unref (info);
continue;
}
tmp_strv = g_strsplit (schemes, ";", 0);
for (j = 0; tmp_strv[j]; ++j) {
const gchar *scheme = tmp_strv[j];
if (!found_schemes || !g_slist_find_custom (found_schemes,
scheme, (GCompareFunc) strcmp)) {
found_schemes = g_slist_append (found_schemes, g_strdup (scheme));
GST_INFO ("Found supported URI scheme: %s", scheme);
}
}
g_strfreev (tmp_strv);
g_object_unref (info);
}
n_schemes = g_slist_length (found_schemes);
schemes_strv = g_new0 (gchar *, n_schemes + 1);
fs = found_schemes;
for (i = 0; i < n_schemes; ++i) {
schemes_strv[i] = fs->data;
fs = fs->next;
}
GST_DEBUG ("Total found URI schemes: %u", n_schemes);
/* Since string pointers were taken,
* free list without content */
g_slist_free (found_schemes);
return schemes_strv;
}
/*
* clapper_enhancers_loader_check:
* @iface_type: a requested #GType
* @scheme: an URI scheme
* @host: (nullable): an URI host
* @name: (out) (optional) (transfer none): return location for found enhancer name
*
* Checks if any enhancer can handle @uri without initializing loader
* or creating enhancer instance, thus this can be used freely from any thread.
*
* Returns: whether enhancer for given scheme and host is available.
*/
gboolean
clapper_enhancers_loader_check (GType iface_type,
const gchar *scheme, const gchar *host, const gchar **name)
{
PeasPluginInfo *info;
if ((info = clapper_enhancers_loader_get_info (iface_type, scheme, host))) {
if (name)
*name = peas_plugin_info_get_name (info);
g_object_unref (info);
return TRUE;
}
return FALSE;
}
/*
* clapper_enhancers_loader_create_enhancer_for_uri:
* @iface_type: a requested #GType
* @uri: a #GUri
*
* Creates a new enhancer object for given URI.
*
* Enhancer should only be created and used within single thread.
*
* Returns: (transfer full) (nullable): a new enhancer instance.
*/
GObject *
clapper_enhancers_loader_create_enhancer (ClapperEnhancerProxy *proxy, GType iface_type)
clapper_enhancers_loader_create_enhancer_for_uri (GType iface_type, GUri *uri)
{
if (!clapper_enhancer_proxy_get_target_creation_allowed (proxy))
return NULL;
GObject *enhancer = NULL;
PeasPluginInfo *info;
const gchar *scheme = g_uri_get_scheme (uri);
const gchar *host = g_uri_get_host (uri);
return _force_create_enhancer (proxy, iface_type);
if ((info = clapper_enhancers_loader_get_info (iface_type, scheme, host))) {
g_mutex_lock (&load_lock);
if (!peas_plugin_info_is_loaded (info) && !peas_engine_load_plugin (_engine, info)) {
GST_ERROR ("Could not load enhancer: %s", peas_plugin_info_get_name (info));
} else if (!peas_engine_provides_extension (_engine, info, iface_type)) {
GST_ERROR ("No \"%s\" enhancer in plugin: %s", ENHANCER_IFACE_NAME_FROM_TYPE (iface_type),
peas_plugin_info_get_name (info));
} else {
enhancer = peas_engine_create_extension (_engine, info, iface_type, NULL);
}
g_mutex_unlock (&load_lock);
g_object_unref (info);
}
return enhancer;
}

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
@@ -126,47 +127,4 @@ typedef enum
CLAPPER_DISCOVERER_DISCOVERY_NONCURRENT,
} ClapperDiscovererDiscoveryMode;
/* NOTE: GStreamer uses param flags 8-16, so start with 17. */
/**
* ClapperEnhancerParamFlags:
* @CLAPPER_ENHANCER_PARAM_GLOBAL: Use this flag for enhancer properties that should have global access scope.
* Such are meant for application `USER` to configure.
* @CLAPPER_ENHANCER_PARAM_LOCAL: Use this flag for enhancer properties that should have local access scope.
* Such are meant for `APPLICATION` to configure.
* @CLAPPER_ENHANCER_PARAM_FILEPATH: Use this flag for enhancer properties that store string with a file path.
* Applications can use this as a hint to show file selection instead of a text entry.
* @CLAPPER_ENHANCER_PARAM_DIRPATH: Use this flag for enhancer properties that store string with a directory path.
* Applications can use this as a hint to show directory selection instead of a text entry.
*
* Additional [flags@GObject.ParamFlags] to be set in enhancer plugins implementations.
*
* Since: 0.10
*/
typedef enum
{
CLAPPER_ENHANCER_PARAM_GLOBAL = 1 << 17,
CLAPPER_ENHANCER_PARAM_LOCAL = 1 << 18,
CLAPPER_ENHANCER_PARAM_FILEPATH = 1 << 19,
CLAPPER_ENHANCER_PARAM_DIRPATH = 1 << 20,
} ClapperEnhancerParamFlags;
/**
* ClapperReactableItemUpdatedFlags:
* @CLAPPER_REACTABLE_ITEM_UPDATED_TITLE: Media item title was updated.
* @CLAPPER_REACTABLE_ITEM_UPDATED_DURATION: Media item duration was updated.
* @CLAPPER_REACTABLE_ITEM_UPDATED_TIMELINE: Media item timeline was updated.
* @CLAPPER_REACTABLE_ITEM_UPDATED_TAGS: Media item tags were updated.
*
* Flags informing which properties were updated within [class@Clapper.MediaItem].
*
* Since: 0.10
*/
typedef enum
{
CLAPPER_REACTABLE_ITEM_UPDATED_TITLE = 1 << 0,
CLAPPER_REACTABLE_ITEM_UPDATED_DURATION = 1 << 1,
CLAPPER_REACTABLE_ITEM_UPDATED_TIMELINE = 1 << 2,
CLAPPER_REACTABLE_ITEM_UPDATED_TAGS = 1 << 3,
} ClapperReactableItemUpdatedFlags;
G_END_DECLS

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
@@ -29,8 +30,6 @@
* virtual functions logic, while for controlling playback implementation
* may call [method@Gst.Object.get_parent] to acquire a weak reference on
* a parent [class@Clapper.Player] object feature was added to.
*
* Deprecated: 0.10: Use [iface@Clapper.Reactable] instead.
*/
#include "clapper-feature.h"

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
@@ -36,7 +37,7 @@ G_BEGIN_DECLS
#define CLAPPER_TYPE_FEATURE (clapper_feature_get_type())
#define CLAPPER_FEATURE_CAST(obj) ((ClapperFeature *)(obj))
CLAPPER_DEPRECATED_FOR(ClapperReactable)
CLAPPER_API
G_DECLARE_DERIVABLE_TYPE (ClapperFeature, clapper_feature, CLAPPER, FEATURE, GstObject)
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "clapper-bus-private.h"

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "clapper-features-manager-private.h"

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
@@ -22,7 +23,6 @@
#include <gst/tag/tag.h>
#include "clapper-harvest.h"
#include "clapper-enhancer-proxy.h"
G_BEGIN_DECLS
@@ -32,10 +32,4 @@ ClapperHarvest * clapper_harvest_new (void);
G_GNUC_INTERNAL
gboolean clapper_harvest_unpack (ClapperHarvest *harvest, GstBuffer **buffer, gsize *buf_size, GstCaps **caps, GstTagList **tags, GstToc **toc, GstStructure **headers);
G_GNUC_INTERNAL
gboolean clapper_harvest_fill_from_cache (ClapperHarvest *harvest, ClapperEnhancerProxy *proxy, const GstStructure *config, GUri *uri);
G_GNUC_INTERNAL
void clapper_harvest_export_to_cache (ClapperHarvest *harvest, ClapperEnhancerProxy *proxy, const GstStructure *config, GUri *uri);
G_END_DECLS

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
@@ -30,11 +31,7 @@
* https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/2867
*/
#include "config.h"
#include "clapper-harvest-private.h"
#include "clapper-cache-private.h"
#include "clapper-utils.h"
#define GST_CAT_DEFAULT clapper_harvest_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
@@ -53,8 +50,6 @@ struct _ClapperHarvest
guint16 n_chapters;
guint16 n_tracks;
gint64 exp_epoch;
};
#define parent_class clapper_harvest_parent_class
@@ -124,302 +119,6 @@ clapper_harvest_unpack (ClapperHarvest *self,
return TRUE;
}
/* Custom implementation due to the lack of TOC serialization in GStreamer */
static void
_harvest_fill_toc_from_cache (ClapperHarvest *self, const gchar **data)
{
guint i, n_entries;
n_entries = clapper_cache_read_uint (data);
for (i = 0; i < n_entries; ++i) {
guint j, n_subentries;
n_subentries = clapper_cache_read_uint (data);
for (j = 0; j < n_subentries; ++j) {
GstTocEntryType type;
const gchar *title;
gdouble start, end;
type = (GstTocEntryType) clapper_cache_read_int (data);
title = clapper_cache_read_string (data);
start = clapper_cache_read_double (data);
end = clapper_cache_read_double (data);
clapper_harvest_toc_add (self, type, title, start, end);
}
}
}
static void
_harvest_store_toc_to_cache (ClapperHarvest *self, GByteArray *bytes)
{
GList *list = NULL, *el;
guint n_entries = 0;
if (self->toc) {
list = gst_toc_get_entries (self->toc);
n_entries = g_list_length (list);
}
clapper_cache_store_uint (bytes, n_entries);
for (el = list; el; el = g_list_next (el)) {
const GstTocEntry *entry = (const GstTocEntry *) el->data;
GList *subentries, *sub_el;
guint n_subentries;
subentries = gst_toc_entry_get_sub_entries (entry);
n_subentries = g_list_length (subentries);
clapper_cache_store_uint (bytes, n_subentries);
for (sub_el = subentries; sub_el; sub_el = g_list_next (sub_el)) {
const GstTocEntry *subentry = (const GstTocEntry *) sub_el->data;
GstTagList *tags;
gint64 start = 0, end = 0;
gdouble start_dbl, end_dbl;
const gchar *title = NULL;
clapper_cache_store_int (bytes, (gint) gst_toc_entry_get_entry_type (subentry));
if ((tags = gst_toc_entry_get_tags (subentry)))
gst_tag_list_peek_string_index (tags, GST_TAG_TITLE, 0, &title);
clapper_cache_store_string (bytes, title);
gst_toc_entry_get_start_stop_times (subentry, &start, &end);
start_dbl = ((gdouble) start) / GST_SECOND;
end_dbl = (end >= 0) ? ((gdouble) end) / GST_SECOND : -1;
clapper_cache_store_double (bytes, start_dbl);
clapper_cache_store_double (bytes, end_dbl);
}
}
}
static inline gchar *
_build_cache_filename (ClapperEnhancerProxy *proxy, GUri *uri)
{
gchar *uri_str = g_uri_to_string (uri);
gchar name[15];
g_snprintf (name, sizeof (name), "%u.bin", g_str_hash (uri_str));
g_free (uri_str);
return g_build_filename (g_get_user_cache_dir (), CLAPPER_API_NAME,
"enhancers", clapper_enhancer_proxy_get_module_name (proxy),
"harvests", name, NULL);
}
/* NOTE: On failure, this function must not modify harvest! */
gboolean
clapper_harvest_fill_from_cache (ClapperHarvest *self, ClapperEnhancerProxy *proxy,
const GstStructure *config, GUri *uri)
{
GMappedFile *mapped_file;
GstStructure *config_cached = NULL;
GError *error = NULL;
gchar *filename;
const gchar *data, *read_str;
const guint8 *buf_data;
guint8 *buf_copy;
gsize buf_size;
gint64 epoch_cached, epoch_now = 0;
gdouble exp_seconds;
gboolean changed, read_ok = FALSE;
filename = _build_cache_filename (proxy, uri);
GST_DEBUG_OBJECT (self, "Importing harvest from cache file: \"%s\"", filename);
mapped_file = clapper_cache_open (filename, &data, &error);
g_free (filename);
if (!mapped_file) {
/* No error if cache disabled or version mismatch */
if (error) {
if (error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT)
GST_DEBUG_OBJECT (self, "No cached harvest found");
else
GST_ERROR_OBJECT (self, "Could not use cached harvest, reason: %s", error->message);
g_error_free (error);
}
return FALSE;
}
/* Plugin version check */
if (g_strcmp0 (clapper_cache_read_string (&data),
clapper_enhancer_proxy_get_version (proxy)) != 0)
goto finish; // no error printing here
if (G_LIKELY ((epoch_cached = clapper_cache_read_int64 (&data)) > 0)) {
GDateTime *date = g_date_time_new_now_utc ();
epoch_now = g_date_time_to_unix (date);
g_date_time_unref (date);
}
/* Check if expired */
if ((exp_seconds = (gdouble) (epoch_cached - epoch_now)) <= 0) {
GST_DEBUG_OBJECT (self, "Cached harvest expired"); // expiration is not an error
goto finish;
}
GST_DEBUG_OBJECT (self, "Cached harvest expiration in %" CLAPPER_TIME_FORMAT,
CLAPPER_TIME_ARGS (exp_seconds));
/* Read last used config to generate cache data */
if ((read_str = clapper_cache_read_string (&data)))
config_cached = gst_structure_from_string (read_str, NULL);
/* Compare used config when cache was generated to the current one */
changed = (config_cached && config)
? !gst_structure_is_equal (config_cached, config)
: (config_cached != config);
gst_clear_structure (&config_cached);
if (changed) {
GST_DEBUG_OBJECT (self, "Enhancer config differs from the last time");
goto finish;
}
/* Read media type */
read_str = clapper_cache_read_string (&data);
if (G_UNLIKELY (read_str == NULL)) {
GST_ERROR_OBJECT (self, "Could not read media type from cache file");
goto finish;
}
/* Read buffer data */
buf_data = clapper_cache_read_data (&data, &buf_size);
if (G_UNLIKELY (buf_data == NULL)) {
GST_ERROR_OBJECT (self, "Could not read buffer data from cache");
goto finish;
}
/* Fill harvest */
buf_copy = g_memdup2 (buf_data, buf_size);
if (!clapper_harvest_fill (self, read_str, buf_copy, buf_size))
goto finish;
/* Read tags */
read_str = clapper_cache_read_string (&data);
if (read_str && (self->tags = gst_tag_list_new_from_string (read_str))) {
GST_LOG_OBJECT (self, "Read %s", read_str);
gst_tag_list_set_scope (self->tags, GST_TAG_SCOPE_GLOBAL);
}
/* Read TOC */
_harvest_fill_toc_from_cache (self, &data);
/* Read headers */
read_str = clapper_cache_read_string (&data);
if (read_str && (self->headers = gst_structure_from_string (read_str, NULL)))
GST_LOG_OBJECT (self, "Read %s", read_str);
read_ok = TRUE;
finish:
g_mapped_file_unref (mapped_file);
if (!read_ok)
return FALSE;
GST_DEBUG_OBJECT (self, "Filled harvest from cache");
return TRUE;
}
void
clapper_harvest_export_to_cache (ClapperHarvest *self, ClapperEnhancerProxy *proxy,
const GstStructure *config, GUri *uri)
{
GByteArray *bytes;
const GstStructure *caps_structure;
gchar *filename, *temp_str = NULL;
gboolean data_ok = TRUE;
/* No caching if no expiration date set */
if (self->exp_epoch <= 0)
return;
/* Might happen if extractor extract function implementation
* returns %TRUE without filling harvest properly */
if (G_UNLIKELY (self->caps == NULL || self->buffer == NULL))
return; // no data to cache
bytes = clapper_cache_create ();
/* If cache disabled */
if (G_UNLIKELY (bytes == NULL))
return;
filename = _build_cache_filename (proxy, uri);
GST_DEBUG_OBJECT (self, "Exporting harvest to cache file: \"%s\"", filename);
/* Store enhancer version that generated harvest */
clapper_cache_store_string (bytes, clapper_enhancer_proxy_get_version (proxy));
/* Store expiration date */
clapper_cache_store_int64 (bytes, self->exp_epoch);
/* Store config used to generate harvest */
if (config)
temp_str = gst_structure_to_string (config);
clapper_cache_store_string (bytes, temp_str); // NULL when no config
g_clear_pointer (&temp_str, g_free);
/* Store media type */
caps_structure = gst_caps_get_structure (self->caps, 0);
if (G_LIKELY (caps_structure != NULL)) {
clapper_cache_store_string (bytes, gst_structure_get_name (caps_structure));
} else {
GST_ERROR_OBJECT (self, "Cannot cache empty caps");
data_ok = FALSE;
}
if (G_LIKELY (data_ok)) {
GstMemory *mem;
GstMapInfo map_info;
/* Store buffer data */
mem = gst_buffer_peek_memory (self->buffer, 0);
if (G_LIKELY (gst_memory_map (mem, &map_info, GST_MAP_READ))) {
clapper_cache_store_data (bytes, map_info.data, map_info.size);
gst_memory_unmap (mem, &map_info);
} else {
GST_ERROR_OBJECT (self, "Could not map harvest buffer for reading");
data_ok = FALSE;
}
}
if (G_LIKELY (data_ok)) {
GError *error = NULL;
/* Store tags */
if (self->tags)
temp_str = gst_tag_list_to_string (self->tags);
clapper_cache_store_string (bytes, temp_str);
g_clear_pointer (&temp_str, g_free);
/* Store TOC */
_harvest_store_toc_to_cache (self, bytes);
/* Store headers */
if (self->headers)
temp_str = gst_structure_to_string (self->headers);
clapper_cache_store_string (bytes, temp_str);
g_clear_pointer (&temp_str, g_free);
if (clapper_cache_write (filename, bytes, &error)) {
GST_DEBUG_OBJECT (self, "Successfully exported harvest to cache file");
} else if (error) {
GST_ERROR_OBJECT (self, "Could not cache harvest, reason: %s", error->message);
g_error_free (error);
}
}
g_free (filename);
g_byte_array_free (bytes, TRUE);
}
/**
* clapper_harvest_fill:
* @harvest: a #ClapperHarvest
@@ -456,7 +155,7 @@ clapper_harvest_fill (ClapperHarvest *self, const gchar *media_type, gpointer da
return FALSE;
}
if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= GST_LEVEL_LOG) {
if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= GST_LEVEL_DEBUG) {
gboolean is_printable = (strcmp (media_type, "application/dash+xml") == 0)
|| (strcmp (media_type, "application/x-hls") == 0)
|| (strcmp (media_type, "text/uri-list") == 0);
@@ -467,7 +166,7 @@ clapper_harvest_fill (ClapperHarvest *self, const gchar *media_type, gpointer da
data_str = g_new0 (gchar, size + 1);
memcpy (data_str, data, size);
GST_LOG_OBJECT (self, "Filled with data:\n%s", data_str);
GST_DEBUG_OBJECT (self, "Filled with data:\n%s", data_str);
g_free (data_str);
}
@@ -629,7 +328,7 @@ clapper_harvest_toc_add (ClapperHarvest *self, GstTocEntryType type,
g_snprintf (edition, sizeof (edition), "0%i", type);
g_snprintf (id, sizeof (id), "%s.%" G_GUINT16_FORMAT, id_prefix, nth_entry);
GST_LOG_OBJECT (self, "Inserting TOC %s: \"%s\""
GST_DEBUG_OBJECT (self, "Inserting TOC %s: \"%s\""
" (%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT ")",
id, title, start_time, end_time);
@@ -681,7 +380,7 @@ clapper_harvest_headers_set (ClapperHarvest *self, const gchar *key, ...)
while (key != NULL) {
const gchar *val = va_arg (args, const gchar *);
GST_LOG_OBJECT (self, "Set header, \"%s\": \"%s\"", key, val);
GST_DEBUG_OBJECT (self, "Set header, \"%s\": \"%s\"", key, val);
gst_structure_set (self->headers, key, G_TYPE_STRING, val, NULL);
key = va_arg (args, const gchar *);
}
@@ -710,70 +409,10 @@ clapper_harvest_headers_set_value (ClapperHarvest *self, const gchar *key, const
_ensure_headers (self);
GST_LOG_OBJECT (self, "Set header, \"%s\": \"%s\"", key, g_value_get_string (value));
GST_DEBUG_OBJECT (self, "Set header, \"%s\": \"%s\"", key, g_value_get_string (value));
gst_structure_set_value (self->headers, key, value);
}
/**
* clapper_harvest_set_expiration_date_utc:
* @harvest: a #ClapperHarvest
* @date_utc: a #GDateTime in UTC time
*
* Set date in UTC time until harvested content is expected
* to stay alive.
*
* This is used for harvest caching, so next time user requests to
* play the same URI, recently harvested data can be reused without
* the need to run [vfunc@Clapper.Extractable.extract] again.
*
* Since: 0.10
*/
void
clapper_harvest_set_expiration_date_utc (ClapperHarvest *self, GDateTime *date_utc)
{
g_return_if_fail (CLAPPER_IS_HARVEST (self));
g_return_if_fail (date_utc != NULL);
self->exp_epoch = g_date_time_to_unix (date_utc);
GST_LOG_OBJECT (self, "Expiration epoch: %" G_GINT64_FORMAT, self->exp_epoch);
}
/**
* clapper_harvest_set_expiration_seconds:
* @harvest: a #ClapperHarvest
* @seconds: time in seconds until expiration
*
* Set amount of seconds for how long harvested content is
* expected to stay alive.
*
* Alternative function to [method@Clapper.Harvest.set_expiration_date_utc],
* but takes time as number in seconds from now.
*
* It is safe to pass zero or negative number to this function in
* case when calculating time manually and it already expired.
*
* Since: 0.10
*/
void
clapper_harvest_set_expiration_seconds (ClapperHarvest *self, gdouble seconds)
{
GDateTime *date, *date_epoch;
g_return_if_fail (CLAPPER_IS_HARVEST (self));
GST_LOG_OBJECT (self, "Set expiration in %" CLAPPER_TIME_FORMAT,
CLAPPER_TIME_ARGS (seconds));
date = g_date_time_new_now_utc ();
date_epoch = g_date_time_add_seconds (date, seconds);
g_date_time_unref (date);
self->exp_epoch = g_date_time_to_unix (date_epoch);
g_date_time_unref (date_epoch);
GST_LOG_OBJECT (self, "Expiration epoch: %" G_GINT64_FORMAT, self->exp_epoch);
}
static void
clapper_harvest_init (ClapperHarvest *self)
{

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
@@ -60,10 +61,4 @@ void clapper_harvest_headers_set (ClapperHarvest *harvest, const gchar *key, ...
CLAPPER_API
void clapper_harvest_headers_set_value (ClapperHarvest *harvest, const gchar *key, const GValue *value);
CLAPPER_API
void clapper_harvest_set_expiration_date_utc (ClapperHarvest *harvest, GDateTime *date_utc);
CLAPPER_API
void clapper_harvest_set_expiration_seconds (ClapperHarvest *harvest, gdouble seconds);
G_END_DECLS

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
@@ -22,7 +23,7 @@
#include <gst/pbutils/pbutils.h>
#include "clapper-media-item.h"
#include "clapper-player.h"
#include "clapper-player-private.h"
#include "clapper-app-bus-private.h"
G_BEGIN_DECLS

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
@@ -29,7 +30,6 @@
#include "clapper-timeline-private.h"
#include "clapper-player-private.h"
#include "clapper-playbin-bus-private.h"
#include "clapper-reactables-manager-private.h"
#include "clapper-features-manager-private.h"
#include "clapper-utils-private.h"
@@ -43,7 +43,6 @@ struct _ClapperMediaItem
gchar *uri;
gchar *suburi;
GstTagList *tags;
ClapperTimeline *timeline;
guint id;
@@ -57,13 +56,6 @@ struct _ClapperMediaItem
gboolean used;
};
typedef struct
{
ClapperMediaItem *item;
gboolean changed;
gboolean from_user;
} ClapperMediaItemTagIterData;
enum
{
PROP_0,
@@ -71,7 +63,6 @@ enum
PROP_URI,
PROP_SUBURI,
PROP_CACHE_LOCATION,
PROP_TAGS,
PROP_TITLE,
PROP_CONTAINER_FORMAT,
PROP_DURATION,
@@ -120,8 +111,8 @@ clapper_media_item_new (const gchar *uri)
/* FIXME: Set initial container format from file extension parsing */
GST_TRACE_OBJECT (item, "New media item, ID: %u, URI: \"%s\", title: \"%s\"",
item->id, item->uri, GST_STR_NULL (item->title));
GST_TRACE_OBJECT (item, "New media item, ID: %u, URI: %s, title: %s",
item->id, item->uri, item->title);
return item;
}
@@ -267,6 +258,27 @@ clapper_media_item_get_suburi (ClapperMediaItem *self)
return suburi;
}
static gboolean
clapper_media_item_take_title (ClapperMediaItem *self, gchar *title,
ClapperAppBus *app_bus)
{
gboolean changed;
GST_OBJECT_LOCK (self);
if ((changed = g_strcmp0 (self->title, title) != 0)) {
g_free (self->title);
self->title = title;
}
GST_OBJECT_UNLOCK (self);
if (changed)
clapper_app_bus_post_prop_notify (app_bus, GST_OBJECT_CAST (self), param_specs[PROP_TITLE]);
else
g_free (title);
return changed;
}
/**
* clapper_media_item_get_title:
* @item: a #ClapperMediaItem
@@ -293,24 +305,25 @@ clapper_media_item_get_title (ClapperMediaItem *self)
return title;
}
static inline gboolean
_refresh_tag_prop_unlocked (ClapperMediaItem *self, const gchar *tag,
gboolean from_user, gchar **tag_ptr)
static gboolean
clapper_media_item_take_container_format (ClapperMediaItem *self, gchar *container_format,
ClapperAppBus *app_bus)
{
const gchar *string;
gboolean changed;
if ((*tag_ptr && from_user) // if already set, user cannot modify it
|| !gst_tag_list_peek_string_index (self->tags, tag, 0, &string) // guarantees non-empty string
|| (g_strcmp0 (*tag_ptr, string) == 0))
return FALSE;
GST_OBJECT_LOCK (self);
if ((changed = g_strcmp0 (self->container_format, container_format) != 0)) {
g_free (self->container_format);
self->container_format = container_format;
}
GST_OBJECT_UNLOCK (self);
GST_LOG_OBJECT (self, "Tag prop \"%s\" update: \"%s\" -> \"%s\"",
tag, GST_STR_NULL (*tag_ptr), string);
if (changed)
clapper_app_bus_post_prop_notify (app_bus, GST_OBJECT_CAST (self), param_specs[PROP_CONTAINER_FORMAT]);
else
g_free (container_format);
g_free (*tag_ptr);
*tag_ptr = g_strdup (string);
return TRUE;
return changed;
}
/**
@@ -320,8 +333,6 @@ _refresh_tag_prop_unlocked (ClapperMediaItem *self, const gchar *tag,
* Get media item container format.
*
* Returns: (transfer full) (nullable): media container format.
*
* Deprecated: 0.10: Get `container-format` from [property@Clapper.MediaItem:tags] instead.
*/
gchar *
clapper_media_item_get_container_format (ClapperMediaItem *self)
@@ -378,214 +389,11 @@ clapper_media_item_get_duration (ClapperMediaItem *self)
return duration;
}
/**
* clapper_media_item_get_tags:
* @item: a #ClapperMediaItem
*
* Get readable list of tags stored in media item.
*
* Returns: (transfer full): a #GstTagList.
*
* Since: 0.10
*/
GstTagList *
clapper_media_item_get_tags (ClapperMediaItem *self)
{
GstTagList *tags = NULL;
g_return_val_if_fail (CLAPPER_IS_MEDIA_ITEM (self), NULL);
GST_OBJECT_LOCK (self);
tags = gst_tag_list_ref (self->tags);
GST_OBJECT_UNLOCK (self);
return tags;
}
static void
_tags_replace_func (const GstTagList *tags, const gchar *tag, ClapperMediaItemTagIterData *data)
{
ClapperMediaItem *self = data->item;
guint index = 0;
gboolean replace = FALSE;
while (TRUE) {
const GValue *old_value = gst_tag_list_get_value_index (self->tags, tag, index);
const GValue *new_value = gst_tag_list_get_value_index (tags, tag, index);
/* Number of old values is the same or greater and
* all values until this iteration were the same */
if (!new_value)
break;
/* A wild new tag appeared */
if (!old_value) {
replace = TRUE;
break;
}
/* Users can only set non-existing tags */
if (data->from_user)
break;
/* Check with tolerance for doubles */
if (G_VALUE_TYPE (old_value) == G_TYPE_DOUBLE
&& G_VALUE_TYPE (new_value) == G_TYPE_DOUBLE) {
gdouble old_dbl, new_dbl;
old_dbl = g_value_get_double (old_value);
new_dbl = g_value_get_double (new_value);
if ((replace = !G_APPROX_VALUE (old_dbl, new_dbl, FLT_EPSILON)))
break;
} else if (gst_value_compare (old_value, new_value) != GST_VALUE_EQUAL) {
replace = TRUE;
break;
}
++index;
}
if (replace) {
const GValue *value;
index = 0;
GST_LOG_OBJECT (self, "Replacing \"%s\" tag value", tag);
/* Ensure writable, but only when replacing something */
if (!data->changed) {
self->tags = gst_tag_list_make_writable (self->tags);
data->changed = TRUE;
}
/* Replace first tag value (so it becomes sole member) */
value = gst_tag_list_get_value_index (tags, tag, index);
gst_tag_list_add_value (self->tags, GST_TAG_MERGE_REPLACE, tag, value);
/* Append any remaining tags (so next time we iterate indexes will match) */
while ((value = gst_tag_list_get_value_index (tags, tag, ++index)))
gst_tag_list_add_value (self->tags, GST_TAG_MERGE_APPEND, tag, value);
}
}
static gboolean
clapper_media_item_insert_tags_internal (ClapperMediaItem *self, const GstTagList *tags,
ClapperAppBus *app_bus, gboolean from_user, ClapperReactableItemUpdatedFlags *flags)
{
ClapperMediaItemTagIterData data;
gboolean title_changed = FALSE, cont_changed = FALSE;
GST_OBJECT_LOCK (self);
data.item = self;
data.changed = FALSE;
data.from_user = from_user;
if (G_LIKELY (tags != self->tags))
gst_tag_list_foreach (tags, (GstTagForeachFunc) _tags_replace_func, &data);
if (data.changed) {
*flags |= CLAPPER_REACTABLE_ITEM_UPDATED_TAGS;
if ((title_changed = _refresh_tag_prop_unlocked (self, GST_TAG_TITLE,
from_user, &self->title))) {
*flags |= CLAPPER_REACTABLE_ITEM_UPDATED_TITLE;
}
cont_changed = _refresh_tag_prop_unlocked (self, GST_TAG_CONTAINER_FORMAT,
from_user, &self->container_format);
}
GST_OBJECT_UNLOCK (self);
if (!data.changed)
return FALSE;
if (app_bus) {
GstObject *src = GST_OBJECT_CAST (self);
clapper_app_bus_post_prop_notify (app_bus, src, param_specs[PROP_TAGS]);
if (title_changed)
clapper_app_bus_post_prop_notify (app_bus, src, param_specs[PROP_TITLE]);
if (cont_changed)
clapper_app_bus_post_prop_notify (app_bus, src, param_specs[PROP_CONTAINER_FORMAT]);
} else {
GObject *src = G_OBJECT (self);
clapper_utils_prop_notify_on_main_sync (src, param_specs[PROP_TAGS]);
if (title_changed)
clapper_utils_prop_notify_on_main_sync (src, param_specs[PROP_TITLE]);
if (cont_changed)
clapper_utils_prop_notify_on_main_sync (src, param_specs[PROP_CONTAINER_FORMAT]);
}
return TRUE;
}
/**
* clapper_media_item_populate_tags:
* @item: a #ClapperMediaItem
* @tags: a #GstTagList of GLOBAL scope
*
* Populate non-existing tags in @item tag list.
*
* Passed @tags must use [enum@Gst.TagScope.GLOBAL] scope.
*
* Note that tags are automatically determined during media playback
* and those take precedence. This function can be useful if an app can
* determine some tags that are not in media metadata or for filling
* item with some initial/cached tags to display in UI before playback.
*
* When a tag already exists in the tag list (was populated) this
* function will not overwrite it. If you really need to permanently
* override some tags in media, you can use `taginject` element as
* player video/audio filter instead.
*
* Returns: whether at least one tag got updated.
*
* Since: 0.10
*/
gboolean
clapper_media_item_populate_tags (ClapperMediaItem *self, const GstTagList *tags)
{
ClapperPlayer *player;
ClapperAppBus *app_bus = NULL;
ClapperReactableItemUpdatedFlags flags = 0;
gboolean changed;
g_return_val_if_fail (CLAPPER_IS_MEDIA_ITEM (self), FALSE);
g_return_val_if_fail (tags != NULL, FALSE);
if (G_UNLIKELY (gst_tag_list_get_scope (tags) != GST_TAG_SCOPE_GLOBAL)) {
g_warning ("Cannot populate media item tags using a list with non-global tag scope");
return FALSE;
}
if ((player = clapper_player_get_from_ancestor (GST_OBJECT_CAST (self))))
app_bus = player->app_bus;
changed = clapper_media_item_insert_tags_internal (self, tags, app_bus, TRUE, &flags);
if (changed && player) {
ClapperFeaturesManager *features_manager;
if (player->reactables_manager)
clapper_reactables_manager_trigger_item_updated (player->reactables_manager, self, flags);
if ((features_manager = clapper_player_get_features_manager (player)))
clapper_features_manager_trigger_item_updated (features_manager, self);
}
gst_clear_object (&player);
return changed;
}
/**
* clapper_media_item_get_timeline:
* @item: a #ClapperMediaItem
*
* Get the [class@Clapper.Timeline] associated with @item.
* Get the [class@Clapper.Timeline] assosiated with @item.
*
* Returns: (transfer none): a #ClapperTimeline of item.
*/
@@ -597,6 +405,21 @@ clapper_media_item_get_timeline (ClapperMediaItem *self)
return self->timeline;
}
static gboolean
clapper_media_item_update_from_container_tags (ClapperMediaItem *self, const GstTagList *tags,
ClapperAppBus *app_bus)
{
gchar *string = NULL;
gboolean changed = FALSE;
if (gst_tag_list_get_string (tags, GST_TAG_CONTAINER_FORMAT, &string))
changed |= clapper_media_item_take_container_format (self, string, app_bus);
if (gst_tag_list_get_string (tags, GST_TAG_TITLE, &string))
changed |= clapper_media_item_take_title (self, string, app_bus);
return changed;
}
void
clapper_media_item_update_from_tag_list (ClapperMediaItem *self, const GstTagList *tags,
ClapperPlayer *player)
@@ -604,14 +427,11 @@ clapper_media_item_update_from_tag_list (ClapperMediaItem *self, const GstTagLis
GstTagScope scope = gst_tag_list_get_scope (tags);
if (scope == GST_TAG_SCOPE_GLOBAL) {
ClapperReactableItemUpdatedFlags flags = 0;
gboolean changed = clapper_media_item_insert_tags_internal (self, tags, player->app_bus, FALSE, &flags);
gboolean changed = clapper_media_item_update_from_container_tags (self, tags, player->app_bus);
if (changed) {
ClapperFeaturesManager *features_manager;
if (player->reactables_manager)
clapper_reactables_manager_trigger_item_updated (player->reactables_manager, self, flags);
if ((features_manager = clapper_player_get_features_manager (player)))
clapper_features_manager_trigger_item_updated (features_manager, self);
}
@@ -624,7 +444,6 @@ clapper_media_item_update_from_discoverer_info (ClapperMediaItem *self, GstDisco
ClapperPlayer *player;
GstDiscovererStreamInfo *sinfo;
GstClockTime duration;
ClapperReactableItemUpdatedFlags flags = 0;
gdouble val_dbl;
gboolean changed = FALSE;
@@ -640,7 +459,7 @@ clapper_media_item_update_from_discoverer_info (ClapperMediaItem *self, GstDisco
GstDiscovererContainerInfo *cinfo = (GstDiscovererContainerInfo *) sinfo;
if ((tags = gst_discoverer_container_info_get_tags (cinfo)))
changed |= clapper_media_item_insert_tags_internal (self, tags, player->app_bus, FALSE, &flags);
changed |= clapper_media_item_update_from_container_tags (self, tags, player->app_bus);
}
gst_discoverer_stream_info_unref (sinfo);
}
@@ -651,16 +470,11 @@ clapper_media_item_update_from_discoverer_info (ClapperMediaItem *self, GstDisco
duration = 0;
val_dbl = (gdouble) duration / GST_SECOND;
if (clapper_media_item_set_duration (self, val_dbl, player->app_bus)) {
changed = TRUE;
flags |= CLAPPER_REACTABLE_ITEM_UPDATED_DURATION;
}
changed |= clapper_media_item_set_duration (self, val_dbl, player->app_bus);
if (changed) {
ClapperFeaturesManager *features_manager;
if (player->reactables_manager)
clapper_reactables_manager_trigger_item_updated (player->reactables_manager, self, flags);
if ((features_manager = clapper_player_get_features_manager (player)))
clapper_features_manager_trigger_item_updated (features_manager, self);
}
@@ -728,9 +542,6 @@ clapper_media_item_get_used (ClapperMediaItem *self)
static void
clapper_media_item_init (ClapperMediaItem *self)
{
self->tags = gst_tag_list_new_empty ();
gst_tag_list_set_scope (self->tags, GST_TAG_SCOPE_GLOBAL);
self->timeline = clapper_timeline_new ();
gst_object_set_parent (GST_OBJECT_CAST (self->timeline), GST_OBJECT_CAST (self));
}
@@ -760,8 +571,6 @@ clapper_media_item_finalize (GObject *object)
g_free (self->title);
g_free (self->container_format);
gst_tag_list_unref (self->tags);
gst_object_unparent (GST_OBJECT_CAST (self->timeline));
gst_object_unref (self->timeline);
@@ -808,9 +617,6 @@ clapper_media_item_get_property (GObject *object, guint prop_id,
case PROP_SUBURI:
g_value_take_string (value, clapper_media_item_get_suburi (self));
break;
case PROP_TAGS:
g_value_take_boxed (value, clapper_media_item_get_tags (self));
break;
case PROP_TITLE:
g_value_take_string (value, clapper_media_item_get_title (self));
break;
@@ -880,27 +686,10 @@ clapper_media_item_class_init (ClapperMediaItemClass *klass)
NULL, NULL, NULL,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ClapperMediaItem:tags:
*
* A readable list of tags stored in media item.
*
* Since: 0.10
*/
param_specs[PROP_TAGS] = g_param_spec_boxed ("tags",
NULL, NULL, GST_TYPE_TAG_LIST,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/* FIXME: 1.0: Consider rename to e.g. "(menu/display)-title"
* and also make it non-nullable (return URI as final fallback) */
/**
* ClapperMediaItem:title:
*
* Media title.
*
* This might be a different string compared to `title` from
* [property@Clapper.MediaItem:tags], as this gives parsed
* title from file name/URI as fallback when no `title` tag.
*/
param_specs[PROP_TITLE] = g_param_spec_string ("title",
NULL, NULL, NULL,
@@ -910,21 +699,15 @@ clapper_media_item_class_init (ClapperMediaItemClass *klass)
* ClapperMediaItem:container-format:
*
* Media container format.
*
* Deprecated: 0.10: Get `container-format` from [property@Clapper.MediaItem:tags] instead.
*/
param_specs[PROP_CONTAINER_FORMAT] = g_param_spec_string ("container-format",
NULL, NULL, NULL,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED);
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ClapperMediaItem:duration:
*
* Media duration as a decimal number in seconds.
*
* This might be a different value compared to `duration` from
* [property@Clapper.MediaItem:tags], as this value is updated
* during decoding instead of being a fixed value from metadata.
*/
param_specs[PROP_DURATION] = g_param_spec_double ("duration",
NULL, NULL, 0, G_MAXDOUBLE, 0,

Some files were not shown because too many files have changed in this diff Show More