mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-29 23:32:04 +02:00
2
.github/workflows/flatpak.yml
vendored
2
.github/workflows/flatpak.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
name: "Flatpak"
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: bilelmoussaoui/flatpak-github-actions:gnome-40
|
||||
image: bilelmoussaoui/flatpak-github-actions:gnome-41
|
||||
options: --privileged
|
||||
strategy:
|
||||
matrix:
|
||||
|
@@ -6,4 +6,4 @@ imports.package.init({
|
||||
prefix: '@prefix@',
|
||||
libdir: '@libdir@',
|
||||
});
|
||||
imports.package.run(imports.src.main@ID_POSTFIX@);
|
||||
imports.package.run(imports.src.main);
|
||||
|
@@ -1,25 +1,19 @@
|
||||
clapper_apps = ['', 'Remote', 'Daemon']
|
||||
bin_conf = configuration_data()
|
||||
|
||||
foreach id_postfix : clapper_apps
|
||||
app_postfix = (id_postfix != '') ? '.' + id_postfix : ''
|
||||
bin_conf.set('GJS', find_program('gjs').path())
|
||||
bin_conf.set('PACKAGE_NAME', meson.project_name())
|
||||
bin_conf.set('PACKAGE_VERSION', meson.project_version())
|
||||
bin_conf.set('prefix', get_option('prefix'))
|
||||
bin_conf.set('libdir', libdir)
|
||||
|
||||
bin_conf = configuration_data()
|
||||
bin_conf.set('GJS', find_program('gjs').path())
|
||||
bin_conf.set('PACKAGE_NAME', meson.project_name())
|
||||
bin_conf.set('PACKAGE_VERSION', meson.project_version())
|
||||
bin_conf.set('ID_POSTFIX', id_postfix)
|
||||
bin_conf.set('prefix', get_option('prefix'))
|
||||
bin_conf.set('libdir', libdir)
|
||||
|
||||
configure_file(
|
||||
input: 'com.github.rafostar.Clapper.in',
|
||||
output: 'com.github.rafostar.Clapper' + app_postfix,
|
||||
configuration: bin_conf,
|
||||
install: true,
|
||||
install_dir: bindir,
|
||||
install_mode: 'rwxr-xr-x'
|
||||
)
|
||||
endforeach
|
||||
configure_file(
|
||||
input: 'com.github.rafostar.Clapper.in',
|
||||
output: 'com.github.rafostar.Clapper',
|
||||
configuration: bin_conf,
|
||||
install: true,
|
||||
install_dir: bindir,
|
||||
install_mode: 'rwxr-xr-x'
|
||||
)
|
||||
|
||||
clapper_symlink_cmd = 'ln -fs @0@ $DESTDIR@1@'.format(
|
||||
'com.github.rafostar.Clapper',
|
||||
|
@@ -32,6 +32,7 @@
|
||||
"flathub/lib/libdvdnav.json",
|
||||
"flathub/lib/libass.json",
|
||||
"flathub/lib/ffmpeg.json",
|
||||
"testing/libsoup3.json",
|
||||
"testing/gstreamer.json",
|
||||
"testing/gtuber.json",
|
||||
{
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"app-id": "com.github.rafostar.Clapper",
|
||||
"runtime": "org.gnome.Platform",
|
||||
"runtime-version": "40",
|
||||
"runtime-version": "41",
|
||||
"sdk": "org.gnome.Sdk",
|
||||
"command": "com.github.rafostar.Clapper",
|
||||
"finish-args": [
|
||||
@@ -33,6 +33,7 @@
|
||||
"flathub/lib/libass.json",
|
||||
"flathub/lib/ffmpeg.json",
|
||||
"flathub/lib/uchardet.json",
|
||||
"testing/libsoup3.json",
|
||||
"flathub/gstreamer-1.0/gstreamer.json",
|
||||
"flathub/lib/gtk4.json",
|
||||
"flathub/lib/libadwaita.json",
|
||||
|
24
pkgs/flatpak/testing/libsoup3.json
Normal file
24
pkgs/flatpak/testing/libsoup3.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "libsoup3",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": [
|
||||
"-Dintrospection=enabled",
|
||||
"-Dvapi=disabled",
|
||||
"-Dtests=false",
|
||||
"-Dsysprof=disabled",
|
||||
"-Dhttp2_tests=disabled",
|
||||
"-Dpkcs11_tests=disabled"
|
||||
],
|
||||
"cleanup": [
|
||||
"/include",
|
||||
"/lib/pkgconfig"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.gnome.org/GNOME/libsoup.git",
|
||||
"tag": "3.0.4",
|
||||
"commit": "25a728020c4b53b5db4c4c675070e92f947fbd4d"
|
||||
}
|
||||
]
|
||||
}
|
@@ -24,6 +24,7 @@
|
||||
%global gtk4_version 4.0.0
|
||||
%global meson_version 0.50
|
||||
%global glib2_version 2.56.0
|
||||
%global soup_version 3.0.0
|
||||
|
||||
Name: clapper
|
||||
Version: 0.4.1
|
||||
@@ -59,6 +60,7 @@ BuildRequires: gstreamer-plugins-base-devel >= %{gst_version}
|
||||
BuildRequires: Mesa-libGLESv2-devel
|
||||
BuildRequires: Mesa-libGLESv3-devel
|
||||
|
||||
Requires: libsoup-devel >= %{soup_version}
|
||||
Requires: gstreamer >= %{gst_version}
|
||||
Requires: gstreamer-plugins-base >= %{gst_version}
|
||||
Requires: gstreamer-plugins-good >= %{gst_version}
|
||||
@@ -80,6 +82,7 @@ BuildRequires: mesa-libGLES-devel
|
||||
BuildRequires: mesa-libGLU-devel
|
||||
BuildRequires: mesa-libEGL-devel
|
||||
|
||||
Requires: libsoup3-devel
|
||||
Requires: gstreamer1 >= %{gst_version}
|
||||
Requires: gstreamer1-plugins-base >= %{gst_version}
|
||||
Requires: gstreamer1-plugins-good >= %{gst_version}
|
||||
@@ -129,6 +132,9 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/*.desktop
|
||||
%{_libdir}/%{appname}/
|
||||
|
||||
%changelog
|
||||
* Thu Feb 17 2022 Rafostar <rafostar.github@gmail.com> - 0.4.1-2
|
||||
- Require libsoup3
|
||||
|
||||
* Mon Dec 20 2021 Rafostar <rafostar.github@gmail.com> - 0.4.1-1
|
||||
- New version
|
||||
|
||||
|
@@ -1,25 +0,0 @@
|
||||
const { GObject } = imports.gi;
|
||||
const { AppBase } = imports.src.appBase;
|
||||
const { HeaderBarRemote } = imports.src.headerbarRemote;
|
||||
const { WidgetRemote } = imports.src.widgetRemote;
|
||||
|
||||
var AppRemote = GObject.registerClass({
|
||||
GTypeName: 'ClapperAppRemote',
|
||||
},
|
||||
class ClapperAppRemote extends AppBase
|
||||
{
|
||||
vfunc_startup()
|
||||
{
|
||||
super.vfunc_startup();
|
||||
|
||||
const window = this.active_window;
|
||||
|
||||
const clapperWidget = new WidgetRemote();
|
||||
window.set_child(clapperWidget);
|
||||
|
||||
const headerBar = new HeaderBarRemote();
|
||||
window.set_titlebar(headerBar);
|
||||
|
||||
window.maximize();
|
||||
}
|
||||
});
|
@@ -1,70 +0,0 @@
|
||||
const { Gio, GLib, GObject } = imports.gi;
|
||||
const Debug = imports.src.debug;
|
||||
|
||||
const { debug } = Debug;
|
||||
|
||||
var Daemon = GObject.registerClass({
|
||||
GTypeName: 'ClapperDaemon',
|
||||
},
|
||||
class ClapperDaemon extends Gio.SubprocessLauncher
|
||||
{
|
||||
_init()
|
||||
{
|
||||
const port = ARGV[0] || 8080;
|
||||
|
||||
/* FIXME: show output when debugging is on */
|
||||
const flags = Gio.SubprocessFlags.STDOUT_SILENCE
|
||||
| Gio.SubprocessFlags.STDERR_SILENCE;
|
||||
|
||||
super._init({ flags });
|
||||
|
||||
this.errMsg = 'exited with error or was forced to close';
|
||||
this.loop = GLib.MainLoop.new(null, false);
|
||||
|
||||
this.broadwayd = this.spawnv(['gtk4-broadwayd', '--port=' + port]);
|
||||
this.broadwayd.wait_async(null, this._onBroadwaydClosed.bind(this));
|
||||
|
||||
this.setenv('GDK_BACKEND', 'broadway', true);
|
||||
|
||||
const remoteApp = this.spawnv(['com.github.rafostar.Clapper.Remote']);
|
||||
remoteApp.wait_async(null, this._onRemoteClosed.bind(this));
|
||||
|
||||
this.loop.run();
|
||||
}
|
||||
|
||||
_checkProcResult(proc, result)
|
||||
{
|
||||
let hadError = false;
|
||||
|
||||
try {
|
||||
hadError = proc.wait_finish(result);
|
||||
}
|
||||
catch(err) {
|
||||
debug(err);
|
||||
}
|
||||
|
||||
return hadError;
|
||||
}
|
||||
|
||||
_onBroadwaydClosed(proc, result)
|
||||
{
|
||||
const hadError = this._checkProcResult(proc, result);
|
||||
|
||||
if(hadError)
|
||||
debug(`broadwayd ${this.errMsg}`);
|
||||
|
||||
this.broadwayd = null;
|
||||
this.loop.quit();
|
||||
}
|
||||
|
||||
_onRemoteClosed(proc, result)
|
||||
{
|
||||
const hadError = this._checkProcResult(proc, result);
|
||||
|
||||
if(hadError)
|
||||
debug(`remote app ${this.errMsg}`);
|
||||
|
||||
if(this.broadwayd)
|
||||
this.broadwayd.force_exit();
|
||||
}
|
||||
});
|
@@ -1,22 +0,0 @@
|
||||
const { GObject } = imports.gi;
|
||||
const { HeaderBarBase } = imports.src.headerbarBase;
|
||||
|
||||
var HeaderBarRemote = GObject.registerClass({
|
||||
GTypeName: 'ClapperHeaderBarRemote',
|
||||
},
|
||||
class ClapperHeaderBarRemote extends HeaderBarBase
|
||||
{
|
||||
_init()
|
||||
{
|
||||
super._init();
|
||||
this.extraButtonsBox.visible = false;
|
||||
}
|
||||
|
||||
_onWindowButtonActivate(action)
|
||||
{
|
||||
if(action === 'toggle-maximized')
|
||||
action = 'toggle_maximized';
|
||||
|
||||
this.root.child.sendWs(action);
|
||||
}
|
||||
});
|
@@ -1,6 +1,6 @@
|
||||
imports.gi.versions.Gdk = '4.0';
|
||||
imports.gi.versions.Gtk = '4.0';
|
||||
imports.gi.versions.Soup = '2.4';
|
||||
imports.gi.versions.Soup = '3.0';
|
||||
|
||||
pkg.initGettext();
|
||||
pkg.initFormat();
|
||||
|
@@ -1,6 +0,0 @@
|
||||
const { Daemon } = imports.src.daemon;
|
||||
|
||||
function main()
|
||||
{
|
||||
new Daemon();
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
imports.gi.versions.Gdk = '4.0';
|
||||
imports.gi.versions.Gtk = '4.0';
|
||||
imports.gi.versions.Soup = '2.4';
|
||||
|
||||
pkg.initGettext();
|
||||
|
||||
const Misc = imports.src.misc;
|
||||
Misc.appId += '.Remote';
|
||||
|
||||
const { Gtk, Adw } = imports.gi;
|
||||
const { AppRemote } = imports.src.appRemote;
|
||||
|
||||
function main(argv)
|
||||
{
|
||||
Gtk.init();
|
||||
Adw.init();
|
||||
|
||||
new AppRemote().run(argv);
|
||||
}
|
@@ -3,7 +3,6 @@ const ByteArray = imports.byteArray;
|
||||
const Debug = imports.src.debug;
|
||||
const Misc = imports.src.misc;
|
||||
const { PlaylistWidget } = imports.src.playlist;
|
||||
const { WebApp } = imports.src.webApp;
|
||||
|
||||
const { debug, warn } = Debug;
|
||||
const { settings } = Misc;
|
||||
@@ -43,7 +42,6 @@ class ClapperPlayer extends GstClapper.Clapper
|
||||
this.visualization_enabled = false;
|
||||
|
||||
this.webserver = null;
|
||||
this.webapp = null;
|
||||
this.playlistWidget = new PlaylistWidget();
|
||||
|
||||
this.seekDone = true;
|
||||
@@ -675,7 +673,6 @@ class ClapperPlayer extends GstClapper.Clapper
|
||||
debug(`changed play flags: ${initialFlags} -> ${settingsFlags}`);
|
||||
break;
|
||||
case 'webserver-enabled':
|
||||
case 'webapp-enabled':
|
||||
const webserverEnabled = settings.get_boolean('webserver-enabled');
|
||||
|
||||
if(webserverEnabled) {
|
||||
@@ -690,22 +687,8 @@ class ClapperPlayer extends GstClapper.Clapper
|
||||
this.webserver.passMsgData = this.receiveWs.bind(this);
|
||||
}
|
||||
this.webserver.startListening();
|
||||
|
||||
const webappEnabled = settings.get_boolean('webapp-enabled');
|
||||
|
||||
if(!this.webapp && !webappEnabled)
|
||||
break;
|
||||
|
||||
if(webappEnabled) {
|
||||
if(!this.webapp)
|
||||
this.webapp = new WebApp();
|
||||
|
||||
this.webapp.startDaemonApp(settings.get_int('webapp-port'));
|
||||
}
|
||||
}
|
||||
else if(this.webserver) {
|
||||
/* remote app will close when connection is lost
|
||||
* which will cause the daemon to close too */
|
||||
this.webserver.stopListening();
|
||||
}
|
||||
break;
|
||||
|
@@ -1,51 +0,0 @@
|
||||
const { GObject } = imports.gi;
|
||||
const { WebClient } = imports.src.webClient;
|
||||
|
||||
var ClapperState = {
|
||||
STOPPED: 0,
|
||||
BUFFERING: 1,
|
||||
PAUSED: 2,
|
||||
PLAYING: 3,
|
||||
};
|
||||
|
||||
var PlayerRemote = GObject.registerClass({
|
||||
GTypeName: 'ClapperPlayerRemote',
|
||||
},
|
||||
class ClapperPlayerRemote extends GObject.Object
|
||||
{
|
||||
_init()
|
||||
{
|
||||
super._init();
|
||||
|
||||
this.webclient = new WebClient();
|
||||
}
|
||||
|
||||
set_playlist(playlist)
|
||||
{
|
||||
const uris = [];
|
||||
|
||||
/* We can not send GioFiles via WebSocket */
|
||||
for(let source of playlist)
|
||||
uris.push(this._getSourceUri(source));
|
||||
|
||||
this.webclient.sendMessage({
|
||||
action: 'set_playlist',
|
||||
value: uris
|
||||
});
|
||||
}
|
||||
|
||||
set_subtitles(source)
|
||||
{
|
||||
this.webclient.sendMessage({
|
||||
action: 'set_subtitles',
|
||||
value: this._getSourceUri(source)
|
||||
});
|
||||
}
|
||||
|
||||
_getSourceUri(source)
|
||||
{
|
||||
return (source.get_uri != null)
|
||||
? source.get_uri()
|
||||
: source;
|
||||
}
|
||||
});
|
@@ -1,51 +0,0 @@
|
||||
const { Gio, GObject } = imports.gi;
|
||||
const Debug = imports.src.debug;
|
||||
const Misc = imports.src.misc;
|
||||
|
||||
const { debug } = Debug;
|
||||
|
||||
var WebApp = GObject.registerClass({
|
||||
GTypeName: 'ClapperWebApp',
|
||||
},
|
||||
class ClapperWebApp extends Gio.SubprocessLauncher
|
||||
{
|
||||
_init()
|
||||
{
|
||||
const flags = Gio.SubprocessFlags.STDOUT_SILENCE
|
||||
| Gio.SubprocessFlags.STDERR_SILENCE;
|
||||
|
||||
super._init({ flags });
|
||||
|
||||
this.daemonApp = null;
|
||||
}
|
||||
|
||||
startDaemonApp(port)
|
||||
{
|
||||
if(this.daemonApp)
|
||||
return;
|
||||
|
||||
this.daemonApp = this.spawnv([Misc.appId + '.Daemon', String(port)]);
|
||||
this.daemonApp.wait_async(null, this._onDaemonClosed.bind(this));
|
||||
|
||||
debug('daemon app started');
|
||||
}
|
||||
|
||||
_onDaemonClosed(proc, result)
|
||||
{
|
||||
let hadError;
|
||||
|
||||
try {
|
||||
hadError = proc.wait_finish(result);
|
||||
}
|
||||
catch(err) {
|
||||
debug(err);
|
||||
}
|
||||
|
||||
this.daemonApp = null;
|
||||
|
||||
if(hadError)
|
||||
debug('daemon app exited with error or was forced to close');
|
||||
|
||||
debug('daemon app closed');
|
||||
}
|
||||
});
|
@@ -1,90 +0,0 @@
|
||||
const { Gio, GObject, Soup } = imports.gi;
|
||||
const Debug = imports.src.debug;
|
||||
const Misc = imports.src.misc;
|
||||
const WebHelpers = imports.src.webHelpers;
|
||||
|
||||
const { debug } = Debug;
|
||||
const { settings } = Misc;
|
||||
|
||||
var WebClient = GObject.registerClass({
|
||||
GTypeName: 'ClapperWebClient',
|
||||
},
|
||||
class ClapperWebClient extends Soup.Session
|
||||
{
|
||||
_init(port)
|
||||
{
|
||||
super._init({
|
||||
timeout: 3,
|
||||
use_thread_context: true,
|
||||
});
|
||||
|
||||
this.wsConn = null;
|
||||
|
||||
this.connectWebsocket();
|
||||
}
|
||||
|
||||
connectWebsocket()
|
||||
{
|
||||
if(this.wsConn)
|
||||
return;
|
||||
|
||||
const port = settings.get_int('webserver-port');
|
||||
const message = Soup.Message.new('GET', `ws://127.0.0.1:${port}/websocket`);
|
||||
this.websocket_connect_async(message, null, null, null, this._onWsConnect.bind(this));
|
||||
|
||||
debug('connecting WebSocket to Clapper app');
|
||||
}
|
||||
|
||||
sendMessage(data)
|
||||
{
|
||||
if(
|
||||
!this.wsConn
|
||||
|| this.wsConn.state !== Soup.WebsocketState.OPEN
|
||||
)
|
||||
return;
|
||||
|
||||
this.wsConn.send_text(JSON.stringify(data));
|
||||
}
|
||||
|
||||
passMsgData(action, value)
|
||||
{
|
||||
}
|
||||
|
||||
_onWsConnect(session, result)
|
||||
{
|
||||
let connection = null;
|
||||
|
||||
try {
|
||||
connection = this.websocket_connect_finish(result);
|
||||
}
|
||||
catch(err) {
|
||||
debug(err);
|
||||
}
|
||||
|
||||
if(!connection)
|
||||
return this.passMsgData('close');
|
||||
|
||||
connection.connect('message', this._onWsMessage.bind(this));
|
||||
connection.connect('closed', this._onWsClosed.bind(this));
|
||||
|
||||
this.wsConn = connection;
|
||||
|
||||
debug('successfully connected WebSocket');
|
||||
}
|
||||
|
||||
_onWsMessage(connection, dataType, bytes)
|
||||
{
|
||||
const [success, parsedMsg] = WebHelpers.parseData(dataType, bytes);
|
||||
|
||||
if(success)
|
||||
this.passMsgData(parsedMsg.action, parsedMsg.value);
|
||||
}
|
||||
|
||||
_onWsClosed(connection)
|
||||
{
|
||||
debug('closed WebSocket connection');
|
||||
this.wsConn = null;
|
||||
|
||||
this.passMsgData('close');
|
||||
}
|
||||
});
|
@@ -107,7 +107,7 @@ class ClapperWebServer extends Soup.Server
|
||||
this.remove_handler('/');
|
||||
}
|
||||
|
||||
_onWsConnection(server, connection)
|
||||
_onWsConnection(server, msg, path, connection)
|
||||
{
|
||||
debug('new WebSocket connection');
|
||||
|
||||
|
@@ -1,72 +0,0 @@
|
||||
const { GObject, Gtk } = imports.gi;
|
||||
const Buttons = imports.src.buttons;
|
||||
const Misc = imports.src.misc;
|
||||
const { PlayerRemote, ClapperState } = imports.src.playerRemote;
|
||||
|
||||
var WidgetRemote = GObject.registerClass({
|
||||
GTypeName: 'ClapperWidgetRemote',
|
||||
},
|
||||
class ClapperWidgetRemote extends Gtk.Grid
|
||||
{
|
||||
_init(opts)
|
||||
{
|
||||
super._init({
|
||||
halign: Gtk.Align.CENTER,
|
||||
valign: Gtk.Align.CENTER,
|
||||
});
|
||||
|
||||
Misc.loadCustomCss();
|
||||
|
||||
this.player = new PlayerRemote();
|
||||
this.player.webclient.passMsgData = this.receiveWs.bind(this);
|
||||
|
||||
/* FIXME: create better way to add buttons for
|
||||
* remote app without duplicating too much code */
|
||||
this.togglePlayButton = new Buttons.IconToggleButton(
|
||||
'media-playback-start-symbolic',
|
||||
'media-playback-pause-symbolic'
|
||||
);
|
||||
this.togglePlayButton.remove_css_class('flat');
|
||||
this.togglePlayButton.connect(
|
||||
'clicked', () => this.sendWs('toggle_play')
|
||||
);
|
||||
|
||||
this.attach(this.togglePlayButton, 0, 0, 1, 1);
|
||||
}
|
||||
|
||||
sendWs(action, value)
|
||||
{
|
||||
const data = { action };
|
||||
|
||||
/* do not send "null" or "undefined"
|
||||
* for faster network data transfer */
|
||||
if(value != null)
|
||||
data.value = value;
|
||||
|
||||
this.player.webclient.sendMessage(data);
|
||||
}
|
||||
|
||||
receiveWs(action, value)
|
||||
{
|
||||
switch(action) {
|
||||
case 'state_changed':
|
||||
switch(value) {
|
||||
case ClapperState.STOPPED:
|
||||
case ClapperState.PAUSED:
|
||||
this.togglePlayButton.setPrimaryIcon();
|
||||
break;
|
||||
case ClapperState.PLAYING:
|
||||
this.togglePlayButton.setSecondaryIcon();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'close':
|
||||
this.root.run_dispose();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
@@ -177,20 +177,6 @@
|
||||
<property name="spin-adjustment">web_server_adjustment</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="ClapperPrefsSwitch">
|
||||
<property name="title" translatable="yes">Run web application in background</property>
|
||||
<property name="subtitle" translatable="yes">Requires GTK compiled with Broadway backend</property>
|
||||
<property name="schema-name">webapp-enabled</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="ClapperPrefsSpin">
|
||||
<property name="title" translatable="yes">Web application port</property>
|
||||
<property name="schema-name">webapp-port</property>
|
||||
<property name="spin-adjustment">web_app_adjustment</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
Reference in New Issue
Block a user