From 1aac5c557700015054685eec36f727199ba9c06c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20B=C3=B6hning?= <1497707+bohning@users.noreply.github.com> Date: Mon, 27 May 2024 21:50:54 +0200 Subject: [PATCH] Add UWebServer which serves the list of available songs on localhost, port 8091. --- Makefile.in | 1 + game/resources/songlist_template.html | 88 ++++++++++ src/base/UMain.pas | 18 +- src/base/UWebServer.pas | 149 ++++++++++++++++ src/ultrastardx-unix.lpi | 242 ++++++++++++++++++++++---- src/ultrastardx.dpr | 2 + 6 files changed, 463 insertions(+), 37 deletions(-) create mode 100644 game/resources/songlist_template.html create mode 100644 src/base/UWebServer.pas diff --git a/Makefile.in b/Makefile.in index f40b28dc6..bb8ae34e2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -413,6 +413,7 @@ macosx-app: all # Must be done BEFORE info.plist is created. $(MKDIR) $(macosx_bundle_path)/resources $(INSTALL_DATA) icons/ultrastardx.icns $(macosx_bundle_path)/resources/ + $(INSTALL_DATA) game/resources/songlist_template.html $(macosx_bundle_path)/resources/ # the info.plist file $(INSTALL_DATA) $(USDX_SRC_DIR)/macosx/Info.plist $(macosx_bundle_path)/ diff --git a/game/resources/songlist_template.html b/game/resources/songlist_template.html new file mode 100644 index 000000000..10a0df268 --- /dev/null +++ b/game/resources/songlist_template.html @@ -0,0 +1,88 @@ + + + + + Song List + + + + +

Song List

+ + + + + + + + + + +
ArtistTitleEditionGenreYear
+ + diff --git a/src/base/UMain.pas b/src/base/UMain.pas index 08ea4aae0..e9df5df96 100644 --- a/src/base/UMain.pas +++ b/src/base/UMain.pas @@ -101,13 +101,16 @@ implementation ULuaParty, ULuaScreenSing, UTime, - UWebcam; + UWebcam, + UWebServer; //UVideoAcinerella; procedure Main; var WindowTitle: string; BadPlayer: integer; + Server: TWebServer; + begin {$IFNDEF Debug} try @@ -262,6 +265,14 @@ procedure Main; Display.CurrentScreen^.FadeTo( @ScreenOptionsRecord ); end; + //------------------------------ + // Start Webserver + //------------------------------ + Log.LogStatus('Webserver', 'Initialization'); + // Create and start the web server + Server := TWebServer.Create(8091); + Server.Start; + //------------------------------ // Start Mainloop //------------------------------ @@ -296,6 +307,11 @@ procedure Main; Log.LogStatus('Finalize SDL', 'Finalization'); SDL_Quit(); + Log.LogStatus('Finalize Webserver', 'Finalization'); + //Server.Terminate; // Terminate the thread + //Server.WaitFor; + //Server.Free; + Log.LogStatus('Finalize Log', 'Finalization'); {$IFNDEF Debug} end; diff --git a/src/base/UWebServer.pas b/src/base/UWebServer.pas new file mode 100644 index 000000000..95564d1d0 --- /dev/null +++ b/src/base/UWebServer.pas @@ -0,0 +1,149 @@ +{* UltraStar Deluxe - Karaoke Game + * + * UltraStar Deluxe is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + *} + +unit UWebServer; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, fphttpserver, HTTPDefs, USongs, USong, UPlatform, UPath; + +type + TWebServer = class(TThread) + private + FServer: TFPHTTPServer; + FPort: Integer; + protected + procedure Execute; override; + procedure HandleRequest(Sender: TObject; var ARequest: TFPHTTPConnectionRequest; + var AResponse: TFPHTTPConnectionResponse); + function GenerateHTMLWithSongs: string; + function LoadTemplate: string; + public + constructor Create(APort: Integer); + destructor Destroy; override; + end; + +implementation + +constructor TWebServer.Create(APort: Integer); +begin + inherited Create(True); // Create suspended + FPort := APort; + FreeOnTerminate := True; +end; + +destructor TWebServer.Destroy; +begin + inherited Destroy; +end; + +procedure TWebServer.Execute; +begin + FServer := TFPHTTPServer.Create(nil); + try + FServer.OnRequest := @HandleRequest; + FServer.Port := FPort; + FServer.Active := True; + WriteLn('Server is running on port ', FPort); + while not Terminated do + Sleep(100); + finally + FServer.Free; + end; +end; + +procedure TWebServer.HandleRequest(Sender: TObject; var ARequest: TFPHTTPConnectionRequest; + var AResponse: TFPHTTPConnectionResponse); +var + ResponseHTML: string; +begin + if ARequest.Method = 'GET' then + begin + // Serve the HTML page with the list of songs + AResponse.ContentType := 'text/html; charset=UTF-8'; + ResponseHTML := GenerateHTMLWithSongs; + AResponse.Content := ResponseHTML; + AResponse.Code := 200; + end + else + begin + // Method not allowed + AResponse.Content := '

