Skip to content

Commit

Permalink
Add OSTemplate.
Browse files Browse the repository at this point in the history
  • Loading branch information
stuerp committed Jan 27, 2025
1 parent c17bc39 commit 65641c5
Showing 1 changed file with 390 additions and 0 deletions.
390 changes: 390 additions & 0 deletions OSTemplate.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,390 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
:root
{
color-scheme: light dark; /* Opt the entire page into the user's color scheme preferences */
}

html
{
margin: 0;
padding: 0;
}
body
{
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0 auto;
padding: 0;
font: 90% Calibri, Sans-serif;
line-height: 1.2;
color: #555753;
/* background-color: #e0e0e0; *//* Don't set a background color to use the theme background color of the foobar2000 panel */
}
div
{
display: none;
margin-top: 0;
text-align: center;
display: inline;
}
.track
{
font: 1.75em Cambria;
color: crimson;
}
.artist
{
font: 1.00em Cambria;
color: crimson;
}
.value
{
font-weight: 800;
}
</style>
</head>
<body>
<div id="Info">
<span id="Album"></span><br/>
<span id="AlbumArtist"></span><br/>
<span id="AlbumDate"></span><br/>
<span id="AlbumPublisher"></span><br/>
<span id="AlbumGenre"></span><br/>
<div>
<span id="TrackTitle" class="track"></span><br/>
<span class="artist">
<span id="TrackArtist"></span><span id="TrackCountry"></span>
<span id="TrackFeaturing"></span>
</span>
</div><br/>
<span id="TrackDate"></span><br/>
<span id="TrackNumber"></span><br/>
<span id="TrackGenre"></span><br/>
<span id="TrackLanguage"></span><br/>
<span id="TrackTime"></span><br/>
<span id="TrackCodec"></span><br/>
<span id="TrackInfo"></span><br/>
<br/>
<span id="TrackComposer"></span><br/>
<span id="TrackLyricist"></span><br/>
<span id="TrackComposed"></span><br/>
<span id="TrackConductor"></span><br/>
<span id="TrackOrchestra"></span><br/>
<span id="TrackArranger"></span><br/>
<span id="OriginalAlbum"></span><br/>
<span id="Medium"></span><br/>
<span id="Comment"></span><br/>
<span id="MIDI"></span><br/>
<div width="256px" height="256px" style="overflow: hidden;">
<img id="Artwork" style="max-width: 256px; height: auto; object-fit: cover;"/>
</div>
<p style="display: flow">
<strong>Events</strong><br/>
onStarting: <span id="Starting">?</span><br/>
onPaused: <span id="Paused">?</span><br/>
onStop: <span id="StopReason">?</span><br/>
onSeek: <span id="Time">?</span>s<br/>
onVolumeChange: <span id="Volume">?</span>dBFS<br/>
</p>
<p>
<strong>Properties</strong><br/>
foo_uie_webview <span id="VersionText"></span> (<span id="Version"></span>)<br/>
volume: <span id="Volume2">?</span>dBFS<br/>
isPlaying: <span id="IsPlaying">?</span><br/>
isPaused: <span id="IsPaused">?</span><br/>
stopAfterCurrent: <span id="StopAfterCurrent">?</span><br/>
length: <span id="Length">?</span><br/>
position: <span id="Position">?</span><br/>
canSeek: <span id="CanSeek">?</span><br/>
</p>
<p>
<div id="Controls">
<button id="Stop" onclick="chrome.webview.hostObjects.sync.foo_uie_webview.stop(); RefreshProperties();"></button>
<button id="Play" onclick="chrome.webview.hostObjects.sync.foo_uie_webview.play(false); RefreshProperties();"></button>
<button id="Pause" onclick="chrome.webview.hostObjects.sync.foo_uie_webview.togglePause(); RefreshProperties();"></button>
<button id="Prev" onclick="chrome.webview.hostObjects.sync.foo_uie_webview.previous(); RefreshProperties();"></button>
<button id="Next" onclick="chrome.webview.hostObjects.sync.foo_uie_webview.next(); RefreshProperties();"></button>
<button id="Random" onclick="chrome.webview.hostObjects.sync.foo_uie_webview.random(); RefreshProperties();"></button>
<button id="VolumeDown" onclick="chrome.webview.hostObjects.sync.foo_uie_webview.volumeDown(); RefreshProperties();"></button>
<button id="VolumeUp" onclick="chrome.webview.hostObjects.sync.foo_uie_webview.volumeUp(); RefreshProperties();"></button>
<button id="Mute" onclick="chrome.webview.hostObjects.sync.foo_uie_webview.toggleMute(); RefreshProperties();"></button>
<button id="Seek" onclick="chrome.webview.hostObjects.sync.foo_uie_webview.seek(Math.random() * chrome.webview.hostObjects.sync.foo_uie_webview.length); RefreshProperties();">Seek</button>
<button id="Delta" onclick="chrome.webview.hostObjects.sync.foo_uie_webview.seekDelta((Math.random() - 0.5) * 5.0); RefreshProperties();">Delta</button>
<br/>
<input type="checkbox" id="ToggleStopAfterCurrent" onclick="chrome.webview.hostObjects.sync.foo_uie_webview.toggleStopAfterCurrent(); RefreshProperties();"/><label for="ToggleStopAfterCurrent">Stop after current item</label>
</div>
</p>
<div>Timestamp: <span id="Timestamp"></span>, <span id="SampleCount"></span> samples, <span id="SampleRate"></span>Hz, <span id="ChannelCount"></span> channels (<span id="ChannelConfig"></span>)<br/>
<span id="Timer"></span><br/>
</div>
</div>
<script type="text/javascript">
var WebView;

window.onload = function()
{
window.chrome.webview.addEventListener("sharedbufferreceived", e =>
{
chrome.webview.hostObjects.sync.foo_uie_webview.print("foo_uie_webview JavaScript says hello.");

document.getElementById("VersionText").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.componentVersionText;

var Version = chrome.webview.hostObjects.sync.foo_uie_webview.componentVersion;

document.getElementById("Version").textContent = 'v' + ((Version >> 24) & 255) + '.' + ((Version >> 16) & 255) + '.' + ((Version >> 8) & 255) + '.' + (Version & 255);

document.getElementById("Volume2").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.volume;

// chrome.webview.hostObjects.sync.foo_uie_webview.volume = 0; // The volume can be set from code.

document.getElementById("Stop").textContent = '\u23F9';
document.getElementById("Play").textContent = '\u23F5';
document.getElementById("Pause").textContent = '\u23F8';
document.getElementById("Prev").textContent = '\u23EE';
document.getElementById("Next").textContent = '\u23ED';
document.getElementById("Random").textContent = '\u{1F500}';
document.getElementById("VolumeDown").textContent = '\u{1F509}';
document.getElementById("VolumeUp").textContent = '\u{1F50A}';
document.getElementById("Mute").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.isMuted ? '\u{1F508}' : '\u{1F507}';

document.getElementById("ToggleStopAfterCurrent").checked = chrome.webview.hostObjects.sync.foo_uie_webview.stopAfterCurrent;

OnSharedBufferReceived(e);
});

window.chrome.webview.addEventListener("playlistItemFocusChanged", e =>
{
alert("Focus changed");
});

Refresh();
}

let SharedBuffer;
let Samples;

// Called when playback is being initialized.
function onPlaybackStarting(command, paused)
{
document.getElementById("Info").style.display = 'inline';
document.getElementById("Starting").textContent = command + " (" + (paused ? "Paused" : "Playing") + ")";

RefreshProperties();
}

// Called when playback advances to a new track.
function onPlaybackNewTrack()
{
document.getElementById("Info").style.display = 'inline';

Refresh()

const TestDataURI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";

const DataURI = chrome.webview.hostObjects.sync.foo_uie_webview.getArtwork("front"); // "front", "back", "disc", "icon", "artist"

document.getElementById("Artwork").src = (DataURI.length != 0) ? DataURI : TestDataURI;
}

// Called when playback stops.
function onPlaybackStop(reason)
{
// document.getElementById("Info").style.display = 'none';
document.getElementById("StopReason").textContent = reason; // "User" / "EOF" / "Starting another" / "Shutting down"

RefreshProperties();
}

// Called when the user seeks to a specific time.
function onPlaybackSeek(time)
{
document.getElementById("Time").textContent = time; // in seconds
}

// Called when playback pauses or resumes.
function onPlaybackPause(paused)
{
document.getElementById("Paused").textContent = paused; // true / false

RefreshProperties();
}

// Called when the currently played file gets edited.
function onPlaybackEdited()
{
Refresh();
}

// Called when dynamic info (VBR bitrate etc...) changes.
function onPlaybackDynamicInfo()
{
Refresh();
}

// Called when the per-track dynamic info (stream track titles etc...) change. Happens less often than OnPlaybackDynamicInfo().
function onPlaybackDynamicTrackInfo()
{
Refresh();
}

// Called, every second, for time display.
function onPlaybackTime(time)
{
document.getElementById("Time").textContent = time; // in seconds
document.getElementById("TrackTime").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("[%playback_time%[/%length%]]");
}

// Called when the user changes the volume.
function OnVolumeChange(newValue)
{
document.getElementById("Volume").textContent = newValue; // in dBFS
}

