1 Commits

Author SHA1 Message Date
Rafostar
f64f438f1e API: Add playlist support 2021-06-06 19:54:56 +02:00
29 changed files with 1018 additions and 429 deletions

View File

@@ -40,7 +40,7 @@
- [X] Remote playback controls via HTTP (VLC) + WebSockets
- [ ] Expand available API
- [ ] API documentation
- [X] Integration with the top bar
- [X] MPRIS support
- [X] Controls in the notifications panel
- [ ] Integration with the top bar
- [ ] MPRIS support
- [ ] Controls in the notifications panel
- [ ] Progress bar in the notifications panel (maybe via extension)

View File

@@ -1,115 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="16"
height="16"
viewBox="0 0 4.2333333 4.2333334"
version="1.1"
id="svg5"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
sodipodi:docname="com.github.rafostar.Clapper-symbolic.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-midpoints="true"
inkscape:snap-global="false"
units="px"
inkscape:zoom="32"
inkscape:cx="6.078125"
inkscape:cy="8.09375"
inkscape:window-width="1680"
inkscape:window-height="981"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2">
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect1853"
is_visible="true"
lpeversion="1"
satellites_param="F,0,0,1,0,1.8520833,0,1 @ F,0,0,1,0,1.8520833,0,1 @ F,0,0,1,0,1.8520833,0,1 @ F,0,0,1,0,1.8520833,0,1"
unit="px"
method="auto"
mode="F"
radius="7"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect1732"
is_visible="true"
lpeversion="1"
satellites_param="F,0,0,1,0,1.8520833,0,1 @ F,0,0,1,0,1.8520833,0,1 @ F,0,0,1,0,1.8520833,0,1 @ F,0,0,1,0,1.8520833,0,1"
unit="px"
method="auto"
mode="F"
radius="7"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g2022"
transform="matrix(0.06169519,0,0,0.06168906,-4.7800087,-3.2713603)">
<path
id="rect973"
style="fill:#000000;stroke-width:1.30776;stroke-linecap:round;stroke-linejoin:round;paint-order:stroke markers fill"
d="m 88.193064,81.795006 c -0.699254,0 -1.342327,0.227875 -1.864484,0.609782 h 51.32503 c -0.52216,-0.381907 -1.16471,-0.609782 -1.86397,-0.609782 z m -3.157945,10.475846 v 26.225278 c 0,1.74939 1.40856,3.15743 3.157945,3.15743 h 47.596576 c 1.74939,0 3.15795,-1.40804 3.15795,-3.15743 V 92.270852 Z m 20.323311,4.964038 15.40009,9.27283 -15.5205,9.56634 z" />
<path
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 83.974394,69.464471 7.344033,-0.06509 a 2.7923103,2.7923103 33.047712 0 1 2.587466,1.683384 l 7.009937,16.201526 a 1.2163248,1.2163248 123.30899 0 1 -1.116623,1.699322 l -15.720141,-0.004 a 1.862525,1.862525 44.853691 0 1 -1.862019,-1.852534 l -0.08473,-15.79409 a 1.8585738,1.8585738 134.59241 0 1 1.842075,-1.868472 z"
id="path1422"
inkscape:path-effect="#path-effect1732"
inkscape:original-d="m 82.122383,69.480886 11.048055,-0.09792 8.480852,19.601124 -19.424307,-0.005 z" />
<rect
style="fill:#000000;stroke-width:1.3;stroke-linecap:round;stroke-linejoin:round;paint-order:stroke markers fill"
id="rect1544"
width="59.366463"
height="9.8661175"
x="82"
y="79.292183"
ry="1.2306831" />
<path
id="rect1847"
style="fill:#000000;stroke-width:4.91339;stroke-linecap:round;stroke-linejoin:round;paint-order:stroke markers fill"
d="m 522.12695,200.42773 c -0.45798,3.8e-4 -0.92335,0.0696 -1.38476,0.21289 l -172.88672,53.70313 5.28515,-0.0469 a 10.55362,10.55362 0 0 1 9.7793,6.36328 l 10.69922,24.72656 158.18359,-49.13477 c 2.46089,-0.7644 3.82691,-3.36137 3.0625,-5.82226 l -8.30078,-26.72657 c -0.62108,-1.99947 -2.4529,-3.277 -4.4375,-3.27539 z m -203.69531,63.05469 -3.08398,0.95899 c -2.46089,0.7644 -3.82691,3.35942 -3.0625,5.82031 l 6.29101,20.2539 z"
transform="scale(0.26458333)" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

View File

@@ -14,10 +14,6 @@
<default>100</default>
<summary>Custom initial volume value in percentage after startup</summary>
</key>
<key name="keep-last-frame" type="b">
<default>false</default>
<summary>Keep showing last video frame after playback finishes</summary>
</key>
<key name="close-auto" type="b">
<default>false</default>
<summary>Automatically close the app after playback finishes</summary>

View File

@@ -25,7 +25,7 @@
<p>
For best stability Wayland session is recommended. Wayland users with AMD/Intel GPUs
can try enabling HIGHLY EXPERIMENTAL "vah264dec" plugin inside player preferences
for reduced CPU and GPU usage on H.264 videos.
for reduced CPU and GPU usage on standard (8-bit) H.264 videos.
</p>
</description>
<developer_name>Rafał Dzięgiel</developer_name>
@@ -52,26 +52,6 @@
</screenshot>
</screenshots>
<releases>
<release version="0.3.0" date="2021-06-18">
<description>
<p>Changes:</p>
<ul>
<li>Added MPRIS support</li>
<li>Added repeat modes: single video, whole playlist and shuffle</li>
<li>Support opening folders with media files</li>
<li>Append playlist items by holding Ctrl while doing Drag and Drop</li>
<li>Improved handling of keyboard shortcuts</li>
<li>Added more keyboard shortcuts</li>
<li>Added window that shows available keyboard shortcuts</li>
<li>Show black screen by default after playback (make showing last frame optional instead)</li>
<li>Added ability to export playlist to file</li>
<li>Improve handling of changing displays with different resolutions</li>
<li>Added support for EGL under x11 with GTK 4.3.1 or later</li>
<li>Added missing symbolic app icon</li>
<li>Some misc bug fixes and code cleanups</li>
</ul>
</description>
</release>
<release version="0.2.1" date="2021-04-19">
<description>
<p>Player:</p>

View File

@@ -4,9 +4,6 @@ iconsdir = join_paths(sharedir, 'icons', 'hicolor')
install_data('com.github.rafostar.Clapper.svg',
install_dir: join_paths(iconsdir, 'scalable', 'apps')
)
install_data('com.github.rafostar.Clapper-symbolic.svg',
install_dir: join_paths(iconsdir, 'symbolic', 'apps')
)
install_data('com.github.rafostar.Clapper.gschema.xml',
install_dir: join_paths(sharedir, 'glib-2.0', 'schemas')
)

View File

@@ -28,6 +28,8 @@
#include <gst/clapper/gstclapper-g-main-context-signal-dispatcher.h>
#include <gst/clapper/gstclapper-video-overlay-video-renderer.h>
#include <gst/clapper/gstclapper-visualization.h>
#include <gst/clapper/gstclapper-playlist.h>
#include <gst/clapper/gstclapper-playlist-item.h>
#include <gst/clapper/gstclapper-mpris.h>
#include <gst/clapper/gstclapper-gtk4-plugin.h>

View File

