mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-30 07:42:23 +02:00
bin: Rewrite Clapper player binary
A rewritten Clapper video player made using "Clapper" and "ClapperGtk" libraries. Since both libraries from this repo are in C, newly rewritten Clapper binary is also in C to avoid mixing different programming languages in a single repo, thus making maintenance easier. Not depending on GJS gives us also an additional benefit of supporting different operating systems or linux shells without pulling GJS as dependency. Licensed under GPL-3.0-or-later.
This commit is contained in:
326
src/bin/clapper-app/clapper-app-utils.c
Normal file
326
src/bin/clapper-app/clapper-app-utils.c
Normal file
@@ -0,0 +1,326 @@
|
||||
/* Clapper Application
|
||||
* Copyright (C) 2024 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "clapper-app-utils.h"
|
||||
#include "clapper-app-media-item-box.h"
|
||||
|
||||
const gchar *const *
|
||||
clapper_app_utils_get_mime_types (void)
|
||||
{
|
||||
static const gchar *const all_mime_types[] = {
|
||||
"video/*",
|
||||
"audio/*",
|
||||
"application/claps",
|
||||
"application/x-subrip",
|
||||
"text/x-ssa",
|
||||
NULL
|
||||
};
|
||||
|
||||
return all_mime_types;
|
||||
}
|
||||
|
||||
const gchar *const *
|
||||
clapper_app_utils_get_subtitles_mime_types (void)
|
||||
{
|
||||
static const gchar *const subs_mime_types[] = {
|
||||
"application/x-subrip",
|
||||
"text/x-ssa",
|
||||
NULL
|
||||
};
|
||||
|
||||
return subs_mime_types;
|
||||
}
|
||||
|
||||
void
|
||||
clapper_app_utils_parse_progression (ClapperQueueProgressionMode mode,
|
||||
const gchar **icon, const gchar **label)
|
||||
{
|
||||
const gchar *const icon_names[] = {
|
||||
"action-unavailable-symbolic",
|
||||
"media-playlist-consecutive-symbolic",
|
||||
"media-playlist-repeat-song-symbolic",
|
||||
"media-playlist-repeat-symbolic",
|
||||
"media-playlist-shuffle-symbolic",
|
||||
NULL
|
||||
};
|
||||
const gchar *const labels[] = {
|
||||
_("No progression"),
|
||||
_("Consecutive"),
|
||||
_("Repeat item"),
|
||||
_("Carousel"),
|
||||
_("Shuffle"),
|
||||
NULL
|
||||
};
|
||||
|
||||
*icon = icon_names[mode];
|
||||
*label = labels[mode];
|
||||
}
|
||||
|
||||
gboolean
|
||||
clapper_app_utils_is_subtitles_file (GFile *file)
|
||||
{
|
||||
GFileInfo *info;
|
||||
gboolean is_subs = FALSE;
|
||||
|
||||
if ((info = g_file_query_info (file,
|
||||
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
|
||||
G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
NULL, NULL))) {
|
||||
is_subs = g_strv_contains (
|
||||
clapper_app_utils_get_subtitles_mime_types (),
|
||||
g_file_info_get_content_type (info));
|
||||
g_object_unref (info);
|
||||
}
|
||||
|
||||
return is_subs;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clapper_app_utils_value_for_item_is_valid (const GValue *value)
|
||||
{
|
||||
if (G_VALUE_HOLDS (value, GTK_TYPE_WIDGET))
|
||||
return CLAPPER_APP_IS_MEDIA_ITEM_BOX (g_value_get_object (value));
|
||||
|
||||
if (G_VALUE_HOLDS (value, GDK_TYPE_FILE_LIST)
|
||||
|| G_VALUE_HOLDS (value, G_TYPE_FILE))
|
||||
return TRUE;
|
||||
|
||||
if (G_VALUE_HOLDS (value, G_TYPE_STRING))
|
||||
return gst_uri_is_valid (g_value_get_string (value));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clapper_app_utils_files_from_list_model (GListModel *files_model, GFile ***files, gint *n_files)
|
||||
{
|
||||
guint i, len = g_list_model_get_n_items (files_model);
|
||||
|
||||
if (G_UNLIKELY (len == 0 || len > G_MAXINT))
|
||||
return FALSE;
|
||||
|
||||
*files = g_new (GFile *, len + 1);
|
||||
|
||||
if (n_files)
|
||||
*n_files = (gint) len;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
(*files)[i] = g_list_model_get_item (files_model, i);
|
||||
}
|
||||
(*files)[i] = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clapper_app_utils_files_from_slist (GSList *file_list, GFile ***files, gint *n_files)
|
||||
{
|
||||
GSList *fl;
|
||||
guint len, i = 0;
|
||||
|
||||
len = g_slist_length (file_list);
|
||||
|
||||
if (G_UNLIKELY (len == 0 || len > G_MAXINT))
|
||||
return FALSE;
|
||||
|
||||
*files = g_new (GFile *, len + 1);
|
||||
|
||||
if (n_files)
|
||||
*n_files = (gint) len;
|
||||
|
||||
for (fl = file_list; fl != NULL; fl = fl->next) {
|
||||
(*files)[i] = (GFile *) g_object_ref (fl->data);
|
||||
i++;
|
||||
}
|
||||
(*files)[i] = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clapper_app_utils_files_from_string (const gchar *string, GFile ***files, gint *n_files)
|
||||
{
|
||||
GSList *slist = NULL;
|
||||
gchar **uris = g_strsplit (string, "\n", 0);
|
||||
guint i;
|
||||
gboolean success;
|
||||
|
||||
for (i = 0; uris[i]; ++i) {
|
||||
const gchar *uri = uris[i];
|
||||
|
||||
if (!gst_uri_is_valid (uri))
|
||||
continue;
|
||||
|
||||
slist = g_slist_append (slist, g_file_new_for_uri (uri));
|
||||
}
|
||||
|
||||
g_strfreev (uris);
|
||||
|
||||
if (!slist)
|
||||
return FALSE;
|
||||
|
||||
success = clapper_app_utils_files_from_slist (slist, files, n_files);
|
||||
g_slist_free_full (slist, g_object_unref);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
_files_from_file (GFile *file, GFile ***files, gint *n_files)
|
||||
{
|
||||
*files = g_new (GFile *, 2);
|
||||
|
||||
(*files)[0] = g_object_ref (file);
|
||||
(*files)[1] = NULL;
|
||||
|
||||
if (n_files)
|
||||
*n_files = 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clapper_app_utils_files_from_value (const GValue *value, GFile ***files, gint *n_files)
|
||||
{
|
||||
if (G_VALUE_HOLDS (value, GDK_TYPE_FILE_LIST)) {
|
||||
return clapper_app_utils_files_from_slist (
|
||||
(GSList *) g_value_get_boxed (value), files, n_files);
|
||||
} else if (G_VALUE_HOLDS (value, G_TYPE_FILE)) {
|
||||
return _files_from_file (
|
||||
(GFile *) g_value_get_object (value), files, n_files);
|
||||
} else if (G_VALUE_HOLDS (value, G_TYPE_STRING)) {
|
||||
return clapper_app_utils_files_from_string (
|
||||
g_value_get_string (value), files, n_files);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
clapper_app_utils_files_free (GFile **files)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; files[i]; ++i)
|
||||
g_object_unref (files[i]);
|
||||
|
||||
g_free (files);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
_parse_feature_name (gchar *str, const gchar **feature_name)
|
||||
{
|
||||
if (!str)
|
||||
return FALSE;
|
||||
|
||||
g_strstrip (str);
|
||||
|
||||
if (str[0] == '\0')
|
||||
return FALSE;
|
||||
|
||||
*feature_name = str;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
_parse_feature_rank (gchar *str, GstRank *rank)
|
||||
{
|
||||
if (!str)
|
||||
return FALSE;
|
||||
|
||||
g_strstrip (str);
|
||||
|
||||
if (str[0] == '\0')
|
||||
return FALSE;
|
||||
|
||||
if (g_ascii_isdigit (str[0])) {
|
||||
gulong l;
|
||||
gchar *endptr;
|
||||
|
||||
l = strtoul (str, &endptr, 10);
|
||||
if (endptr > str && endptr[0] == 0) {
|
||||
*rank = (GstRank) l;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
} else if (g_ascii_strcasecmp (str, "NONE") == 0) {
|
||||
*rank = GST_RANK_NONE;
|
||||
} else if (g_ascii_strcasecmp (str, "MARGINAL") == 0) {
|
||||
*rank = GST_RANK_MARGINAL;
|
||||
} else if (g_ascii_strcasecmp (str, "SECONDARY") == 0) {
|
||||
*rank = GST_RANK_SECONDARY;
|
||||
} else if (g_ascii_strcasecmp (str, "PRIMARY") == 0) {
|
||||
*rank = GST_RANK_PRIMARY;
|
||||
} else if (g_ascii_strcasecmp (str, "MAX") == 0) {
|
||||
*rank = (GstRank) G_MAXINT;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
clapper_app_utils_iterate_plugin_feature_ranks (GSettings *settings,
|
||||
ClapperAppUtilsIterRanks callback, gpointer user_data)
|
||||
{
|
||||
gchar **split, **walk, *stored_overrides;
|
||||
const gchar *env_overrides;
|
||||
gboolean from_env = FALSE;
|
||||
|
||||
stored_overrides = g_settings_get_string (settings, "plugin-feature-ranks");
|
||||
env_overrides = g_getenv ("GST_PLUGIN_FEATURE_RANK");
|
||||
|
||||
/* Iterate from GSettings, then from ENV */
|
||||
parse_overrides:
|
||||
split = g_strsplit ((from_env) ? env_overrides : stored_overrides, ",", 0);
|
||||
|
||||
for (walk = split; *walk; walk++) {
|
||||
gchar **values;
|
||||
|
||||
if (!strchr (*walk, ':'))
|
||||
continue;
|
||||
|
||||
values = g_strsplit (*walk, ":", 2);
|
||||
|
||||
if (g_strv_length (values) == 2) {
|
||||
GstRank rank;
|
||||
const gchar *feature_name;
|
||||
|
||||
if (_parse_feature_name (values[0], &feature_name)
|
||||
&& _parse_feature_rank (values[1], &rank))
|
||||
callback (feature_name, rank, from_env, user_data);
|
||||
}
|
||||
|
||||
g_strfreev (values);
|
||||
}
|
||||
|
||||
g_strfreev (split);
|
||||
|
||||
if (!from_env && env_overrides) {
|
||||
from_env = TRUE;
|
||||
goto parse_overrides;
|
||||
}
|
||||
|
||||
g_free (stored_overrides);
|
||||
}
|
Reference in New Issue
Block a user