mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Fix: Migrations
This commit is contained in:
parent
471fb6723e
commit
be152c1531
41 changed files with 2373 additions and 1321 deletions
|
|
@ -0,0 +1 @@
|
|||
Versions/Current/MediaRemoteAdapter
|
||||
1
mediaremote-adapter/MediaRemoteAdapter.framework/Resources
Symbolic link
1
mediaremote-adapter/MediaRemoteAdapter.framework/Resources
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
Versions/Current/Resources
|
||||
BIN
mediaremote-adapter/MediaRemoteAdapter.framework/Versions/A/MediaRemoteAdapter
Executable file
BIN
mediaremote-adapter/MediaRemoteAdapter.framework/Versions/A/MediaRemoteAdapter
Executable file
Binary file not shown.
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>MediaRemoteAdapter</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.vandenbe.MediaRemoteAdapter</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>MediaRemoteAdapter</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.1.0</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.1</string>
|
||||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>files</key>
|
||||
<dict>
|
||||
<key>Resources/Info.plist</key>
|
||||
<data>
|
||||
M6AF1VWVJ1A/DSliCSjg170FqsY=
|
||||
</data>
|
||||
</dict>
|
||||
<key>files2</key>
|
||||
<dict>
|
||||
<key>Resources/Info.plist</key>
|
||||
<dict>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
z3yWmTAqjdrPJEZUQ+t6AVPhw0e/I8PAiVr0HIU2ivg=
|
||||
</data>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>rules</key>
|
||||
<dict>
|
||||
<key>^Resources/</key>
|
||||
<true/>
|
||||
<key>^Resources/.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Resources/Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^version.plist$</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>rules2</key>
|
||||
<dict>
|
||||
<key>.*\.dSYM($|/)</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>11</real>
|
||||
</dict>
|
||||
<key>^(.*/)?\.DS_Store$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>2000</real>
|
||||
</dict>
|
||||
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
|
||||
<dict>
|
||||
<key>nested</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>10</real>
|
||||
</dict>
|
||||
<key>^.*</key>
|
||||
<true/>
|
||||
<key>^Info\.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^PkgInfo$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^Resources/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Resources/Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^[^/]+$</key>
|
||||
<dict>
|
||||
<key>nested</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>10</real>
|
||||
</dict>
|
||||
<key>^embedded\.provisionprofile$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^version\.plist$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1 @@
|
|||
A
|
||||
BIN
mediaremote-adapter/NowPlayingTestClient
Executable file
BIN
mediaremote-adapter/NowPlayingTestClient
Executable file
Binary file not shown.
257
mediaremote-adapter/mediaremote-adapter.pl
Executable file
257
mediaremote-adapter/mediaremote-adapter.pl
Executable file
|
|
@ -0,0 +1,257 @@
|
|||
#!/usr/bin/perl
|
||||
# Copyright (c) 2025 Jonas van den Berg
|
||||
# This file is licensed under the BSD 3-Clause License.
|
||||
|
||||
# For usage information read below or run the script without arguments.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use DynaLoader;
|
||||
use File::Spec;
|
||||
use File::Basename;
|
||||
|
||||
sub print_help() {
|
||||
print <<'HELP';
|
||||
Usage:
|
||||
mediaremote-adapter.pl FRAMEWORK_PATH [NOWPLAYING_CLIENT_PATH] [FUNCTION [PARAMS|OPTIONS...]]
|
||||
|
||||
FRAMEWORK_PATH:
|
||||
Absolute path to MediaRemoteAdapter.framework
|
||||
|
||||
NOWPLAYING_CLIENT_PATH (optional):
|
||||
Path to the NowPlayingTestClient executable (used for test mode)
|
||||
|
||||
FUNCTION:
|
||||
stream Streams now playing information (as diff by default)
|
||||
get Prints now playing information once with all available metadata
|
||||
send Sends a command to the now playing application
|
||||
seek Seeks to a specific timeline position
|
||||
shuffle Sets the shuffle mode
|
||||
repeat Sets the repeat mode
|
||||
speed Sets the playback speed
|
||||
|
||||
PARAMS:
|
||||
send(command)
|
||||
command: The MRCommand ID as a number (e.g. kMRPlay = 0)
|
||||
seek(position)
|
||||
position: The timeline position in microseconds
|
||||
shuffle(mode)
|
||||
mode: The shuffle mode
|
||||
repeat(mode)
|
||||
mode: The repeat mode
|
||||
speed(speed)
|
||||
speed: The playback speed
|
||||
|
||||
OPTIONS:
|
||||
get
|
||||
--now: Sets "elapsedTime" to the current elapsed time. By default,
|
||||
this value is the elapsed time at the time of the given "timestamp"
|
||||
stream
|
||||
--no-diff: Disable diffing and always dump all metadata
|
||||
--debounce=N: Delay in milliseconds to prevent spam (0 by default)
|
||||
get, stream
|
||||
--micros: Replaces the following time keys with microsecond equivalents
|
||||
"duration" -> "durationMicros"
|
||||
"elapsedTime" -> "elapsedTimeMicros"
|
||||
"timestamp" -> "timestampEpochMicros" (converted to epoch time)
|
||||
--human-readable, -h: Makes values human-readable. Use only for debugging.
|
||||
The JSON output is pretty-printed and the following keys are adapted:
|
||||
"artworkData" -> Binary data is truncated to a shorter representation
|
||||
|
||||
Examples (script name and framework path omitted):
|
||||
stream --no-diff --debounce=100
|
||||
send 2 # Toggles play/pause in the media player (kMRATogglePlayPause)
|
||||
repeat 3 # Sets the repeat mode to "playlist" (kMRARepeatModePlaylist)
|
||||
|
||||
HELP
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if (!defined $ARGV[1]) {
|
||||
print_help();
|
||||
}
|
||||
|
||||
sub fail {
|
||||
my ($error) = @_;
|
||||
print STDERR "$error\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
fail "Framework path not provided" unless @ARGV >= 1;
|
||||
|
||||
my $framework_path = shift @ARGV;
|
||||
|
||||
# Optionally accept NOWPLAYING_CLIENT path as second argument
|
||||
my $maybe_helper_path = $ARGV[0] // '';
|
||||
if ($maybe_helper_path =~ m{NowPlayingTestClient} || $maybe_helper_path =~ m{/}) {
|
||||
my $helper_path = shift @ARGV;
|
||||
$ENV{NOWPLAYING_CLIENT} = $helper_path;
|
||||
}
|
||||
|
||||
my $framework_basename = File::Basename::basename($framework_path);
|
||||
fail "Provided path is not a framework: $framework_path"
|
||||
unless $framework_basename =~ s/\.framework$//;
|
||||
|
||||
my $framework = File::Spec->catfile($framework_path, $framework_basename);
|
||||
fail "Framework not found at $framework" unless -e $framework;
|
||||
|
||||
my $handle = DynaLoader::dl_load_file($framework, 0)
|
||||
or fail "Failed to load framework: $framework";
|
||||
my $function_name = shift @ARGV or fail "Missing function name";
|
||||
fail "Invalid function name: '$function_name'"
|
||||
unless $function_name eq "stream"
|
||||
|| $function_name eq "get"
|
||||
|| $function_name eq "send"
|
||||
|| $function_name eq "seek"
|
||||
|| $function_name eq "shuffle"
|
||||
|| $function_name eq "repeat"
|
||||
|| $function_name eq "speed"
|
||||
|| $function_name eq "test";
|
||||
|
||||
sub parse_options {
|
||||
my ($start_index) = @_;
|
||||
my %arg_map;
|
||||
my $i = $start_index;
|
||||
while ($i <= $#ARGV) {
|
||||
my $arg = $ARGV[$i];
|
||||
if ($arg =~ /^--([a-z\\-]+)(?:=(.*))?$/) {
|
||||
my $key = $1;
|
||||
my $value = defined $2 ? $2 : undef;
|
||||
$arg_map{$key} = $value;
|
||||
splice @ARGV, $i, 1;
|
||||
}
|
||||
elsif ($arg =~ /^-([a-zA-Z]+)$/) {
|
||||
my @flags = split //, $1;
|
||||
$arg_map{$_} = undef for @flags;
|
||||
splice @ARGV, $i, 1;
|
||||
}
|
||||
else {
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
return \%arg_map;
|
||||
}
|
||||
|
||||
sub env_func {
|
||||
my $symbol_name = shift;
|
||||
return "${symbol_name}_env";
|
||||
}
|
||||
|
||||
sub set_env_param {
|
||||
my ($func, $index, $name, $value) = @_;
|
||||
$ENV{"MEDIAREMOTEADAPTER_PARAM_${func}_${index}_${name}"} = "$value";
|
||||
}
|
||||
|
||||
sub set_env_option_unsafe {
|
||||
my ($name, $value) = @_;
|
||||
$name =~ s/-/_/g;
|
||||
$ENV{"MEDIAREMOTEADAPTER_OPTION_${name}"} = defined $value ? "$value" : "";
|
||||
}
|
||||
|
||||
sub set_env_option {
|
||||
my ($options, $key) = @_;
|
||||
my $value = $options->{$key};
|
||||
if (defined $value) {
|
||||
fail "Unexpected value for option '$key'";
|
||||
}
|
||||
set_env_option_unsafe($key, $value);
|
||||
}
|
||||
|
||||
sub set_env_option_value {
|
||||
my ($options, $key) = @_;
|
||||
my $value = $options->{$key};
|
||||
if (!defined $value) {
|
||||
fail "Missing value for option '$key'";
|
||||
}
|
||||
set_env_option_unsafe($key, $value);
|
||||
}
|
||||
|
||||
my $symbol_name = "adapter_$function_name";
|
||||
if ($function_name eq "send") {
|
||||
my $id = shift @ARGV;
|
||||
fail "Missing ID for '$function_name' command" unless defined $id;
|
||||
set_env_param($symbol_name, 0, "command", "$id");
|
||||
$symbol_name = env_func($symbol_name);
|
||||
}
|
||||
elsif ($function_name eq "stream") {
|
||||
my $options = parse_options(0);
|
||||
foreach my $key (keys %{$options}) {
|
||||
if ($key eq "no-diff") {
|
||||
set_env_option($options, $key);
|
||||
}
|
||||
elsif ($key eq "debounce") {
|
||||
set_env_option_value($options, $key);
|
||||
}
|
||||
elsif ($key eq "micros") {
|
||||
set_env_option($options, $key);
|
||||
}
|
||||
elsif ($key eq "human-readable" || $key eq "h") {
|
||||
set_env_option($options, "human-readable");
|
||||
}
|
||||
else {
|
||||
fail "Unrecognized option '$key'";
|
||||
}
|
||||
}
|
||||
$symbol_name = env_func($symbol_name);
|
||||
}
|
||||
elsif ($function_name eq "get") {
|
||||
my $options = parse_options(0);
|
||||
foreach my $key (keys %{$options}) {
|
||||
if ($key eq "micros") {
|
||||
set_env_option($options, $key);
|
||||
}
|
||||
elsif ($key eq "human-readable" || $key eq "h") {
|
||||
set_env_option($options, "human-readable");
|
||||
}
|
||||
elsif ($key eq "now") {
|
||||
set_env_option($options, $key);
|
||||
}
|
||||
else {
|
||||
fail "Unrecognized option '$key'";
|
||||
}
|
||||
}
|
||||
$symbol_name = env_func($symbol_name);
|
||||
}
|
||||
elsif ($function_name eq "seek") {
|
||||
my $position = shift @ARGV;
|
||||
fail "Missing position for '$function_name' command" unless defined $position;
|
||||
set_env_param($symbol_name, 0, "position", "$position");
|
||||
$symbol_name = env_func($symbol_name);
|
||||
}
|
||||
elsif ($function_name eq "shuffle") {
|
||||
my $mode = shift @ARGV;
|
||||
fail "Missing mode for '$function_name' command" unless defined $mode;
|
||||
set_env_param($symbol_name, 0, "mode", "$mode");
|
||||
$symbol_name = env_func($symbol_name);
|
||||
}
|
||||
elsif ($function_name eq "repeat") {
|
||||
my $mode = shift @ARGV;
|
||||
fail "Missing mode for '$function_name' command" unless defined $mode;
|
||||
set_env_param($symbol_name, 0, "mode", "$mode");
|
||||
$symbol_name = env_func($symbol_name);
|
||||
}
|
||||
elsif ($function_name eq "speed") {
|
||||
my $speed = shift @ARGV;
|
||||
fail "Missing speed for '$function_name' command" unless defined $speed;
|
||||
set_env_param($symbol_name, 0, "speed", "$speed");
|
||||
$symbol_name = env_func($symbol_name);
|
||||
}
|
||||
elsif ($function_name eq "test") {
|
||||
$symbol_name = "_adapter_is_it_broken_yet";
|
||||
}
|
||||
|
||||
if (defined shift @ARGV) {
|
||||
fail "Too many arguments";
|
||||
}
|
||||
|
||||
my $symbol = DynaLoader::dl_find_symbol($handle, "$symbol_name")
|
||||
or fail "Symbol '$symbol_name' not found in $framework";
|
||||
DynaLoader::dl_install_xsub("main::$function_name", $symbol);
|
||||
|
||||
eval {
|
||||
no strict "refs";
|
||||
&{"main::$function_name"}();
|
||||
};
|
||||
if ($@) {
|
||||
fail "Error executing $function_name: $@";
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue