mirror of
https://gitlab.com/freepascal.org/fpc/pas2js.git
synced 2025-04-07 15:47:45 +02:00
* Player demo
This commit is contained in:
parent
e4b569110d
commit
49b0ae4bec
BIN
demo/player/headset.jpeg
Normal file
BIN
demo/player/headset.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
54
demo/player/index.html
Normal file
54
demo/player/index.html
Normal file
@ -0,0 +1,54 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Media player demo</title>
|
||||
<link rel="stylesheet" href = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<script src="tracks.js"></script>
|
||||
<script src="main.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="player">
|
||||
|
||||
<div class="details">
|
||||
<div class="display-text"></div>
|
||||
<div class="now-playing">PLAYING x OF y</div>
|
||||
<div class="track-art"></div>
|
||||
<div class="track-name">Track Name</div>
|
||||
<div class="track-artist">Track Artist</div>
|
||||
</div>
|
||||
|
||||
<div class="buttons">
|
||||
<div class="prev-track" >
|
||||
<i class="fa fa-step-backward fa-2x"></i>
|
||||
</div>
|
||||
<div class="playpause-track">
|
||||
<i class="fa fa-play-circle fa-5x"></i>
|
||||
</div>
|
||||
<div class="next-track" >
|
||||
<i class="fa fa-step-forward fa-2x"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="slider_container">
|
||||
<div class="current-time">00:00</div>
|
||||
<input type="range" min="1" max="100"
|
||||
value="0" class="seek_slider" >
|
||||
<div class="total-duration">00:00</div>
|
||||
</div>
|
||||
|
||||
<div class="slider_container">
|
||||
<i class="fa fa-volume-down"></i>
|
||||
<input type="range" min="1" max="100"
|
||||
value="99" class="volume_slider">
|
||||
<i class="fa fa-volume-up"></i>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<a href="main.pas">Program sources</a> <a
|
||||
href="https://www.bensound.com/royalty-free-music/">Royalty-free music from Bensound</a>
|
||||
<script>
|
||||
window.addEventListener("load",rtl.run)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
81
demo/player/main.lpi
Normal file
81
demo/player/main.lpi
Normal file
@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CONFIG>
|
||||
<ProjectOptions>
|
||||
<Version Value="12"/>
|
||||
<General>
|
||||
<Flags>
|
||||
<MainUnitHasCreateFormStatements Value="False"/>
|
||||
<MainUnitHasTitleStatement Value="False"/>
|
||||
<MainUnitHasScaledStatement Value="False"/>
|
||||
<Runnable Value="False"/>
|
||||
</Flags>
|
||||
<SessionStorage Value="InProjectDir"/>
|
||||
<Title Value="main"/>
|
||||
<UseAppBundle Value="False"/>
|
||||
<ResourceType Value="res"/>
|
||||
</General>
|
||||
<CustomData Count="2">
|
||||
<Item0 Name="PasJSPort" Value="0"/>
|
||||
<Item1 Name="PasJSWebBrowserProject" Value="1"/>
|
||||
</CustomData>
|
||||
<BuildModes>
|
||||
<Item Name="Default" Default="True"/>
|
||||
</BuildModes>
|
||||
<PublishOptions>
|
||||
<Version Value="2"/>
|
||||
<UseFileFilters Value="True"/>
|
||||
</PublishOptions>
|
||||
<RunParams>
|
||||
<FormatVersion Value="2"/>
|
||||
</RunParams>
|
||||
<Units>
|
||||
<Unit>
|
||||
<Filename Value="main.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
<Version Value="11"/>
|
||||
<Target FileExt=".js">
|
||||
<Filename Value="main"/>
|
||||
</Target>
|
||||
<SearchPaths>
|
||||
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||
<UnitOutputDirectory Value="js"/>
|
||||
</SearchPaths>
|
||||
<Parsing>
|
||||
<SyntaxOptions>
|
||||
<AllowLabel Value="False"/>
|
||||
<CPPInline Value="False"/>
|
||||
<UseAnsiStrings Value="False"/>
|
||||
</SyntaxOptions>
|
||||
</Parsing>
|
||||
<CodeGeneration>
|
||||
<TargetOS Value="browser"/>
|
||||
</CodeGeneration>
|
||||
<Linking>
|
||||
<Debugging>
|
||||
<GenerateDebugInfo Value="False"/>
|
||||
<UseLineInfoUnit Value="False"/>
|
||||
</Debugging>
|
||||
</Linking>
|
||||
<Other>
|
||||
<CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc -Jminclude"/>
|
||||
<CompilerPath Value="$(pas2js)"/>
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
<Debugging>
|
||||
<Exceptions>
|
||||
<Item>
|
||||
<Name Value="EAbort"/>
|
||||
</Item>
|
||||
<Item>
|
||||
<Name Value="ECodetoolError"/>
|
||||
</Item>
|
||||
<Item>
|
||||
<Name Value="EFOpenError"/>
|
||||
</Item>
|
||||
</Exceptions>
|
||||
</Debugging>
|
||||
</CONFIG>
|
229
demo/player/main.pas
Normal file
229
demo/player/main.pas
Normal file
@ -0,0 +1,229 @@
|
||||
program main;
|
||||
|
||||
{$mode objfpc}
|
||||
|
||||
uses
|
||||
browserapp, JS, Classes, SysUtils, Web;
|
||||
|
||||
type
|
||||
TTrack = Record
|
||||
name,
|
||||
artist,
|
||||
image,
|
||||
path,
|
||||
display,
|
||||
url : String;
|
||||
end;
|
||||
|
||||
TMyApplication = class(TBrowserApplication)
|
||||
now_playing,
|
||||
track_art,
|
||||
track_name,
|
||||
track_artist,
|
||||
display_text,
|
||||
playpause_btn,
|
||||
next_btn,
|
||||
prev_btn,
|
||||
curr_time,
|
||||
total_duration : TJSHTMLElement;
|
||||
curr_track : TJSHTMLAudioElement;
|
||||
volume_slider,
|
||||
seek_slider : TJSHTMLinputElement;
|
||||
isPlaying : Boolean;
|
||||
track_index : Integer;
|
||||
updateTimer: Integer;
|
||||
Procedure BindElements;
|
||||
Procedure seekTo(Event: TJSEvent);
|
||||
Procedure SetVolume(Event: TJSEvent);
|
||||
Procedure DoPlayPause(Event: TJSEvent);
|
||||
Procedure NextTrack(Event: TJSEvent);
|
||||
Procedure PrevTrack(Event: TJSEvent);
|
||||
Procedure PlayTrack;
|
||||
Procedure PauseTrack;
|
||||
procedure LoadTrack(aIndex : Integer);
|
||||
procedure random_bg_color;
|
||||
procedure resetValues;
|
||||
procedure seekUpdate;
|
||||
procedure doRun; override;
|
||||
private
|
||||
end;
|
||||
|
||||
var
|
||||
track_list : Array of TTrack; external name 'track_list';
|
||||
|
||||
|
||||
procedure TMyApplication.seekUpdate;
|
||||
|
||||
Var
|
||||
seekPosition : Double;
|
||||
currentMinutes,
|
||||
currentSeconds,
|
||||
durationMinutes,
|
||||
durationSeconds : Integer;
|
||||
|
||||
begin
|
||||
if jsIsNan(curr_track.duration) then exit;
|
||||
seekPosition:=curr_track.currentTime * (100 / curr_track.duration);
|
||||
seek_slider.value :=FloatToStr(seekPosition);
|
||||
currentMinutes:=Round(curr_track.currentTime / 60);
|
||||
currentSeconds:=Round(curr_track.currentTime - currentMinutes * 60);
|
||||
durationMinutes:=Round(curr_track.duration / 60);
|
||||
durationSeconds:=Round(curr_track.duration - durationMinutes * 60);
|
||||
curr_time.innerText:= Format('%.2:%d2',[currentMinutes,currentSeconds]);
|
||||
total_duration.innerText:=Format('%.2:%d2',[durationMinutes,durationSeconds]);
|
||||
end;
|
||||
|
||||
procedure TMyApplication.BindElements;
|
||||
|
||||
Function GetElement (aClass : String) : TJSHTMLELement;
|
||||
|
||||
begin
|
||||
|
||||
Result:=TJSHTMLELement(Document.querySelector('.'+aClass));
|
||||
Writeln('Looking for ',aClass,' : ',assigned(Result));
|
||||
end;
|
||||
|
||||
begin
|
||||
now_playing :=GetElement('now-playing');
|
||||
track_art :=GetElement('track-art');
|
||||
track_name :=GetElement('track-name');
|
||||
track_artist :=GetElement('track-artist');
|
||||
display_text :=GetElement('display-text');
|
||||
|
||||
playpause_btn :=GetElement('playpause-track');
|
||||
playpause_btn.AddEventListener('click',@DoPlayPause);
|
||||
next_btn :=GetElement('next-track');
|
||||
next_btn.AddEventListener('click',@NextTrack);
|
||||
prev_btn :=GetElement('prev-track');
|
||||
prev_btn.AddEventListener('click',@PrevTrack);
|
||||
seek_slider :=TJSHTMLInputElement(GetElement('seek_slider'));
|
||||
seek_slider.AddEventListener('change',@SeekTo);
|
||||
volume_slider :=TJSHTMLInputElement(GetElement('volume_slider'));
|
||||
volume_slider.AddEventListener('change',@SetVolume);
|
||||
curr_time :=GetElement('current-time');
|
||||
total_duration :=GetElement('total-duration');
|
||||
end;
|
||||
|
||||
procedure TMyApplication.seekTo(Event: TJSEvent);
|
||||
|
||||
Var
|
||||
dSeekTo : Double;
|
||||
|
||||
begin
|
||||
dSeekTo := curr_track.duration * (StrToFloatDef(seek_slider.value,50) / 100);
|
||||
curr_track.currentTime := dSeekTo;
|
||||
end;
|
||||
|
||||
procedure TMyApplication.SetVolume(Event: TJSEvent);
|
||||
begin
|
||||
curr_track.volume := StrToFloatDef(volume_slider.value,50) / 100;
|
||||
end;
|
||||
|
||||
procedure TMyApplication.DoPlayPause(Event: TJSEvent);
|
||||
begin
|
||||
if isPlaying then
|
||||
pauseTrack
|
||||
else
|
||||
playTrack;
|
||||
end;
|
||||
|
||||
procedure TMyApplication.NextTrack(Event: TJSEvent);
|
||||
begin
|
||||
// Go back to the first track if the
|
||||
// current one is the last in the track list
|
||||
if (track_index < (Length(track_list) - 1)) then
|
||||
Inc(track_index)
|
||||
else
|
||||
track_index:=0;
|
||||
// Load and play the new track
|
||||
loadTrack(track_index);
|
||||
playTrack();
|
||||
end;
|
||||
|
||||
procedure TMyApplication.PrevTrack(Event: TJSEvent);
|
||||
begin
|
||||
if (track_index > 0) then
|
||||
Dec(track_index)
|
||||
else
|
||||
track_index := Length(track_list)- 1;
|
||||
loadTrack(track_index);
|
||||
playTrack();
|
||||
end;
|
||||
|
||||
procedure TMyApplication.PlayTrack;
|
||||
begin
|
||||
curr_track.play();
|
||||
isPlaying:=true;
|
||||
playpause_btn.innerHTML := '<i class="fa fa-pause-circle fa-5x"></i>';
|
||||
end;
|
||||
|
||||
procedure TMyApplication.PauseTrack;
|
||||
begin
|
||||
curr_track.pause();
|
||||
isPlaying:=false;
|
||||
playpause_btn.innerHTML := '<i class="fa fa-play-circle fa-5x"></i>';
|
||||
end;
|
||||
|
||||
procedure TMyApplication.LoadTrack(aIndex: Integer);
|
||||
begin
|
||||
// Clear the previous seek timer
|
||||
window.clearInterval(updateTimer);
|
||||
resetValues();
|
||||
|
||||
curr_track.src :=track_list[track_index].path;
|
||||
curr_track.load();
|
||||
|
||||
track_art.style.SetProperty('background-image','url("' + track_list[track_index].image+ '")');
|
||||
track_art.style.SetProperty('background-image','url("' + track_list[track_index].image+ '")');
|
||||
track_artist.InnerHTML := track_list[track_index].artist;
|
||||
track_name.InnerHTML := track_list[track_index].name;
|
||||
display_text.InnerHTML:=String(track_list[track_index].display);
|
||||
now_playing.InnerHTML := Format('PLAYING %d OF %d',[track_index + 1,Length(track_list)]);
|
||||
updateTimer :=Window.setInterval(@seekUpdate, 1000);
|
||||
curr_track.addEventListener('ended', @nextTrack);
|
||||
random_bg_color();
|
||||
end;
|
||||
|
||||
procedure TMyApplication.random_bg_color;
|
||||
|
||||
Const
|
||||
Lim = 256 - 64;
|
||||
|
||||
Var
|
||||
red,Green,blue : Integer;
|
||||
col : string;
|
||||
begin
|
||||
red:=Round(random(Lim) + 64);
|
||||
green:=Round(random(lim) + 64);
|
||||
blue:=Round(random(lim)+64);
|
||||
col:= Format('rgb(%d,%d,%d)',[red, green ,blue]);
|
||||
TJSHTMLELement(document.body).style.SetProperty('background',col);
|
||||
end;
|
||||
|
||||
procedure TMyApplication.resetValues;
|
||||
begin
|
||||
curr_time.InnerHTML:= '00:00';
|
||||
total_duration.InnerHTML:= '00:00';
|
||||
seek_slider.value:='0';
|
||||
end;
|
||||
|
||||
procedure TMyApplication.doRun;
|
||||
|
||||
begin
|
||||
Terminate;
|
||||
BindElements;
|
||||
curr_track:=TJSHTMLAudioElement(document.createElement('audio'));
|
||||
curr_track.autoplay:=true;
|
||||
ResetValues;
|
||||
Window.SetInterval(@seekUpdate,1000);
|
||||
LoadTrack(0);
|
||||
end;
|
||||
|
||||
var
|
||||
Application : TMyApplication;
|
||||
|
||||
begin
|
||||
Application:=TMyApplication.Create(nil);
|
||||
Application.Initialize;
|
||||
Application.Run;
|
||||
end.
|
143
demo/player/style.css
Normal file
143
demo/player/style.css
Normal file
@ -0,0 +1,143 @@
|
||||
body {
|
||||
background-color: lightgreen;
|
||||
|
||||
/* Smoothly transition the background color */
|
||||
transition: background-color .5s;
|
||||
}
|
||||
|
||||
/* Using flex with the column direction to
|
||||
align items in a vertical direction */
|
||||
.player {
|
||||
height: 95vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.details {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.track-art {
|
||||
margin: 25px;
|
||||
height: 250px;
|
||||
width: 250px;
|
||||
background-image: URL("headset.jpeg");
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
border-radius: 15%;
|
||||
}
|
||||
|
||||
/* Changing the font sizes to suitable ones */
|
||||
.now-playing {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.track-name {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
.display-text {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
.track-artist {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
/* Using flex with the row direction to
|
||||
align items in a horizontal direction */
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.playpause-track,
|
||||
.prev-track,
|
||||
.next-track {
|
||||
padding: 25px;
|
||||
opacity: 0.8;
|
||||
|
||||
/* Smoothly transition the opacity */
|
||||
transition: opacity .2s;
|
||||
}
|
||||
|
||||
/* Change the opacity when mouse is hovered */
|
||||
.playpause-track:hover,
|
||||
.prev-track:hover,
|
||||
.next-track:hover {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
/* Define the slider width so that it scales properly */
|
||||
.slider_container {
|
||||
width: 75%;
|
||||
max-width: 400px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Modify the appearance of the slider */
|
||||
.seek_slider, .volume_slider {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
height: 5px;
|
||||
background: black;
|
||||
opacity: 0.7;
|
||||
-webkit-transition: .2s;
|
||||
transition: opacity .2s;
|
||||
}
|
||||
|
||||
/* Modify the appearance of the slider thumb */
|
||||
.seek_slider::-webkit-slider-thumb,
|
||||
.volume_slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
background: white;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* Change the opacity when mouse is hovered */
|
||||
.seek_slider:hover,
|
||||
.volume_slider:hover {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.seek_slider {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.volume_slider {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.current-time,
|
||||
.total-duration {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
i.fa-volume-down,
|
||||
i.fa-volume-up {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* Change the mouse cursor to a pointer
|
||||
when hovered over */
|
||||
i.fa-play-circle,
|
||||
i.fa-pause-circle,
|
||||
i.fa-step-forward,
|
||||
i.fa-step-backward {
|
||||
cursor: pointer;
|
||||
}
|
46
demo/player/tracks.js
Normal file
46
demo/player/tracks.js
Normal file
@ -0,0 +1,46 @@
|
||||
|
||||
var track_list = [
|
||||
{
|
||||
display: "here we go with our demo!",
|
||||
name: "Epic music",
|
||||
artist: "Bensound epic",
|
||||
image: "https://www.freepascal.org/~michael/pas2js-demos/player/epic.jpg",
|
||||
path: "https://www.freepascal.org/~michael/pas2js-demos/player/bensound-epic.mp3",
|
||||
},
|
||||
{
|
||||
display: "Now for something less hard...",
|
||||
name: "Rumble rock",
|
||||
artist: "Bensound rumble",
|
||||
image: "https://www.freepascal.org/~michael/pas2js-demos/player/rumble.jpg",
|
||||
path: "https://www.freepascal.org/~michael/pas2js-demos/player/bensound-rumble.mp3"
|
||||
},
|
||||
{
|
||||
display: "We even have dubstep",
|
||||
name: "Dubstep for the fans",
|
||||
artist: "Bensound dubstep",
|
||||
image: "https://www.freepascal.org/~michael/pas2js-demos/player/dubstep.jpg",
|
||||
path: "https://www.freepascal.org/~michael/pas2js-demos/player/bensound-dubstep.mp3"
|
||||
},
|
||||
{
|
||||
display: "We also have some pop tunes",
|
||||
name: "Pop tune beyond the line",
|
||||
artist: "Bensound pop tune ",
|
||||
image: "https://www.freepascal.org/~michael/pas2js-demos/player/beyondtheline.jpg",
|
||||
path: "https://www.freepascal.org/~michael/pas2js-demos/player/bensound-beyondtheline.mp3"
|
||||
},
|
||||
{
|
||||
display: "Something soundtrack-like.",
|
||||
name: "Once again",
|
||||
artist: "Bensound once again",
|
||||
image: "https://www.freepascal.org/~michael/pas2js-demos/player/onceagain.jpg",
|
||||
path: "https://www.freepascal.org/~michael/pas2js-demos/player/bensound-onceagain.mp3",
|
||||
},
|
||||
{
|
||||
display: "And going home with some jazzy tune!",
|
||||
name: "Jazzy lounge",
|
||||
artist: "Bensound the lounge",
|
||||
image: "https://www.freepascal.org/~michael/pas2js-demos/player/thelounge.jpg",
|
||||
path: "https://www.freepascal.org/~michael/pas2js-demos/player/bensound-thelounge.mp3",
|
||||
}
|
||||
];
|
||||
|
Loading…
Reference in New Issue
Block a user