@@ -392,11 +392,17 @@ handle_open_uri_cb (GstClapperMprisMediaPlayer2Player * player_skeleton,
gpointer user_data)
{
GstClapper *clapper = GST_CLAPPER (user_data);
GstClapperPlaylist *playlist;
GstClapperPlaylistItem *item;
GST_DEBUG ("Handle OpenUri");
/* FIXME: set one item playlist instead */
gst_clapper_set_uri (clapper, uri);
playlist = gst_clapper_playlist_new ();
item = gst_clapper_playlist_item_new (uri);
gst_clapper_playlist_append (playlist, item);
gst_clapper_set_playlist (clapper, playlist);
gst_clapper_mpris_media_player2_player_complete_open_uri (player_skeleton, invocation);
return TRUE;
@@ -771,8 +777,12 @@ gst_clapper_mpris_new (const gchar * own_name, const gchar * id_path,
const gchar * identity, const gchar * desktop_entry,
const gchar * default_art_url)
{
return g_object_new (GST_TYPE_CLAPPER_MPRIS,
GstClapperMpris *self;
self = g_object_new (GST_TYPE_CLAPPER,
"own-name", own_name, "id_path", id_path,
"identity", identity, "desktop-entry", desktop_entry,
"default-art-url", default_art_url, NULL);
return self;
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2021 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 Library General Public
* License as published by the Free Software Foundation; either
* version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_CLAPPER_PLAYLIST_ITEM_PRIVATE_H__
#define __GST_CLAPPER_PLAYLIST_ITEM_PRIVATE_H__
#include "gstclapper-playlist.h"
struct _GstClapperPlaylistItem
{
GstObject parent;
/* ID of the playlist this item belongs to */
gchar *owner_uuid;
gint id;
gchar *uri;
gchar *suburi;
gchar *custom_title;
/* Signals */
gulong activated_signal_id;
};
struct _GstClapperPlaylistItemClass
{
GstObjectClass parent_class;
};
G_GNUC_INTERNAL
void gst_clapper_playlist_item_mark_added (GstClapperPlaylistItem *item, GstClapperPlaylist *playlist);
#endif /* __GST_CLAPPER_PLAYLIST_ITEM_PRIVATE_H__ */

View File

@@ -0,0 +1,281 @@
/*
* Copyright (C) 2021 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 Library General Public
* License as published by the Free Software Foundation; either
* version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstclapper-playlist-item.h"
#include "gstclapper-playlist-item-private.h"
#include "gstclapper-playlist-private.h"
enum
{
PROP_0,
PROP_URI,
PROP_SUBURI,
PROP_CUSTOM_TITLE,
PROP_LAST
};
enum
{
SIGNAL_ACTIVATED,
SIGNAL_LAST
};
#define parent_class gst_clapper_playlist_item_parent_class
G_DEFINE_TYPE (GstClapperPlaylistItem, gst_clapper_playlist_item, GST_TYPE_OBJECT);
static guint signals[SIGNAL_LAST] = { 0, };
static GParamSpec *param_specs[PROP_LAST] = { NULL, };
static void gst_clapper_playlist_item_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_clapper_playlist_item_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_clapper_playlist_item_dispose (GObject * object);
static void gst_clapper_playlist_item_finalize (GObject * object);
static void
gst_clapper_playlist_item_init (GstClapperPlaylistItem * self)
{
self->owner_uuid = NULL;
self->id = -1;
self->uri = NULL;
self->suburi = NULL;
self->custom_title = NULL;
}
static void
gst_clapper_playlist_item_class_init (GstClapperPlaylistItemClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
gobject_class->set_property = gst_clapper_playlist_item_set_property;
gobject_class->get_property = gst_clapper_playlist_item_get_property;
gobject_class->dispose = gst_clapper_playlist_item_dispose;
gobject_class->finalize = gst_clapper_playlist_item_finalize;
param_specs[PROP_URI] = g_param_spec_string ("uri",
"URI", "Playlist Item URI", NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
param_specs[PROP_SUBURI] = g_param_spec_string ("suburi",
"Subtitle URI", "Playlist Item Subtitle URI", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_CUSTOM_TITLE] = g_param_spec_string ("custom-title",
"Custom Title", "Playlist Item Custom Title", NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
signals[SIGNAL_ACTIVATED] =
g_signal_new ("activated", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 0, G_TYPE_INVALID);
}
static void
gst_clapper_playlist_item_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
GstClapperPlaylistItem *self = GST_CLAPPER_PLAYLIST_ITEM (object);
switch (prop_id) {
case PROP_URI:
self->uri = g_value_dup_string (value);
break;
case PROP_SUBURI:
g_free (self->suburi);
self->suburi = g_value_dup_string (value);
break;
case PROP_CUSTOM_TITLE:
self->custom_title = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_clapper_playlist_item_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
GstClapperPlaylistItem *self = GST_CLAPPER_PLAYLIST_ITEM (object);
switch (prop_id) {
case PROP_URI:
g_value_set_string (value, self->uri);
break;
case PROP_SUBURI:
g_value_set_string (value, self->suburi);
break;
case PROP_CUSTOM_TITLE:
g_value_set_string (value, self->custom_title);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_clapper_playlist_item_dispose (GObject * object)
{
GstClapperPlaylistItem *self = GST_CLAPPER_PLAYLIST_ITEM (object);
if (self->activated_signal_id) {
g_signal_handler_disconnect (self, self->activated_signal_id);
self->activated_signal_id = 0;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_clapper_playlist_item_finalize (GObject * object)
{
GstClapperPlaylistItem *self = GST_CLAPPER_PLAYLIST_ITEM (object);
g_free (self->owner_uuid);
g_free (self->uri);
g_free (self->suburi);
g_free (self->custom_title);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
item_activate_cb (GstClapperPlaylistItem * self, GParamSpec * pspec,
GstClapperPlaylist * playlist)
{
gst_clapper_playlist_emit_item_activated (playlist, self);
}
void
gst_clapper_playlist_item_mark_added (GstClapperPlaylistItem * self,
GstClapperPlaylist * playlist)
{
GST_OBJECT_LOCK (self);
self->owner_uuid = g_strdup (playlist->uuid);
self->id = playlist->id_count;
self->activated_signal_id = g_signal_connect (self, "activated",
G_CALLBACK (item_activate_cb), playlist);
GST_OBJECT_UNLOCK (self);
}
/**
* gst_clapper_playlist_item_new:
*
* Creates a new #GstClapperPlaylistItem.
*
* Returns: (transfer full): a new #GstClapperPlaylistItem object.
*/
GstClapperPlaylistItem *
gst_clapper_playlist_item_new (const gchar * uri)
{
return g_object_new (GST_TYPE_CLAPPER_PLAYLIST_ITEM, "uri", uri, NULL);
}
/**
* gst_clapper_playlist_item_new_titled:
* @uri: An URI pointing to media
* @custom_title: A custom title for this item
*
* Creates a new #GstClapperPlaylistItem with a custom title.
*
* Normally item title is obtained from media info or local filename,
* use this function for online sources where media title cannot be
* determined or if you want to override original title for some reason.
*
* Returns: (transfer full): a new #GstClapperPlaylistItem object.
*/
GstClapperPlaylistItem *
gst_clapper_playlist_item_new_titled (const gchar * uri,
const gchar * custom_title)
{
return g_object_new (GST_TYPE_CLAPPER_PLAYLIST_ITEM, "uri", uri,
"custom_title", custom_title, NULL);
}
/**
* gst_clapper_playlist_item_copy:
* @item: #GstClapperPlaylistItem
*
* Duplicates a #GstClapperPlaylistItem.
*
* Duplicated items do not belong to any playlist.
* Use this function if you want to append the same
* media into another #GstClapperPlaylist instance.
*
* Returns: (transfer full): a new #GstClapperPlaylistItem object.
*/
GstClapperPlaylistItem *
gst_clapper_playlist_item_copy (GstClapperPlaylistItem * source)
{
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST_ITEM (source), NULL);
return g_object_new (GST_TYPE_CLAPPER_PLAYLIST_ITEM, "uri", source->uri,
"suburi", source->suburi, "custom-title", source->custom_title, NULL);
}
/**
* gst_clapper_playlist_item_set_suburi:
* @item: #GstClapperPlaylistItem
* @suburi: subtitle URI
*
* Sets the external subtitle URI.
*/
void
gst_clapper_playlist_item_set_suburi (GstClapperPlaylistItem * self,
const gchar * suburi)
{
/* TODO: When setting this property for an item that is currently active,
* it should be combined with a call to
* gst_clapper_set_subtitle_track_enabled(Clapper, TRUE),
* so the subtitles are actually rendered.
*/
g_return_if_fail (GST_IS_CLAPPER_PLAYLIST_ITEM (self));
g_object_set (self, "suburi", suburi, NULL);
}
/**
* gst_clapper_playlist_item_activate:
* @item: #GstClapperPlaylistItem
*
* Activates the #GstClapperPlaylistItem.
*/
void
gst_clapper_playlist_item_activate (GstClapperPlaylistItem * self)
{
g_return_if_fail (GST_IS_CLAPPER_PLAYLIST_ITEM (self));
g_signal_emit (self, signals[SIGNAL_ACTIVATED], 0);
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2021 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 Library General Public
* License as published by the Free Software Foundation; either
* version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_CLAPPER_PLAYLIST_ITEM_H__
#define __GST_CLAPPER_PLAYLIST_ITEM_H__
#include <gst/clapper/clapper-prelude.h>
G_BEGIN_DECLS
typedef struct _GstClapperPlaylistItem GstClapperPlaylistItem;
typedef struct _GstClapperPlaylistItemClass GstClapperPlaylistItemClass;
#define GST_TYPE_CLAPPER_PLAYLIST_ITEM (gst_clapper_playlist_item_get_type ())
#define GST_IS_CLAPPER_PLAYLIST_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_PLAYLIST_ITEM))
#define GST_IS_CLAPPER_PLAYLIST_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_PLAYLIST_ITEM))
#define GST_CLAPPER_PLAYLIST_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_PLAYLIST_ITEM, GstClapperPlaylistItemClass))
#define GST_CLAPPER_PLAYLIST_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_PLAYLIST_ITEM, GstClapperPlaylistItem))
#define GST_CLAPPER_PLAYLIST_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_PLAYLIST_ITEM, GstClapperPlaylistItemClass))
#define GST_CLAPPER_PLAYLIST_ITEM_CAST(obj) ((GstClapperPlaylistItem*)(obj))
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstClapperPlaylistItem, gst_object_unref)
#endif
GST_CLAPPER_API
GType gst_clapper_playlist_item_get_type (void);
GST_CLAPPER_API
GstClapperPlaylistItem * gst_clapper_playlist_item_new (const gchar *uri);
GST_CLAPPER_API
GstClapperPlaylistItem * gst_clapper_playlist_item_new_titled (const gchar *uri, const gchar *custom_title);
GST_CLAPPER_API
GstClapperPlaylistItem * gst_clapper_playlist_item_copy (GstClapperPlaylistItem *item);
GST_CLAPPER_API
void gst_clapper_playlist_item_set_suburi (GstClapperPlaylistItem *item, const gchar *suburi);
GST_CLAPPER_API
void gst_clapper_playlist_item_activate (GstClapperPlaylistItem *item);
G_END_DECLS
#endif /* __GST_CLAPPER_PLAYLIST_ITEM_H__ */

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2021 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 Library General Public
* License as published by the Free Software Foundation; either
* version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_CLAPPER_PLAYLIST_PRIVATE_H__
#define __GST_CLAPPER_PLAYLIST_PRIVATE_H__
#include "gstclapper-playlist.h"
struct _GstClapperPlaylist
{
GstObject parent;
gchar *uuid;
gint id_count;
GArray *items;
gint active_index;
};
struct _GstClapperPlaylistClass
{
GstObjectClass parent_class;
};
G_GNUC_INTERNAL
void gst_clapper_playlist_emit_item_activated (GstClapperPlaylist *playlist, GstClapperPlaylistItem *item);
#endif /* __GST_CLAPPER_PLAYLIST_PRIVATE_H__ */

275
lib/gst/clapper/gstclapper-playlist.c vendored Normal file
View File

@@ -0,0 +1,275 @@
/*
* Copyright (C) 2021 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 Library General Public
* License as published by the Free Software Foundation; either
* version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstclapper-playlist.h"
#include "gstclapper-playlist-private.h"
#include "gstclapper-playlist-item.h"
#include "gstclapper-playlist-item-private.h"
enum
{
SIGNAL_ITEM_ACTIVATED,
SIGNAL_LAST
};
#define parent_class gst_clapper_playlist_parent_class
G_DEFINE_TYPE (GstClapperPlaylist, gst_clapper_playlist, GST_TYPE_OBJECT);
static guint signals[SIGNAL_LAST] = { 0, };
static void gst_clapper_playlist_dispose (GObject * object);
static void gst_clapper_playlist_finalize (GObject * object);
static void
gst_clapper_playlist_init (GstClapperPlaylist * self)
{
self->uuid = g_uuid_string_random ();
self->id_count = 0;
self->items = g_array_new (FALSE, FALSE, sizeof (GstClapperPlaylistItem));
self->active_index = -1;
g_array_set_clear_func (self->items, (GDestroyNotify) gst_object_unref);
}
static void
gst_clapper_playlist_class_init (GstClapperPlaylistClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
gobject_class->dispose = gst_clapper_playlist_dispose;
gobject_class->finalize = gst_clapper_playlist_finalize;
signals[SIGNAL_ITEM_ACTIVATED] =
g_signal_new ("item-activated", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLAPPER_PLAYLIST_ITEM);
}
static void
gst_clapper_playlist_dispose (GObject * object)
{
GstClapperPlaylist *self = GST_CLAPPER_PLAYLIST (object);
/* FIXME: Need this for something? */
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_clapper_playlist_finalize (GObject * object)
{
GstClapperPlaylist *self = GST_CLAPPER_PLAYLIST (object);
g_free (self->uuid);
g_array_unref (self->items);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
void
gst_clapper_playlist_emit_item_activated (GstClapperPlaylist * self,
GstClapperPlaylistItem * item)
{
g_signal_emit (self, signals[SIGNAL_ITEM_ACTIVATED], 0, item);
}
/**
* gst_clapper_playlist_new:
*
* Creates a new #GstClapperPlaylist.
*
* Returns: (transfer full): a new #GstClapperPlaylist instance.
*/
GstClapperPlaylist *
gst_clapper_playlist_new (void)
{
return g_object_new (GST_TYPE_CLAPPER_PLAYLIST, NULL);
}
/**
* gst_clapper_playlist_append:
* @playlist: #GstClapperPlaylist
* @item: #GstClapperPlaylistItem to append
*
* Adds a new #GstClapperPlaylistItem to the end of playlist.
*
* Returns: %TRUE if the item was added successfully.
*/
gboolean
gst_clapper_playlist_append (GstClapperPlaylist * self, GstClapperPlaylistItem * item)
{
gboolean added = FALSE;
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST (self), FALSE);
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST_ITEM (item), FALSE);
g_return_val_if_fail (item->owner_uuid == NULL, FALSE);
GST_OBJECT_LOCK (self);
added = g_array_append_val (self->items, item) != NULL;
if (added) {
gst_clapper_playlist_item_mark_added (item, self);
self->id_count++;
}
GST_OBJECT_UNLOCK (self);
return added;
}
/**
* gst_clapper_playlist_get_length:
* @playlist: #GstClapperPlaylist
*
* Returns: Amount of items in playlist.
*/
guint
gst_clapper_playlist_get_length (GstClapperPlaylist * self)
{
guint len;
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST (self), 0);
GST_OBJECT_LOCK (self);
len = self->items->len;
GST_OBJECT_UNLOCK (self);
return len;
}
/**
* gst_clapper_playlist_get_item_at_index:
* @playlist: #GstClapperPlaylist
*
* Returns: (transfer none): A #GstClapperPlaylistItem at given index.
*/
GstClapperPlaylistItem *
gst_clapper_playlist_get_item_at_index (GstClapperPlaylist * self, gint index)
{
GstClapperPlaylistItem *item = NULL;
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST (self), NULL);
GST_OBJECT_LOCK (self);
if (index < self->items->len)
goto out;
item = &g_array_index (self->items, GstClapperPlaylistItem, index);
out:
GST_OBJECT_UNLOCK (self);
return item;
}
/**
* gst_clapper_playlist_get_active_item:
* @playlist: #GstClapperPlaylist
*
* Returns: (transfer none): A #GstClapperPlaylistItem that is
* currently playing.
*/
GstClapperPlaylistItem *
gst_clapper_playlist_get_active_item (GstClapperPlaylist * self)
{
gint active_index;
GST_OBJECT_LOCK (self);
active_index = self->active_index;
GST_OBJECT_UNLOCK (self);
return gst_clapper_playlist_get_item_at_index (self, active_index);
}
/**
* gst_clapper_playlist_remove_item_at_index:
* @playlist: #GstClapperPlaylist
* @index: Index of #GstClapperPlaylistItem to remove
*
* Removes item at given index from playlist.
*
* Returns: %TRUE if the item was removed successfully.
*/
gboolean
gst_clapper_playlist_remove_item_at_index (GstClapperPlaylist * self, guint index)
{
gboolean removed = FALSE;
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST (self), FALSE);
GST_OBJECT_LOCK (self);
if (index >= self->items->len || index == self->active_index)
goto out;
removed = g_array_remove_index (self->items, index) != NULL;
out:
GST_OBJECT_UNLOCK (self);
return removed;
}
/**
* gst_clapper_playlist_remove_item:
* @playlist: #GstClapperPlaylist
* @item: #GstClapperPlaylistItem object to remove
*
* Removes given playlist item from playlist.
*
* Returns: %TRUE if the item was removed successfully.
*/
gboolean
gst_clapper_playlist_remove_item (GstClapperPlaylist * self,
GstClapperPlaylistItem * item)
{
gint i;
gboolean removed = FALSE;
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST (self), FALSE);
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST_ITEM (item), FALSE);
GST_OBJECT_LOCK (self);
if (strcmp (self->uuid, item->owner_uuid) != 0)
goto out;
for (i = 0; i < self->items->len; i++) {
GstClapperPlaylistItem *curr_item;
curr_item = &g_array_index (self->items, GstClapperPlaylistItem, i);
if (!curr_item)
goto out;
if (item->id == curr_item->id) {
removed = g_array_remove_index (self->items, i) != NULL;
break;
}
}
out:
GST_OBJECT_UNLOCK (self);
return removed;
}

71
lib/gst/clapper/gstclapper-playlist.h vendored Normal file
View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2021 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 Library General Public
* License as published by the Free Software Foundation; either
* version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_CLAPPER_PLAYLIST_H__
#define __GST_CLAPPER_PLAYLIST_H__
#include <gst/clapper/clapper-prelude.h>
#include <gst/clapper/gstclapper-playlist-item.h>
G_BEGIN_DECLS
typedef struct _GstClapperPlaylist GstClapperPlaylist;
typedef struct _GstClapperPlaylistClass GstClapperPlaylistClass;
#define GST_TYPE_CLAPPER_PLAYLIST (gst_clapper_playlist_get_type ())
#define GST_IS_CLAPPER_PLAYLIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_PLAYLIST))
#define GST_IS_CLAPPER_PLAYLIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_PLAYLIST))
#define GST_CLAPPER_PLAYLIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_PLAYLIST, GstClapperPlaylistClass))
#define GST_CLAPPER_PLAYLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_PLAYLIST, GstClapperPlaylist))
#define GST_CLAPPER_PLAYLIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_PLAYLIST, GstClapperPlaylistClass))
#define GST_CLAPPER_PLAYLIST_CAST(obj) ((GstClapperPlaylist*)(obj))
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstClapperPlaylist, g_object_unref)
#endif
GST_CLAPPER_API
GType gst_clapper_playlist_get_type (void);
GST_CLAPPER_API
GstClapperPlaylist * gst_clapper_playlist_new (void);
GST_CLAPPER_API
gboolean gst_clapper_playlist_append (GstClapperPlaylist *playlist, GstClapperPlaylistItem *item);
GST_CLAPPER_API
guint gst_clapper_playlist_get_length (GstClapperPlaylist *playlist);
GST_CLAPPER_API
GstClapperPlaylistItem *
gst_clapper_playlist_get_item_at_index (GstClapperPlaylist *playlist, gint index);
GST_CLAPPER_API
GstClapperPlaylistItem *
gst_clapper_playlist_get_active_item (GstClapperPlaylist *playlist);
GST_CLAPPER_API
gboolean gst_clapper_playlist_remove_item_at_index (GstClapperPlaylist *playlist, guint index);
GST_CLAPPER_API
gboolean gst_clapper_playlist_remove_item (GstClapperPlaylist *playlist, GstClapperPlaylistItem *item);
G_END_DECLS
#endif /* __GST_CLAPPER_PLAYLIST_H__ */