// Refreshes the content of all elements.
function Refresh()
{
document.getElementById("Album").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("[%album%[: %subtitle%]]");
document.getElementById("AlbumArtist").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("[%album artist%]");
document.getElementById("AlbumDate").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("[%album recorded%]['/'%album released%]");
document.getElementById("AlbumPublisher").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("[%publisher%[' ('%album country%')']]");
document.getElementById("AlbumGenre").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("[%album genre%]");

document.getElementById("TrackTitle").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("%title%[' ['%remix%']']");
document.getElementById("TrackArtist").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("[%artist%]");
document.getElementById("TrackCountry").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("[' ('%country%')']");
document.getElementById("TrackFeaturing").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("['ft. '%featuring%]");
document.getElementById("TrackDate").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("[%date%]");
document.getElementById("TrackNumber").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("[%tracknumber%[/%totaltracks%]]");
document.getElementById("TrackGenre").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("%genre%[/%subgenre%]");
document.getElementById("TrackLanguage").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("[ %language%]");

document.getElementById("TrackTime").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("[%playback_time%[/%length%]]");

document.getElementById("TrackCodec").textContent = chrome.webview.hostObjects.sync.getFormattedText("%codec_long%[, $info(codec_profile)], $caps($info(encoding))");
document.getElementById("TrackInfo").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("%samplerate%Hz, %bitrate% kbps[, $info(bitspersample) bit], $caps(%channels%)[, $caps($info(channel_mode))]");

document.getElementById("TrackComposer").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("['Composer: '%composer%]");
document.getElementById("TrackLyricist").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("['Lyricist: '%lyricist%]");
document.getElementById("TrackComposed").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("['Composed in: ' %composed%]");
document.getElementById("TrackConductor").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("['Conductor: '%conductor%]");
document.getElementById("TrackOrchestra").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("['Orchestra: '%orchestra%]");
document.getElementById("TrackArranger").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("['Arranger: ' %arranger%]");

document.getElementById("OriginalAlbum").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("['Original Album: '%original album%]");

document.getElementById("Medium").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("['Medium: '%medium%]");
document.getElementById("Comment").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("['Comments: '%comment%]");
document.getElementById("MIDI").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.getFormattedText("['MIDI: '$info(midi_player)][, $info(midi_active_voices) voices '(peak ' $info(midi_peak_voices)')'][, extra percussion channel $info(midi_extra_percussion_channel)]");

RefreshProperties();
}

// Refreshes the content of the property elements.
function RefreshProperties()
{
document.getElementById("IsPlaying").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.isPlaying ? 'True' : 'False';
document.getElementById("IsPaused").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.isPaused ? 'True' : 'False';
document.getElementById("StopAfterCurrent").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.stopAfterCurrent ? 'True' : 'False';

document.getElementById("Length").textContent = (Math.round(chrome.webview.hostObjects.sync.foo_uie_webview.length * 100) / 100).toFixed(2) + 's';
document.getElementById("CanSeek").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.canSeek ? 'True' : 'False';

document.getElementById("Mute").textContent = chrome.webview.hostObjects.sync.foo_uie_webview.isMuted ? '\u{1F508}' : '\u{1F507}';
}

// Called when the shared buffer does not exist yet or when the channel configuration changes.
function OnSharedBufferReceived(e)
{
if (SharedBuffer)
{
window.chrome.webview.releaseBuffer(SharedBuffer);
SharedBuffer = null;
Samples = null;
}

if (!e.additionalData)
return;

SharedBuffer = e.getBuffer(); // as an ArrayBuffer
Samples = new Float64Array(SharedBuffer);

document.getElementById("Timestamp").textContent = Date.now();
document.getElementById("SampleCount").textContent = e.additionalData.SampleCount;
document.getElementById("SampleRate").textContent = e.additionalData.SampleRate;
document.getElementById("ChannelCount").textContent = e.additionalData.ChannelCount;
document.getElementById("ChannelConfig").textContent = GetChannelConfigurationText(e.additionalData.ChannelConfig);
}

// Called when the visualisation timer ticks.
function OnTimer(sampleCount, sampleRate, channelCount, channelConfig)
{
document.getElementById("Position").textContent = (Math.round(chrome.webview.hostObjects.sync.foo_uie_webview.position * 100) / 100).toFixed(2) + 's';

var L = 0, R = 0;

if (Samples && Samples.length >= 2)
{
for (i = 0; i < sampleCount; i += channelCount)
{
if ((channelConfig & 3) == 3) // Front Left + Front Right
{
L = Math.max(L, Samples[i]);
R = Math.max(R, Samples[i + 1]);
}
else
if ((channelConfig & 4) == 4) // Front Center (Mono)
{
L = R = Math.max(L, Samples[i]);
}
}
}
else
document.getElementById("Timer").textContent = "N/A";

const NormalizeValue = (value) =>
{
const dB = 20 * Math.log10(value);

return Math.min(Math.max((dB + 60) / 60, 0.0), 1.0);
};

L = NormalizeValue(L);
R = NormalizeValue(R);

document.getElementById("Timer").textContent = Date.now() + ": " + sampleCount + " samples, " + sampleRate + "Hz, " + channelCount + " channels (0x" + ("00000000" + channelConfig.toString(16)).toUpperCase().slice(-8) + "), Left: " + L.toFixed(2) + "%, Right: " + R.toFixed(2) + "%";
}

// Converts the channel configuration mask to text.
function GetChannelConfigurationText(channelConfig)
{
var ChannelNames =
[
"FL", "FR", "FC",
"LFE",
"BL", "BR",
"FCL", "FCR",
"BC", "SL", "SR", "TC",
"TFL", "TFC", "TFR", "TBL", "TBC", "TBR",
];

return ChannelNames.filter
(
function(x)
{
var b = (channelConfig & 1);

channelConfig >>= 1;

return b;
}
).join(" / ");
}
</script>
</body>
</html>

0 comments on commit 65641c5

Please sign in to comment.