Method Not Allowed

'; + AResponse.ContentType := 'text/html; charset=UTF-8'; + AResponse.Code := 405; + end; +end; + +function TWebServer.LoadTemplate: string; +var + TemplateFilePath: IPath; + TemplateFile: TStringList; +begin + TemplateFile := TStringList.Create; + try + TemplateFilePath := Platform.GetGameUserPath.Append('resources\songlist_template.html'); + TemplateFile.LoadFromFile(TemplateFilePath.toNative); + Result := TemplateFile.Text; + finally + TemplateFile.Free; + end; +end; + +function TWebServer.GenerateHTMLWithSongs: string; +var + I: Integer; + SongRows: string; + Edition, Genre, Year: string; +begin + SongRows := ''; + for I := 0 to Songs.SongList.Count - 1 do + begin + Edition := UTF8Encode(TSong(Songs.SongList[I]).Edition); + Genre := UTF8Encode(TSong(Songs.SongList[I]).Genre); + Year := IntToStr(TSong(Songs.SongList[I]).Year); + + if Edition = 'Unknown' then + Edition := ''; + if Genre = 'Unknown' then + Genre := ''; + if Year = '0' then + Year := ''; + + SongRows := SongRows + '' + sLineBreak + + '' + UTF8Encode(TSong(Songs.SongList[I]).Artist) + '' + sLineBreak + + '' + UTF8Encode(TSong(Songs.SongList[I]).Title) + '' + sLineBreak + + '' + Edition + '' + sLineBreak + + '' + Genre + '' + sLineBreak + + '' + Year + '' + sLineBreak + + '' + sLineBreak; + end; + + Result := LoadTemplate; + Result := StringReplace(Result, '', SongRows, []); +end; + +end. + diff --git a/src/ultrastardx-unix.lpi b/src/ultrastardx-unix.lpi index 649279c62..ee087578f 100644 --- a/src/ultrastardx-unix.lpi +++ b/src/ultrastardx-unix.lpi @@ -1,39 +1,41 @@ - + - - + + + - - </General> - <VersionInfo> - <ProjectVersion Value=""/> - </VersionInfo> + <BuildModes Count="1"> + <Item1 Name="default" Default="True"/> + </BuildModes> <PublishOptions> <Version Value="2"/> - <IgnoreBinaries Value="False"/> - <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> - <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/> </PublishOptions> <RunParams> <local> - <FormatVersion Value="1"/> - <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/> + <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/> </local> + <FormatVersion Value="2"/> + <Modes Count="1"> + <Mode0 Name="default"> + <local> + <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/> + </local> + </Mode0> + </Modes> </RunParams> - <Units Count="126"> + <Units Count="172"> <Unit0> <Filename Value="ultrastardx.dpr"/> <IsPartOfProject Value="True"/> - <UnitName Value="ultrastardx"/> </Unit0> <Unit1> <Filename Value="base/TextGL.pas"/> @@ -130,7 +132,6 @@ <Unit24> <Filename Value="base/UMain.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="UMain"/> </Unit24> <Unit25> <Filename Value="base/UMusic.pas"/> @@ -211,17 +212,14 @@ <Unit44> <Filename Value="base/UThemes.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="UThemes"/> </Unit44> <Unit45> <Filename Value="base/UTime.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="UTime"/> </Unit45> <Unit46> <Filename Value="lua/ULuaUtils.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="ULuaUtils"/> </Unit46> <Unit47> <Filename Value="menu/UDisplay.pas"/> @@ -290,7 +288,6 @@ <Unit63> <Filename Value="screens/UScreenCredits.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="UScreenCredits"/> </Unit63> <Unit64> <Filename Value="screens/UScreenEdit.pas"/> @@ -487,12 +484,10 @@ <Unit112> <Filename Value="media/UVideo.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="UVideo"/> </Unit112> <Unit113> <Filename Value="media/UVisualizer.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="UVisualizer"/> </Unit113> <Unit114> <Filename Value="config-linux.inc"/> @@ -509,69 +504,245 @@ <Unit117> <Filename Value="lua/UHookableEvent.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="UHookableEvent"/> </Unit117> <Unit118> <Filename Value="lua/ULuaCore.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="ULuaCore"/> </Unit118> <Unit119> <Filename Value="lua/ULuaGl.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="ULuaGl"/> </Unit119> <Unit120> <Filename Value="lua/ULuaLog.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="ULuaLog"/> </Unit120> <Unit121> <Filename Value="lua/ULuaParty.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="ULuaParty"/> </Unit121> <Unit122> <Filename Value="lua/ULuaScreenSing.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="ULuaScreenSing"/> </Unit122> <Unit123> <Filename Value="lua/ULuaTextGL.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="ULuaTextGL"/> </Unit123> <Unit124> <Filename Value="lua/ULuaTexture.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="ULuaTexture"/> </Unit124> <Unit125> <Filename Value="lua/ULuaUsdx.pas"/> <IsPartOfProject Value="True"/> - <UnitName Value="ULuaUsdx"/> </Unit125> + <Unit126> + <Filename Value="base/UFilesystem.pas"/> + <IsPartOfProject Value="True"/> + </Unit126> + <Unit127> + <Filename Value="lib/ctypes/ctypes.pas"/> + <IsPartOfProject Value="True"/> + </Unit127> + <Unit128> + <Filename Value="lib/anyascii/anyascii.pas"/> + <IsPartOfProject Value="True"/> + </Unit128> + <Unit129> + <Filename Value="lib/SQLite/SQLiteTable3.pas"/> + <IsPartOfProject Value="True"/> + </Unit129> + <Unit130> + <Filename Value="lib/SQLite/SQLite3.pas"/> + <IsPartOfProject Value="True"/> + </Unit130> + <Unit131> + <Filename Value="lib/SDL2/sdl2.pas"/> + <IsPartOfProject Value="True"/> + </Unit131> + <Unit132> + <Filename Value="lib/SDL2/SDL2_image.pas"/> + <IsPartOfProject Value="True"/> + </Unit132> + <Unit133> + <Filename Value="lib/dglOpenGL/dglOpenGL.pas"/> + <IsPartOfProject Value="True"/> + </Unit133> + <Unit134> + <Filename Value="lib/zlib/zlib.pas"/> + <IsPartOfProject Value="True"/> + </Unit134> + <Unit135> + <Filename Value="lib/freetype/freetype.pas"/> + <IsPartOfProject Value="True"/> + </Unit135> + <Unit136> + <Filename Value="lib/Lua/ULua.pas"/> + <IsPartOfProject Value="True"/> + </Unit136> + <Unit137> + <Filename Value="base/UPathUtils.pas"/> + <IsPartOfProject Value="True"/> + </Unit137> + <Unit138> + <Filename Value="base/UNote.pas"/> + <IsPartOfProject Value="True"/> + </Unit138> + <Unit139> + <Filename Value="base/UBeatTimer.pas"/> + <IsPartOfProject Value="True"/> + </Unit139> + <Unit140> + <Filename Value="base/UUnicodeUtils.pas"/> + <IsPartOfProject Value="True"/> + </Unit140> + <Unit141> + <Filename Value="base/uunicodestringhelper.pas"/> + <IsPartOfProject Value="True"/> + </Unit141> + <Unit142> + <Filename Value="base/UTextEncoding.pas"/> + <IsPartOfProject Value="True"/> + </Unit142> + <Unit143> + <Filename Value="base/UPath.pas"/> + <IsPartOfProject Value="True"/> + </Unit143> + <Unit144> + <Filename Value="base/UHelp.pas"/> + <IsPartOfProject Value="True"/> + </Unit144> + <Unit145> + <Filename Value="lib/fft/UFFT.pas"/> + <IsPartOfProject Value="True"/> + </Unit145> + <Unit146> + <Filename Value="media/UAudioInput_SDL.pas"/> + <IsPartOfProject Value="True"/> + </Unit146> + <Unit147> + <Filename Value="screens/controllers/UScreenSingController.pas"/> + <IsPartOfProject Value="True"/> + </Unit147> + <Unit148> + <Filename Value="screens/views/UScreenSingView.pas"/> + <IsPartOfProject Value="True"/> + </Unit148> + <Unit149> + <Filename Value="screens/UScreenJukebox.pas"/> + <IsPartOfProject Value="True"/> + </Unit149> + <Unit150> + <Filename Value="screens/UScreenOptionsInput.pas"/> + <IsPartOfProject Value="True"/> + </Unit150> + <Unit151> + <Filename Value="screens/UScreenOptionsNetwork.pas"/> + <IsPartOfProject Value="True"/> + </Unit151> + <Unit152> + <Filename Value="screens/UScreenOptionsWebcam.pas"/> + <IsPartOfProject Value="True"/> + </Unit152> + <Unit153> + <Filename Value="screens/UScreenOptionsJukebox.pas"/> + <IsPartOfProject Value="True"/> + </Unit153> + <Unit154> + <Filename Value="screens/UScreenPartyRounds.pas"/> + <IsPartOfProject Value="True"/> + </Unit154> + <Unit155> + <Filename Value="webSDK/UWebSDK.pas"/> + <IsPartOfProject Value="True"/> + </Unit155> + <Unit156> + <Filename Value="lib/openCV/opencv_highgui.pas"/> + <IsPartOfProject Value="True"/> + </Unit156> + <Unit157> + <Filename Value="lib/openCV/opencv_core.pas"/> + <IsPartOfProject Value="True"/> + </Unit157> + <Unit158> + <Filename Value="lib/openCV/opencv_imgproc.pas"/> + <IsPartOfProject Value="True"/> + </Unit158> + <Unit159> + <Filename Value="lib/openCV/opencv_types.pas"/> + <IsPartOfProject Value="True"/> + </Unit159> + <Unit160> + <Filename Value="menu/UMenuStaticList.pas"/> + <IsPartOfProject Value="True"/> + </Unit160> + <Unit161> + <Filename Value="base/UWebcam.pas"/> + <IsPartOfProject Value="True"/> + </Unit161> + <Unit162> + <Filename Value="base/UPartyTournament.pas"/> + <IsPartOfProject Value="True"/> + </Unit162> + <Unit163> + <Filename Value="screens/UScreenPartyTournamentRounds.pas"/> + <IsPartOfProject Value="True"/> + </Unit163> + <Unit164> + <Filename Value="screens/UScreenPartyTournamentPlayer.pas"/> + <IsPartOfProject Value="True"/> + </Unit164> + <Unit165> + <Filename Value="screens/UScreenPartyTournamentOptions.pas"/> + <IsPartOfProject Value="True"/> + </Unit165> + <Unit166> + <Filename Value="screens/UScreenPartyTournamentWin.pas"/> + <IsPartOfProject Value="True"/> + </Unit166> + <Unit167> + <Filename Value="screens/UScreenJukeboxOptions.pas"/> + <IsPartOfProject Value="True"/> + </Unit167> + <Unit168> + <Filename Value="screens/UScreenJukeboxPlaylist.pas"/> + <IsPartOfProject Value="True"/> + </Unit168> + <Unit169> + <Filename Value="base/UAvatars.pas"/> + <IsPartOfProject Value="True"/> + </Unit169> + <Unit170> + <Filename Value="screens/UScreenAbout.pas"/> + <IsPartOfProject Value="True"/> + </Unit170> + <Unit171> + <Filename Value="base/UWebServer.pas"/> + <IsPartOfProject Value="True"/> + </Unit171> </Units> </ProjectOptions> <CompilerOptions> - <Version Value="8"/> + <Version Value="11"/> <Target> <Filename Value="../game/ultrastardx"/> </Target> <SearchPaths> - <IncludeFiles Value="lib/JEDI-SDL/SDL/Pas/"/> - <OtherUnitFiles Value="base/;menu/;screens/;media/;lib/;lua/"/> + <IncludeFiles Value="lib/JEDI-SDL/SDL/Pas"/> + <OtherUnitFiles Value="base;menu;screens;media;lib;lua"/> <UnitOutputDirectory Value="../build/fpc-$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> <SyntaxOptions> <CStyleOperator Value="False"/> <AllowLabel Value="False"/> + <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <Linking> <Debugging> - <GenerateDebugInfo Value="True"/> + <DebugInfoType Value="dsDwarf3"/> </Debugging> </Linking> <Other> @@ -579,7 +750,6 @@ <ShowNotes Value="False"/> <ShowHints Value="False"/> </Verbosity> - <CompilerPath Value="$(CompPath)"/> <ExecuteBefore> <Command Value="/usr/bin/make"/> <ScanForFPCMsgs Value="True"/> diff --git a/src/ultrastardx.dpr b/src/ultrastardx.dpr index 9ce433f9e..5b43b41a1 100644 --- a/src/ultrastardx.dpr +++ b/src/ultrastardx.dpr @@ -396,6 +396,8 @@ uses UAvatars in 'base\UAvatars.pas', UScreenAbout in 'screens\UScreenAbout.pas', + UWebServer in 'base\UWebServer.pas', + SysUtils; const