View File

@@ -46,6 +46,7 @@
#include "gstclapper-signal-dispatcher-private.h"
#include "gstclapper-video-renderer-private.h"
#include "gstclapper-media-info-private.h"
#include "gstclapper-playlist-item-private.h"
#include "gstclapper-mpris-private.h"
GST_DEBUG_CATEGORY_STATIC (gst_clapper_debug);
@@ -79,8 +80,7 @@ enum
PROP_SIGNAL_DISPATCHER,
PROP_MPRIS,
PROP_STATE,
PROP_URI,
PROP_SUBURI,
PROP_PLAYLIST,
PROP_POSITION,
PROP_DURATION,
PROP_MEDIA_INFO,
@@ -134,6 +134,7 @@ struct _GstClapper
gchar *uri;
gchar *redirect_uri;
gchar *suburi;
gchar *custom_title;
GThread *thread;
GMutex lock;
@@ -188,6 +189,12 @@ struct _GstClapper
gchar *audio_sid;
gchar *subtitle_sid;
gulong stream_notify_id;
/* For playlist */
GstClapperPlaylist *playlist;
GstClapperPlaylistItem *active_item;
gulong item_activated_id;
gulong suburi_notify_id;
};
struct _GstClapperClass
@@ -320,12 +327,8 @@ gst_clapper_class_init (GstClapperClass * klass)
GST_TYPE_CLAPPER_STATE, DEFAULT_STATE, G_PARAM_READABLE |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
param_specs[PROP_URI] = g_param_spec_string ("uri", "URI", "Current URI",
DEFAULT_URI, G_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
param_specs[PROP_SUBURI] = g_param_spec_string ("suburi", "Subtitle URI",
"Current Subtitle URI", NULL, G_PARAM_READWRITE |
param_specs[PROP_PLAYLIST] = g_param_spec_string ("playlist", "Playlist",
"Current Playlist", NULL, G_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
param_specs[PROP_POSITION] =
@@ -519,6 +522,8 @@ gst_clapper_finalize (GObject * object)
g_object_unref (self->signal_dispatcher);
if (self->mpris)
g_object_unref (self->mpris);
if (self->playlist)
gst_object_unref (self->playlist);
if (self->current_vis_element)
gst_object_unref (self->current_vis_element);
if (self->collection)
@@ -567,35 +572,6 @@ uri_loaded_signal_data_free (UriLoadedSignalData * data)
g_free (data);
}
static gboolean
gst_clapper_set_uri_internal (gpointer user_data)
{
GstClapper *self = user_data;
gst_clapper_stop_internal (self, FALSE);
g_mutex_lock (&self->lock);
GST_DEBUG_OBJECT (self, "Changing URI to '%s'", GST_STR_NULL (self->uri));
g_object_set (self->playbin, "uri", self->uri, NULL);
g_object_set (self->playbin, "suburi", NULL, NULL);
self->can_start = TRUE;
if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID,
signals[SIGNAL_URI_LOADED], 0, NULL, NULL, NULL) != 0) {
UriLoadedSignalData *data = g_new (UriLoadedSignalData, 1);
data->clapper = g_object_ref (self);
data->uri = g_strdup (self->uri);
gst_clapper_signal_dispatcher_dispatch (self->signal_dispatcher, self,
uri_loaded_dispatch, data,
(GDestroyNotify) uri_loaded_signal_data_free);
}
g_mutex_unlock (&self->lock);
return G_SOURCE_REMOVE;
}
static gboolean
gst_clapper_set_suburi_internal (gpointer user_data)
{
@@ -628,6 +604,100 @@ gst_clapper_set_suburi_internal (gpointer user_data)
return G_SOURCE_REMOVE;
}
static void
suburi_notify_cb (GstClapperPlaylistItem * item, GParamSpec * pspec,
GstClapper * self)
{
g_mutex_lock (&self->lock);
g_free (self->suburi);
self->suburi = g_strdup (item->suburi);
GST_DEBUG_OBJECT (self, "Set suburi: %s", self->suburi);
g_mutex_unlock (&self->lock);
g_main_context_invoke_full (self->context, G_PRIORITY_DEFAULT + 1,
gst_clapper_set_suburi_internal, self, NULL);
}
static void
gst_clapper_set_playlist_item_locked (GstClapper * self,
GstClapperPlaylistItem * item)
{
if (self->suburi_notify_id)
g_signal_handler_disconnect (self->active_item, self->suburi_notify_id);
gst_object_replace ((GstObject **) & self->active_item,
(GstObject *) item);
g_free (self->uri);
self->uri = g_strdup (self->active_item->uri);
g_free (self->redirect_uri);
self->redirect_uri = NULL;
g_free (self->suburi);
self->suburi = g_strdup (self->active_item->suburi);
g_free (self->custom_title);
self->custom_title = g_strdup (self->active_item->custom_title);
GST_DEBUG_OBJECT (self, "Changing URI to '%s'",
GST_STR_NULL (self->uri));
g_object_set (self->playbin, "uri", self->uri, NULL);
GST_DEBUG_OBJECT (self, "Changing SUBURI to '%s'",
GST_STR_NULL (self->suburi));
g_object_set (self->playbin, "suburi", self->suburi, NULL);
self->suburi_notify_id = g_signal_connect (self->active_item,
"notify::suburi", G_CALLBACK (suburi_notify_cb), self);
self->can_start = TRUE;
if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID,
signals[SIGNAL_URI_LOADED], 0, NULL, NULL, NULL) != 0) {
UriLoadedSignalData *data = g_new (UriLoadedSignalData, 1);
data->clapper = g_object_ref (self);
data->uri = g_strdup (self->uri);
gst_clapper_signal_dispatcher_dispatch (self->signal_dispatcher, self,
uri_loaded_dispatch, data,
(GDestroyNotify) uri_loaded_signal_data_free);
}
}
static gboolean
gst_clapper_set_playlist_internal (gpointer user_data)
{
GstClapper *self = user_data;
GstClapperPlaylistItem *item;
gst_clapper_stop_internal (self, FALSE);
g_mutex_lock (&self->lock);
item = gst_clapper_playlist_get_item_at_index (self->playlist, 0);
if (!item) {
GST_DEBUG_OBJECT (self, "Set empty playlist");
goto out;
}
gst_clapper_set_playlist_item_locked (self, item);
out:
g_mutex_unlock (&self->lock);
return G_SOURCE_REMOVE;
}
static void
item_activated_cb (G_GNUC_UNUSED GstClapperPlaylist * playlist,
GstClapperPlaylistItem * item, gpointer user_data)
{
GstClapper *self = GST_CLAPPER (user_data);
g_mutex_lock (&self->lock);
gst_clapper_set_playlist_item_locked (self, item);
g_mutex_unlock (&self->lock);
}
static void
gst_clapper_set_rate_internal (GstClapper * self)
{
@@ -664,35 +734,21 @@ gst_clapper_set_property (GObject * object, guint prop_id,
case PROP_MPRIS:
self->mpris = g_value_dup_object (value);
break;
case PROP_URI:{
case PROP_PLAYLIST:
g_mutex_lock (&self->lock);
g_free (self->uri);
g_free (self->redirect_uri);
self->redirect_uri = NULL;
g_free (self->suburi);
self->suburi = NULL;
self->uri = g_value_dup_string (value);
GST_DEBUG_OBJECT (self, "Set uri=%s", self->uri);
if (self->playlist) {
if (self->item_activated_id)
g_signal_handler_disconnect (self->playlist, self->item_activated_id);
gst_object_unref (self->playlist);
}
self->playlist = g_value_dup_object (value);
self->item_activated_id = g_signal_connect (self->playlist, "item-activated",
G_CALLBACK (item_activated_cb), self);
g_mutex_unlock (&self->lock);
g_main_context_invoke_full (self->context, G_PRIORITY_DEFAULT,
gst_clapper_set_uri_internal, self, NULL);
gst_clapper_set_playlist_internal, self, NULL);
break;
}
case PROP_SUBURI:{
g_mutex_lock (&self->lock);
g_free (self->suburi);
self->suburi = g_value_dup_string (value);
GST_DEBUG_OBJECT (self, "Set suburi=%s", self->suburi);
g_mutex_unlock (&self->lock);
g_main_context_invoke_full (self->context, G_PRIORITY_DEFAULT,
gst_clapper_set_suburi_internal, self, NULL);
break;
}
case PROP_VOLUME: {
GValue volume_linear = G_VALUE_INIT;
gdouble volume = g_value_get_double (value);
@@ -757,27 +813,13 @@ gst_clapper_get_property (GObject * object, guint prop_id,
switch (prop_id) {
case PROP_MPRIS:
g_mutex_lock (&self->lock);
g_value_set_object (value, self->mpris);
g_mutex_unlock (&self->lock);
break;
case PROP_STATE:
g_mutex_lock (&self->lock);
g_value_set_enum (value, self->app_state);
g_mutex_unlock (&self->lock);
break;
case PROP_URI:
g_mutex_lock (&self->lock);
g_value_set_string (value, self->uri);
g_mutex_unlock (&self->lock);
break;
case PROP_SUBURI:
g_mutex_lock (&self->lock);
g_value_set_string (value, self->suburi);
g_mutex_unlock (&self->lock);
GST_DEBUG_OBJECT (self, "Returning suburi=%s",
g_value_get_string (value));
break;
case PROP_POSITION:{
gint64 position = GST_CLOCK_TIME_NONE;
@@ -787,12 +829,11 @@ gst_clapper_get_property (GObject * object, guint prop_id,
GST_TIME_ARGS (g_value_get_uint64 (value)));
break;
}
case PROP_DURATION:{
case PROP_DURATION:
g_value_set_uint64 (value, self->cached_duration);
GST_TRACE_OBJECT (self, "Returning duration=%" GST_TIME_FORMAT,
GST_TIME_ARGS (g_value_get_uint64 (value)));
break;
}
case PROP_MEDIA_INFO:{
GstClapperMediaInfo *media_info = gst_clapper_get_media_info (self);
g_value_take_object (value, media_info);
@@ -839,20 +880,18 @@ gst_clapper_get_property (GObject * object, guint prop_id,
case PROP_PIPELINE:
g_value_set_object (value, self->playbin);
break;
case PROP_VIDEO_MULTIVIEW_MODE:{
case PROP_VIDEO_MULTIVIEW_MODE:
g_object_get_property (G_OBJECT (self->playbin), "video-multiview-mode",
value);
GST_TRACE_OBJECT (self, "Return multiview mode=%d",
g_value_get_enum (value));
break;
}
case PROP_VIDEO_MULTIVIEW_FLAGS:{
case PROP_VIDEO_MULTIVIEW_FLAGS:
g_object_get_property (G_OBJECT (self->playbin), "video-multiview-flags",
value);
GST_TRACE_OBJECT (self, "Return multiview flags=%x",
g_value_get_flags (value));
break;
}
case PROP_AUDIO_VIDEO_OFFSET:
g_object_get_property (G_OBJECT (self->playbin), "av-offset", value);
break;
@@ -1618,7 +1657,7 @@ static void
emit_duration_changed (GstClapper * self, GstClockTime duration)
{
if (self->cached_duration == duration
|| self->cached_duration / (250 * GST_MSECOND) == duration / (250 * GST_MSECOND))
|| self->cached_duration / GST_MSECOND == duration / GST_MSECOND)
return;
GST_DEBUG_OBJECT (self, "Duration changed %" GST_TIME_FORMAT,
@@ -1806,11 +1845,13 @@ request_state_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg,
static void
media_info_update (GstClapper * self, GstClapperMediaInfo * info)
{
/* Update title from new tags or leave the title from URI */
gchar *tags_title = get_from_tags (self, info, get_title);
if (tags_title) {
g_free (info->title);
info->title = tags_title;
if (!self->custom_title) {
/* Update title from new tags or leave the title from URI */
gchar *tags_title = get_from_tags (self, info, get_title);
if (tags_title) {
g_free (info->title);
info->title = tags_title;
}
}
g_free (info->container);
@@ -2819,7 +2860,10 @@ gst_clapper_media_info_create (GstClapper * self)
GST_TYPE_CLAPPER_SUBTITLE_INFO);
}
media_info->title = get_from_tags (self, media_info, get_title);
if (self->custom_title)
media_info->title = g_strdup (self->custom_title);
if (!media_info->title)
media_info->title = get_from_tags (self, media_info, get_title);
if (!media_info->title)
media_info->title = get_title_from_uri (self->uri);
@@ -3632,77 +3676,19 @@ gst_clapper_get_state (GstClapper * self)
}
/**
* gst_clapper_get_uri:
* gst_clapper_set_playlist:
* @clapper: #GstClapper instance
* @playlist: #GstClapperPlaylist instance
*
* Gets the URI of the currently-playing stream.
*
* Returns: (transfer full): a string containing the URI of the
* currently-playing stream. g_free() after usage.
*/
gchar *
gst_clapper_get_uri (GstClapper * self)
{
gchar *val;
g_return_val_if_fail (GST_IS_CLAPPER (self), DEFAULT_URI);
g_object_get (self, "uri", &val, NULL);
return val;
}
/**
* gst_clapper_set_uri:
* @clapper: #GstClapper instance
* @uri: next URI to play.
*
* Sets the next URI to play.
* Sets the new #GstClapperPlaylist
*/
void
gst_clapper_set_uri (GstClapper * self, const gchar * val)
gst_clapper_set_playlist (GstClapper * self, GstClapperPlaylist * val)
{
g_return_if_fail (GST_IS_CLAPPER (self));
g_return_if_fail (GST_IS_CLAPPER_PLAYLIST (val));
g_object_set (self, "uri", val, NULL);
}
/**
* gst_clapper_set_subtitle_uri:
* @clapper: #GstClapper instance
* @uri: subtitle URI
*
* Sets the external subtitle URI. This should be combined with a call to
* gst_clapper_set_subtitle_track_enabled(@clapper, TRUE) so the subtitles are actually
* rendered.
*/
void
gst_clapper_set_subtitle_uri (GstClapper * self, const gchar * suburi)
{
g_return_if_fail (GST_IS_CLAPPER (self));
g_object_set (self, "suburi", suburi, NULL);
}
/**
* gst_clapper_get_subtitle_uri:
* @clapper: #GstClapper instance
*
* current subtitle URI
*
* Returns: (transfer full): URI of the current external subtitle.
* g_free() after usage.
*/
gchar *
gst_clapper_get_subtitle_uri (GstClapper * self)
{
gchar *val = NULL;
g_return_val_if_fail (GST_IS_CLAPPER (self), NULL);
g_object_get (self, "suburi", &val, NULL);
return val;
g_object_set (self, "playlist", val, NULL);
}
/**

View File

@@ -30,6 +30,8 @@
#include <gst/clapper/gstclapper-signal-dispatcher.h>
#include <gst/clapper/gstclapper-video-renderer.h>
#include <gst/clapper/gstclapper-media-info.h>
#include <gst/clapper/gstclapper-playlist.h>
#include <gst/clapper/gstclapper-playlist-item.h>
#include <gst/clapper/gstclapper-mpris.h>
G_BEGIN_DECLS
@@ -193,16 +195,7 @@ GST_CLAPPER_API
gdouble gst_clapper_get_rate (GstClapper *clapper);
GST_CLAPPER_API
gchar * gst_clapper_get_uri (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_set_uri (GstClapper *clapper, const gchar *uri);
GST_CLAPPER_API
gchar * gst_clapper_get_subtitle_uri (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_set_subtitle_uri (GstClapper *clapper, const gchar *uri);
void gst_clapper_set_playlist (GstClapper *clapper, GstClapperPlaylist *playlist);
GST_CLAPPER_API
GstClockTime gst_clapper_get_position (GstClapper *clapper);

View File

@@ -37,6 +37,10 @@
GST_DEBUG_CATEGORY (gst_debug_clapper_gl_sink);
#define GST_CAT_DEFAULT gst_debug_clapper_gl_sink
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
#define DEFAULT_PAR_N 0
#define DEFAULT_PAR_D 1
static GstStaticPadTemplate gst_clapper_gl_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
@@ -58,7 +62,6 @@ static gboolean gst_clapper_gl_sink_propose_allocation (GstBaseSink * bsink,
static gboolean gst_clapper_gl_sink_query (GstBaseSink * bsink, GstQuery * query);
static gboolean gst_clapper_gl_sink_start (GstBaseSink * bsink);
static gboolean gst_clapper_gl_sink_stop (GstBaseSink * bsink);
static GstFlowReturn gst_clapper_gl_sink_wait_event (GstBaseSink * bsink, GstEvent * event);
static GstStateChangeReturn
gst_clapper_gl_sink_change_state (GstElement * element,
@@ -76,6 +79,14 @@ static GstFlowReturn gst_clapper_gl_sink_show_frame (GstVideoSink * bsink,
static void
gst_clapper_gl_sink_navigation_interface_init (GstNavigationInterface * iface);
enum
{
PROP_0,
PROP_WIDGET,
PROP_FORCE_ASPECT_RATIO,
PROP_PIXEL_ASPECT_RATIO,
};
#define gst_clapper_gl_sink_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstClapperGLSink, gst_clapper_gl_sink,
GST_TYPE_VIDEO_SINK,
@@ -101,7 +112,6 @@ gst_clapper_gl_sink_class_init (GstClapperGLSinkClass * klass)
gobject_class->set_property = gst_clapper_gl_sink_set_property;
gobject_class->get_property = gst_clapper_gl_sink_get_property;
gobject_class->finalize = gst_clapper_gl_sink_finalize;
g_object_class_install_property (gobject_class, PROP_WIDGET,
g_param_spec_object ("widget", "GTK Widget",
@@ -109,7 +119,19 @@ gst_clapper_gl_sink_class_init (GstClapperGLSinkClass * klass)
"(must only be get from the GTK main thread)",
GTK_TYPE_WIDGET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
gst_gtk_install_shared_properties (gobject_class);
g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
g_param_spec_boolean ("force-aspect-ratio",
"Force aspect ratio",
"When enabled, scaling will respect original aspect ratio",
DEFAULT_FORCE_ASPECT_RATIO,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio",
"The pixel aspect ratio of the device", DEFAULT_PAR_N, DEFAULT_PAR_D,
G_MAXINT, 1, 1, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gobject_class->finalize = gst_clapper_gl_sink_finalize;
gstelement_class->change_state = gst_clapper_gl_sink_change_state;
@@ -120,7 +142,6 @@ gst_clapper_gl_sink_class_init (GstClapperGLSinkClass * klass)
gstbasesink_class->query = gst_clapper_gl_sink_query;
gstbasesink_class->start = gst_clapper_gl_sink_start;
gstbasesink_class->stop = gst_clapper_gl_sink_stop;
gstbasesink_class->wait_event = gst_clapper_gl_sink_wait_event;
gstvideosink_class->show_frame = gst_clapper_gl_sink_show_frame;
@@ -145,9 +166,6 @@ gst_clapper_gl_sink_init (GstClapperGLSink * clapper_sink)
clapper_sink->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
clapper_sink->par_n = DEFAULT_PAR_N;
clapper_sink->par_d = DEFAULT_PAR_D;
clapper_sink->keep_last_frame = DEFAULT_KEEP_LAST_FRAME;
clapper_sink->had_eos = FALSE;
}
static void
@@ -210,12 +228,12 @@ gst_clapper_gl_sink_get_widget (GstClapperGLSink * clapper_sink)
clapper_sink->widget = (GtkClapperGLWidget *)
GST_CLAPPER_GL_SINK_GET_CLASS (clapper_sink)->create_widget ();
g_object_bind_property (clapper_sink, "force-aspect-ratio", clapper_sink->widget,
clapper_sink->bind_aspect_ratio =
g_object_bind_property (clapper_sink, "force-aspect-ratio", clapper_sink->widget,
"force-aspect-ratio", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
g_object_bind_property (clapper_sink, "pixel-aspect-ratio", clapper_sink->widget,
clapper_sink->bind_pixel_aspect_ratio =
g_object_bind_property (clapper_sink, "pixel-aspect-ratio", clapper_sink->widget,
"pixel-aspect-ratio", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
g_object_bind_property (clapper_sink, "keep-last-frame", clapper_sink->widget,
"keep-last-frame", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
/* Take the floating ref, other wise the destruction of the container will
* make this widget disappear possibly before we are done. */
@@ -261,9 +279,6 @@ gst_clapper_gl_sink_get_property (GObject * object, guint prop_id,
case PROP_PIXEL_ASPECT_RATIO:
gst_value_set_fraction (value, clapper_sink->par_n, clapper_sink->par_d);
break;
case PROP_KEEP_LAST_FRAME:
g_value_set_boolean (value, clapper_sink->keep_last_frame);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -284,9 +299,6 @@ gst_clapper_gl_sink_set_property (GObject * object, guint prop_id,
clapper_sink->par_n = gst_value_get_fraction_numerator (value);
clapper_sink->par_d = gst_value_get_fraction_denominator (value);
break;
case PROP_KEEP_LAST_FRAME:
clapper_sink->keep_last_frame = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -577,7 +589,6 @@ gst_clapper_gl_sink_change_state (GstElement * element, GstStateChange transitio
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
GST_OBJECT_LOCK (clapper_sink);
clapper_sink->had_eos = FALSE;
if (clapper_sink->widget) {
GTK_CLAPPER_GL_WIDGET_LOCK (clapper_sink->widget);
clapper_sink->widget->ignore_buffers = FALSE;
@@ -603,8 +614,7 @@ gst_clapper_gl_sink_change_state (GstElement * element, GstStateChange transitio
GST_OBJECT_LOCK (clapper_sink);
if (clapper_sink->widget) {
GTK_CLAPPER_GL_WIDGET_LOCK (clapper_sink->widget);
clapper_sink->widget->ignore_buffers =
!clapper_sink->had_eos || !clapper_sink->keep_last_frame;
clapper_sink->widget->ignore_buffers = TRUE;
GTK_CLAPPER_GL_WIDGET_UNLOCK (clapper_sink->widget);
}
GST_OBJECT_UNLOCK (clapper_sink);
@@ -696,29 +706,6 @@ gst_clapper_gl_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
return TRUE;
}
static GstFlowReturn
gst_clapper_gl_sink_wait_event (GstBaseSink * bsink, GstEvent * event)
{
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (bsink);
GstFlowReturn ret;
ret = GST_BASE_SINK_CLASS (parent_class)->wait_event (bsink, event);
switch (event->type) {
case GST_EVENT_EOS:
if (ret == GST_FLOW_OK) {
GST_OBJECT_LOCK (clapper_sink);
clapper_sink->had_eos = TRUE;
GST_OBJECT_UNLOCK (clapper_sink);
}
break;
default:
break;
}
return ret;
}
static GstFlowReturn
gst_clapper_gl_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
{

View File

@@ -58,14 +58,15 @@ struct _GstClapperGLSink
GtkClapperGLWidget *widget;
gboolean had_eos;
/* properties */
gboolean force_aspect_ratio;
GBinding *bind_aspect_ratio;
gint par_n, par_d;
gboolean keep_last_frame;
GBinding *bind_pixel_aspect_ratio;
gboolean ignore_textures;
GBinding *bind_ignore_textures;
GtkWidget *window;
gulong widget_destroy_id;

View File

@@ -19,7 +19,6 @@
* Boston, MA 02110-1301, USA.
*/
#include <gst/gst.h>
#include "gstgtkutils.h"
struct invoke_context
@@ -70,26 +69,3 @@ gst_gtk_invoke_on_main (GThreadFunc func, gpointer data)
return info.res;
}
void
gst_gtk_install_shared_properties (GObjectClass *gobject_class)
{
g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
g_param_spec_boolean ("force-aspect-ratio",
"Force aspect ratio",
"When enabled, scaling will respect original aspect ratio",
DEFAULT_FORCE_ASPECT_RATIO,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio",
"The pixel aspect ratio of the device", DEFAULT_PAR_N, DEFAULT_PAR_D,
G_MAXINT, 1, 1, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_KEEP_LAST_FRAME,
g_param_spec_boolean ("keep-last-frame",
"Keep last frame",
"Keep showing last video frame after playback instead of black screen",
DEFAULT_KEEP_LAST_FRAME,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}

View File

@@ -22,25 +22,8 @@
#ifndef __GST_GTK_UTILS_H__
#define __GST_GTK_UTILS_H__
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
#define DEFAULT_PAR_N 0
#define DEFAULT_PAR_D 1
#define DEFAULT_KEEP_LAST_FRAME FALSE
#include <glib.h>
#include <glib-object.h>
enum
{
PROP_0,
PROP_WIDGET,
PROP_FORCE_ASPECT_RATIO,
PROP_PIXEL_ASPECT_RATIO,
PROP_KEEP_LAST_FRAME
};
gpointer gst_gtk_invoke_on_main (GThreadFunc func, gpointer data);
void gst_gtk_install_shared_properties (GObjectClass *gobject_class);
#endif /* __GST_GTK_UTILS_H__ */

View File

@@ -57,6 +57,10 @@
GST_DEBUG_CATEGORY (gst_debug_clapper_gl_widget);
#define GST_CAT_DEFAULT gst_debug_clapper_gl_widget
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
#define DEFAULT_PAR_N 0
#define DEFAULT_PAR_D 1
struct _GtkClapperGLWidgetPrivate
{
gboolean initiated;
@@ -90,6 +94,13 @@ G_DEFINE_TYPE_WITH_CODE (GtkClapperGLWidget, gtk_clapper_gl_widget, GTK_TYPE_GL_
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gtkclapperglwidget", 0,
"GTK Clapper GL Widget"));
enum
{
PROP_0,
PROP_FORCE_ASPECT_RATIO,
PROP_PIXEL_ASPECT_RATIO,
};
static void
gtk_clapper_gl_widget_get_preferred_width (GtkWidget * widget, gint * min,
gint * natural)
@@ -163,9 +174,6 @@ gtk_clapper_gl_widget_set_property (GObject * object, guint prop_id,
clapper_widget->par_n = gst_value_get_fraction_numerator (value);
clapper_widget->par_d = gst_value_get_fraction_denominator (value);
break;
case PROP_KEEP_LAST_FRAME:
clapper_widget->keep_last_frame = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -185,9 +193,6 @@ gtk_clapper_gl_widget_get_property (GObject * object, guint prop_id,
case PROP_PIXEL_ASPECT_RATIO:
gst_value_set_fraction (value, clapper_widget->par_n, clapper_widget->par_d);
break;
case PROP_KEEP_LAST_FRAME:
g_value_set_boolean (value, clapper_widget->keep_last_frame);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -904,20 +909,30 @@ _get_gl_context (GtkClapperGLWidget * clapper_widget)
static void
gtk_clapper_gl_widget_class_init (GtkClapperGLWidgetClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
GtkGLAreaClass *gl_area_class = (GtkGLAreaClass *) klass;
GObjectClass *gobject_klass = (GObjectClass *) klass;
GtkWidgetClass *widget_klass = (GtkWidgetClass *) klass;
GtkGLAreaClass *gl_area_klass = (GtkGLAreaClass *) klass;
gobject_class->set_property = gtk_clapper_gl_widget_set_property;
gobject_class->get_property = gtk_clapper_gl_widget_get_property;
gobject_class->finalize = gtk_clapper_gl_widget_finalize;
gobject_klass->set_property = gtk_clapper_gl_widget_set_property;
gobject_klass->get_property = gtk_clapper_gl_widget_get_property;
gobject_klass->finalize = gtk_clapper_gl_widget_finalize;
gst_gtk_install_shared_properties (gobject_class);
g_object_class_install_property (gobject_klass, PROP_FORCE_ASPECT_RATIO,
g_param_spec_boolean ("force-aspect-ratio",
"Force aspect ratio",
"When enabled, scaling will respect original aspect ratio",
DEFAULT_FORCE_ASPECT_RATIO,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
widget_class->measure = gtk_clapper_gl_widget_measure;
widget_class->size_allocate = gtk_clapper_gl_widget_size_allocate;
g_object_class_install_property (gobject_klass, PROP_PIXEL_ASPECT_RATIO,
gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio",
"The pixel aspect ratio of the device", DEFAULT_PAR_N, DEFAULT_PAR_D,
G_MAXINT, 1, 1, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gl_area_class->render = gtk_clapper_gl_widget_render;
widget_klass->measure = gtk_clapper_gl_widget_measure;
widget_klass->size_allocate = gtk_clapper_gl_widget_size_allocate;
gl_area_klass->render = gtk_clapper_gl_widget_render;
}
static void
@@ -930,7 +945,6 @@ gtk_clapper_gl_widget_init (GtkClapperGLWidget * clapper_widget)
clapper_widget->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
clapper_widget->par_n = DEFAULT_PAR_N;
clapper_widget->par_d = DEFAULT_PAR_D;
clapper_widget->keep_last_frame = DEFAULT_KEEP_LAST_FRAME;
clapper_widget->ignore_buffers = FALSE;
clapper_widget->last_pos_x = 0;
clapper_widget->last_pos_y = 0;
@@ -979,7 +993,7 @@ gtk_clapper_gl_widget_init (GtkClapperGLWidget * clapper_widget)
#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11)
if (GDK_IS_X11_DISPLAY (display)) {
gpointer display_ptr;
#if GST_GL_HAVE_PLATFORM_EGL && GTK_CHECK_VERSION(4,3,1)
#if GST_GL_HAVE_PLATFORM_EGL && GTK_CHECK_VERSION(4,4,0)
display_ptr = gdk_x11_display_get_egl_display (display);
if (display_ptr)
priv->display = (GstGLDisplay *)

View File

@@ -52,7 +52,6 @@ struct _GtkClapperGLWidget
/* properties */
gboolean force_aspect_ratio;
gint par_n, par_d;
gboolean keep_last_frame;
gint display_width;
gint display_height;

View File

@@ -8,6 +8,8 @@ gstclapper_sources = [
'gstclapper-g-main-context-signal-dispatcher.c',
'gstclapper-video-overlay-video-renderer.c',
'gstclapper-visualization.c',
'gstclapper-playlist.c',
'gstclapper-playlist-item.c',
'gstclapper-mpris.c',
'gstclapper-gtk4-plugin.c',
@@ -26,6 +28,8 @@ gstclapper_headers = [
'gstclapper-g-main-context-signal-dispatcher.h',
'gstclapper-video-overlay-video-renderer.h',
'gstclapper-visualization.h',
'gstclapper-playlist.h',
'gstclapper-playlist-item.h',
'gstclapper-mpris.h',
'gstclapper-gtk4-plugin.h',
]

View File

@@ -1,5 +1,5 @@
project('com.github.rafostar.Clapper', 'c', 'cpp',
version: '0.3.0',
version: '0.2.1',
meson_version: '>= 0.50.0',
license: 'GPL3',
default_options: [

View File

@@ -2,7 +2,7 @@ Format: 3.0 (quilt)
Source: clapper
Binary: clapper
Architecture: any
Version: 0.3.0
Version: 0.2.1
Maintainer: Rafostar <rafostar.github@gmail.com>
Build-Depends: debhelper (>= 10),
meson (>= 0.50),

View File

@@ -1,5 +1,5 @@
clapper (0.3.0) unstable; urgency=low
clapper (0.2.1) unstable; urgency=low
* New version
-- Rafostar <rafostar.github@gmail.com> Fri, 18 Jun 2021 09:39:00 +0100
-- Rafostar <rafostar.github@gmail.com> Mon, 19 Apr 2021 09:39:00 +0100

View File

@@ -26,7 +26,7 @@
%global glib2_version 2.56.0
Name: clapper
Version: 0.3.0
Version: 0.2.1
Release: 1%{?dist}
Summary: Simple and modern GNOME media player
@@ -126,9 +126,6 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/*.desktop
%{_libdir}/%{appname}/
%changelog
* Fri Jun 18 2021 Rafostar <rafostar.github@gmail.com> - 0.3.0-1
- New version
* Mon Apr 19 2021 Rafostar <rafostar.github@gmail.com> - 0.2.1-1
- New version

View File

@@ -81,8 +81,7 @@ class ClapperPlayer extends GstClapper.Clapper
this._onSettingsKeyChanged(settings, key);
const flag = Gio.SettingsBindFlags.GET;
settings.bind('keep-last-frame', this.widget, 'keep-last-frame', flag);
settings.bind('subtitle-font', this.pipeline, 'subtitle-font-desc', flag);
settings.bind('subtitle-font', this.pipeline, 'subtitle_font_desc', flag);
}
set_initial_config()

View File

@@ -41,7 +41,6 @@ class ClapperGeneralPage extends PrefsBase.Grid
comboBox.connect('changed', this._onVolumeInitialChanged.bind(this, spinButton));
this.addTitle('Finish');
this.addCheckButton('Keep showing last frame', 'keep-last-frame');
this.addCheckButton('Close after playback', 'close-auto');
}

View File

@@ -38,7 +38,7 @@ var YouTubeClient = GObject.registerClass({
this.lastInfo = null;
this.postInfo = {
clientVersion: "2.20210605.09.00",
clientVersion: null,
visitorData: "",
};