diff --git a/Makefile b/Makefile index 0614d43..f1648ab 100644 --- a/Makefile +++ b/Makefile @@ -39,19 +39,20 @@ include $(DEVKITPRO)/libnx/switch_rules #--------------------------------------------------------------------------------- TARGET := $(notdir $(CURDIR)) BUILD := build -SOURCES := libs/imgui libs/imgui/misc/freetype source source/UI source/remotefs/Enigma2 source/localfs source/localfs/usb source/remotefs/ftplib source/remotefs/HTTPDir +SOURCES := libs/imgui libs/imgui/misc/freetype source source/eqpreset source/database source/UI source/remotefs/Enigma2 source/localfs source/localfs/usb source/remotefs/ftplib source/remotefs/HTTPDir DATA := data -INCLUDES := libs/simpleini libs/imgui include source/remotefs/Enigma2 source/localfs source/localfs/usb source/remotefs/ftplib source/remotefs/HTTPDir +INCLUDES := libs/simpleini libs/imgui include source/eqpreset source/database source/remotefs/Enigma2 source/localfs source/localfs/usb source/remotefs/ftplib source/remotefs/HTTPDir ROMFS := romfs VERSION_MAJOR := 0 -VERSION_MINOR := 4 -VERSION_MICRO := 1 +VERSION_MINOR := 5 +VERSION_MICRO := 0 APP_TITLE := NXMP APP_AUTHOR := proconsule APP_VERSION := ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO} + #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- @@ -61,7 +62,7 @@ CFLAGS := -g -Wall -Wno-sign-compare -O2 -ffunction-sections \ $(ARCH) $(DEFINES) CFLAGS += `sdl2-config --cflags` `freetype-config --cflags` -CFLAGS += $(INCLUDE) -D__SWITCH__ +CFLAGS += $(INCLUDE) -D__SWITCH__ $(BUILD_TYPE) CFLAGS += -DVERSION_MAJOR=$(VERSION_MAJOR) -DVERSION_MINOR=$(VERSION_MINOR) -DVERSION_MICRO=$(VERSION_MICRO) -gdwarf-2 -gstrict-dwarf @@ -71,7 +72,9 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fexceptions -DIMGUI_IMPL_OPENGL_LOADER_GLAD \ ASFLAGS := -g $(ARCH) LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) -LIBS := `curl-config --libs` `sdl2-config --libs` `freetype-config --libs` -lmpv -lswscale -lswresample -lavformat -lavfilter -lavcodec -lavutil -llzma -lopus -lvpx -lass -lfreetype -lfribidi -lpng -lbz2 -lusbhsfs -lntfs-3g -llwext4 -lglad -lEGL -lglapi -ldrm_nouveau -ltinyxml2 -lturbojpeg -llua -lnx -lz +LIBS := `curl-config --libs` `sdl2-config --libs` `freetype-config --libs` -lmpv -lswscale -lswresample -lavformat -lavfilter -lavcodec -lavutil -llzma -lopus -lvpx -lass -lharfbuzz -lfreetype -lfribidi -lpng -lbz2 -lusbhsfs -lntfs-3g -llwext4 -lglad -lEGL -lglapi -ldrm_nouveau -ltinyxml2 -lturbojpeg -llua -lmbedcrypto -lmbedx509 -lmbedtls -lmbedcrypto -lmbedx509 -lmbedtls -lsqlite3 -lnx -lz + + #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing @@ -174,7 +177,17 @@ all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile +ifneq (,$(findstring r,$(MAKEFLAGS))) + @echo "Stable Release" + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile BUILD_TYPE=-DRELEASE_TYPE=0 +else + @echo "Beta Release" + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile BUILD_TYPE=-DRELEASE_TYPE=1 + +endif + + + #--------------------------------------------------------------------------------- clean: @@ -197,6 +210,7 @@ DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- ifeq ($(strip $(APP_JSON)),) + all : $(OUTPUT).nro ifeq ($(strip $(NO_NACP)),) diff --git a/Makefile.win32 b/Makefile.win32 index 9aa6bc4..37268ee 100644 --- a/Makefile.win32 +++ b/Makefile.win32 @@ -7,8 +7,8 @@ BUILD := build-win32 TARGET := $(notdir $(CURDIR)) VERSION_MAJOR := 0 -VERSION_MINOR := 2 -VERSION_MICRO := 1 +VERSION_MINOR := 5 +VERSION_MICRO := 0 CFLAGS := -g -Wall -Wno-sign-compare -O2 -ffunction-sections CFLAGS += `sdl2-config --cflags` `freetype-config --cflags` @@ -20,11 +20,11 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fexceptions -DIMGUI_IMPL_OPENGL_LOADER_GLAD \ -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS -DIMGUI_ENABLE_FREETYPE -fpermissive -LIBS := $(shell pkgconf mpv --libs --static) $(shell pkgconf libavcodec --libs --static) -lmpv `curl-config --libs` `sdl2-config --static-libs` `freetype-config --libs` -lswscale -lswresample -lavformat -lavfilter -lavcodec -lavutil -lfreetype -lfribidi -lpng -lbz2 -ltinyxml2 -llua5.1 -ldwmapi -llcms2 -lglfw3 -lopengl32 -lmingw32 -lSDLmain -lSDL2 -mwindows -liconv -lm -luser32 -lgdi32 -lwinmm -ldxguid -lws2_32 -lavrt -lz +LIBS := ../../sqlite-snapshot-202111051952/.libs/libsqlite3.a $(shell pkgconf mpv --libs --static) $(shell pkgconf libavcodec --libs --static) -lmpv `curl-config --libs` `sdl2-config --static-libs` `freetype-config --libs` -lswscale -lswresample -lavformat -lavfilter -lavcodec -lavutil -lfreetype -lfribidi -lpng -lbz2 -ltinyxml2 -llua5.1 -ldwmapi -llcms2 -lglfw3 -lopengl32 -lmingw32 -lSDLmain -lSDL2 -mwindows -liconv -lm -luser32 -lgdi32 -lwinmm -ldxguid -lws2_32 -lavrt -lz -SOURCES := libs/glad/src/ libs/imgui libs/imgui/misc/freetype source source/UI source/remotefs/Enigma2 source/remotefs/ftplib source/remotefs/HTTPDir -INCLUDES := /mingw64/include/ libs/glad/include libs/simpleini libs/imgui include source/remotefs/Enigma2 source/remotefs/ftplib source/remotefs/HTTPDir +SOURCES := libs/glad/src/ libs/imgui libs/imgui/misc/freetype source source/eqpreset source/database source/localfs source/localfs/usb source/UI source/remotefs/Enigma2 source/remotefs/ftplib source/remotefs/HTTPDir +INCLUDES := /mingw64/include/ source/localfs/usb source/localfs libs/glad/include libs/simpleini libs/imgui source/database source/eqpreset include source/remotefs/Enigma2 source/remotefs/ftplib source/remotefs/HTTPDir ifneq ($(BUILD),$(notdir $(CURDIR))) diff --git a/README.md b/README.md index 51cbba1..0d08ffd 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,8 @@ Buttons Mapping - R L ZR ZL (seek +/- during playback) - \+ Exit NXMP - R Stick Button Toggle Masterlock (during playback, only A button will work) -- Dpad Right (during playback show right menu) -- Dpad Left (during playback close right menu) +- Dpad Right (during playback show/hide right menu) +- Dpad Down (during playback show/hide player UI) - R Stick Up/Down Fast Scroll on file list FAQ @@ -62,6 +62,8 @@ Thanks to - Cpasjuste for pPlay https://github.com/Cpasjuste/pplay some code was taken here (mpv part) - DarkMatterCore for libusbhsfs https://github.com/DarkMatterCore/libusbhsfs (this gives NXMP USB support) - bodyXY @ GBATemp forum for banner and icons +- Godorowski @ GBATemp forum for player UI design and icons +- Chocola @ GBATemp forum for usage guide and beta testing - docgold @ GBATemp forum for Enigma2 samples and support on decoders - tataniko @ GBATemp forum for suggestions and bug hunting - All guys on GBAtemp diff --git a/include/apppopups.h b/include/apppopups.h index ee5f3fc..54f1dc9 100644 --- a/include/apppopups.h +++ b/include/apppopups.h @@ -16,6 +16,7 @@ namespace Popups { }; void SaveSettingsPopup(void); + void ResumePopup(void); } #endif \ No newline at end of file diff --git a/include/appwindows.h b/include/appwindows.h index 29f5d31..7584f78 100644 --- a/include/appwindows.h +++ b/include/appwindows.h @@ -15,7 +15,7 @@ namespace Windows { ImGui::PopStyleVar(); }; - void FileBrowserWindow(bool *focus, bool first_item); + void FileBrowserWindow(bool *focus, bool *first_item); void USBBrowserWindow(bool *focus, bool *first_item); void EnigmaWindow(bool *focus, bool *first_item); void MainMenuWindow(bool *focus, bool *first_item); diff --git a/include/config.h b/include/config.h index 5af4c5b..62c1b17 100644 --- a/include/config.h +++ b/include/config.h @@ -31,6 +31,14 @@ class Config{ int getDeinterlace(bool tmpvalue); void setDeinterlace(int value); + bool getDbActive(bool tmpvalue); + void setDbActive(bool value); + + int getResumeStartPerc(bool tmpvalue); + void setResumeStartPerc(int value); + int getResumeStopPerc(bool tmpvalue); + void setResumeStopPerc(int value); + void saveSettings(); std::vector topmenu; @@ -52,6 +60,16 @@ class Config{ int tmpdeint; int deint; + + int tmpstartresumeperc; + int tmpstopresumeperc; + int startresumeperc; + int stopresumeperc; + + + bool tmpdbactive; + bool dbactive; + std::string inifilePath; }; diff --git a/include/fileInfo.h b/include/fileInfo.h index e29748d..b230f48 100644 --- a/include/fileInfo.h +++ b/include/fileInfo.h @@ -20,6 +20,7 @@ class fileInfo { int sample_rate; int width; int height; + bool albumart = false; bool selected = false; }; @@ -35,12 +36,20 @@ class fileInfo { int aud_id = -1; int sub_id = -1; int position = 0; + int duration = 0; + std::string title; + std::string artist; + double getplayPerc(){ + return (double)position/(double)duration; + } + bool islive = false; }; std::string title = "Unknown"; std::string path; long duration = 0; + long resume = 0; int bit_rate = 0; std::vector videos; std::vector audios; diff --git a/include/gui.h b/include/gui.h index 7beb8c3..d253d12 100644 --- a/include/gui.h +++ b/include/gui.h @@ -16,6 +16,8 @@ #include "remotefs.h" #include "localfiles.h" #include "SimpleIni.h" +#include "eqpreset.h" +#include "SQLiteDB.h" #include "remotefs.h" #include "localFs.h" #include "utils.h" @@ -47,7 +49,8 @@ enum PLAYER_STATES { enum APP_POPUP_STATES { POPUP_STATE_NONE, - POPUP_STATE_SAVE_SETTINGS + POPUP_STATE_SAVE_SETTINGS, + POPUP_STATE_RESUME }; enum PLAYER_RIGHT_MENU_STATES { @@ -67,12 +70,18 @@ enum PLAYER_RIGHT_MENU_STATES { PLAYER_SUPERAUDIOEQ }; +enum PLAYER_CONTROL_STATES { + PLAYER_CONTROL_STATE_NONE, + PLAYER_CONTROL_STATE_CONTROLS +}; + typedef struct { MENU_STATES state = MENU_STATE_HOME; MENU_STATES laststate = MENU_STATE_FILEBROWSER; PLAYER_RIGHT_MENU_STATES rightmenustate = PLAYER_RIGHT_MENU_PLAYER; PLAYER_STATES playerstate = PLAYER_STATE_VIDEO; + PLAYER_CONTROL_STATES playercontrolstate = PLAYER_CONTROL_STATE_NONE; APP_POPUP_STATES popupstate = POPUP_STATE_NONE; int selected = 0; std::string usbpath = ""; @@ -81,6 +90,7 @@ typedef struct { std::vector networksources; + float rightmenu_startpos = 1280.0; bool networkselect = true; int playershowcontrols = false; @@ -121,6 +131,8 @@ extern std::string nxmpTitle; extern Enigma2 *enigma2; extern Config *configini; +extern EQPreset *eqpreset; +extern SQLiteDB *sqlitedb; extern Tex SdCardTexture; extern Tex UsbTexture; @@ -142,6 +154,17 @@ extern Tex MPVTexture; extern Tex NXMPBannerTexture; extern Tex ExitTexture; + +extern Tex PlayIcon; +extern Tex PauseIcon; +extern Tex StopIcon; +extern Tex MuteIcon; +extern Tex VolumeIcon; +extern Tex LoopIcon; +extern Tex NoLoopIcon; + + + extern ImFont* fontSmall; diff --git a/include/libmpv.h b/include/libmpv.h index 19d165d..3a15792 100644 --- a/include/libmpv.h +++ b/include/libmpv.h @@ -22,6 +22,10 @@ class libMpv{ ~libMpv(); + void loadFile(std::string _path); + + void loadFileLive(std::string _path,std::string _changename = ""); + void Pause(); void Resume(); @@ -35,6 +39,9 @@ class libMpv{ bool Paused(); int64_t getPosition(); + int64_t getDuration(); + + int getFileInfoPerc(); int64_t getVideoWidth(); int64_t getVideoHeight(); @@ -56,10 +63,15 @@ class libMpv{ void setRotate(int value, bool osd); void setVolume(int value,bool osd); + + bool getMute(); + void toggleMute(); + void setAudioDelay(double value,bool osd); void setAudioEQ(int *eqval,bool osd); void setAudioSuperEQ(float *eqval,bool osd); + void setAudioSuperEQband(float eqval,int band,bool osd); void setSubDelay(double value,bool osd); void setSubPos(int value,bool osd); @@ -67,10 +79,12 @@ class libMpv{ void setDeinterlace(int value); - + void setLoop(bool val); + bool getLoop(); void getfileInfo(); + mpv_handle *getHandle(); @@ -87,6 +101,10 @@ class libMpv{ std::vector decoderlist; fileInfo * fileinfo = nullptr; + bool loop = false; + int volume = 100; + int tmpvolume = 100; + }; #endif \ No newline at end of file diff --git a/include/localfiles.h b/include/localfiles.h index 2574b00..1603972 100644 --- a/include/localfiles.h +++ b/include/localfiles.h @@ -40,6 +40,7 @@ namespace FS { std::vector getDirList(const std::string &path,bool showHidden,const std::vector &extensions); std::string backPath(std::string path); bool Sort(const FileEntry &entryA, const FileEntry &entryB); + std::string getFilefromPath(std::string path); } #endif \ No newline at end of file diff --git a/include/playerwindows.h b/include/playerwindows.h index d6f504a..86c097c 100644 --- a/include/playerwindows.h +++ b/include/playerwindows.h @@ -2,6 +2,7 @@ #define NXMP_PLAYERWINDOWS_H #include "imgui.h" +#include "gui.h" namespace playerWindows{ @@ -13,8 +14,9 @@ namespace playerWindows{ ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0,0.0,0.0,0.5)); } + static float rightmenuposX = 1280.0f; inline void SetupRightWindow(void) { - ImGui::SetNextWindowPos(ImVec2(1080.0f, 0.0f), ImGuiCond_Once); + ImGui::SetNextWindowPos(ImVec2(rightmenuposX, 0.0f), ImGuiCond_Always); ImGui::SetNextWindowSize(ImVec2(200.0f, 720.0f), ImGuiCond_Once); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0,0.0,0.0,0.5)); @@ -35,6 +37,13 @@ namespace playerWindows{ ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0,0.0,0.0,0.5)); }; + + inline void SetupPlayerControlsWindow(void) { + ImGui::SetNextWindowPos(ImVec2(0.0f, 620.0f), ImGuiCond_Once); + ImGui::SetNextWindowSize(ImVec2(1280.0f, 720.0f), ImGuiCond_Once); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0,0.0,0.0,0.5)); + }; inline void ExitWindow(void) { ImGui::End(); @@ -61,6 +70,8 @@ namespace playerWindows{ void CacheWindow(); + void playerControls(); + } #endif \ No newline at end of file diff --git a/include/utils.h b/include/utils.h index 274c9d2..d360c19 100644 --- a/include/utils.h +++ b/include/utils.h @@ -54,6 +54,7 @@ namespace Utility{ std::string ltrim(const std::string &s); std::string rtrim(const std::string &s); std::string trim(const std::string &s); + std::string truncateLen(std::string path,int len); } #endif \ No newline at end of file diff --git a/romfs/network.png b/romfs/network.png old mode 100755 new mode 100644 diff --git a/romfs/player/loop.png b/romfs/player/loop.png new file mode 100644 index 0000000..20d50ef Binary files /dev/null and b/romfs/player/loop.png differ diff --git a/romfs/player/mute.png b/romfs/player/mute.png new file mode 100644 index 0000000..908d1d2 Binary files /dev/null and b/romfs/player/mute.png differ diff --git a/romfs/player/noloop.png b/romfs/player/noloop.png new file mode 100644 index 0000000..a8c42ee Binary files /dev/null and b/romfs/player/noloop.png differ diff --git a/romfs/player/pause.png b/romfs/player/pause.png new file mode 100644 index 0000000..1491909 Binary files /dev/null and b/romfs/player/pause.png differ diff --git a/romfs/player/play.png b/romfs/player/play.png new file mode 100644 index 0000000..9521578 Binary files /dev/null and b/romfs/player/play.png differ diff --git a/romfs/player/stop.png b/romfs/player/stop.png new file mode 100644 index 0000000..14582c7 Binary files /dev/null and b/romfs/player/stop.png differ diff --git a/romfs/player/volume.png b/romfs/player/volume.png new file mode 100644 index 0000000..98dfbd3 Binary files /dev/null and b/romfs/player/volume.png differ diff --git a/romfs/sdcard.png b/romfs/sdcard.png old mode 100755 new mode 100644 diff --git a/source/UI/apppopups.cpp b/source/UI/apppopups.cpp index 6c1c562..3d6ca8a 100644 --- a/source/UI/apppopups.cpp +++ b/source/UI/apppopups.cpp @@ -34,4 +34,34 @@ namespace Popups{ Popups::ExitPopup(); } + void ResumePopup(void) { + Popups::SetupPopup("Resume Play"); + + if (ImGui::BeginPopupModal("Resume Play", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { + + ImGui::Text("Resume Playback?"); + + ImGui::Text("Resume Playback @ %s",Utility::formatTimeShort(libmpv->getFileInfo()->resume).c_str()); + + ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f); + if (ImGui::Button("Yes", button_size)) + { + libmpv->seek(libmpv->getFileInfo()->resume,false); + item.popupstate = POPUP_STATE_NONE; + ImGui::CloseCurrentPopup(); + + } + ImGui::SameLine(); + if (ImGui::Button("No", button_size)) + { + + + item.popupstate = POPUP_STATE_NONE; + ImGui::CloseCurrentPopup(); + } + + } + Popups::ExitPopup(); + } + } \ No newline at end of file diff --git a/source/UI/enigmaui.cpp b/source/UI/enigmaui.cpp index 707b091..6be2203 100644 --- a/source/UI/enigmaui.cpp +++ b/source/UI/enigmaui.cpp @@ -18,7 +18,9 @@ namespace Windows { ImGui::Text("%s",enigma2->getCurrBouquet().name.c_str()); ImGui::EndMenuBar(); } - if (ImGui::BeginListBox("Enigma2 Browser Menu",ImVec2(1280.0f, 720.0f))){ + float total_w = ImGui::GetContentRegionAvail().x; + float total_h = ImGui::GetContentRegionAvail().y; + if (ImGui::BeginListBox("Enigma2 Browser Menu",ImVec2(total_w, total_h))){ if(enigma2->getCurrBouquet().bouquetref == ""){ for (unsigned int n = 0; n < enigma2->e2services.size(); n++){ static int selected = -1; @@ -43,8 +45,9 @@ namespace Windows { float currstartpos = ImGui::GetCursorPosX(); if (ImGui::Selectable(itemid.c_str(), selected == n, 0, ImVec2(0, 70))){ - const char *cmd[] = {"loadfile", enigma2->e2currbouqet[n].url.c_str(), NULL}; - mpv_command_async(libmpv->getHandle(), 0, cmd); + libmpv->loadFileLive(enigma2->e2currbouqet[n].url,enigma2->e2currbouqet[n].name); + + } ImGui::SameLine(); ImGui::SetCursorPosX(currstartpos); diff --git a/source/UI/filebrowser.cpp b/source/UI/filebrowser.cpp index 17a9a24..75a40ab 100644 --- a/source/UI/filebrowser.cpp +++ b/source/UI/filebrowser.cpp @@ -8,11 +8,11 @@ namespace Windows { - void FileBrowserWindow(bool *focus, bool first_item) { + void FileBrowserWindow(bool *focus, bool *first_item) { Windows::SetupWindow(); std::vector topmenu = {"Local Files","Network","Enigma2"}; - if (ImGui::Begin("File Browser", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_MenuBar)) { + if (ImGui::Begin("File Browser", nullptr, ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_MenuBar)) { ImGui::SetNextWindowFocus(); @@ -20,10 +20,14 @@ namespace Windows { ImGui::Text("current path: %s",localdir->getCurrentPath().c_str()); ImGui::EndMenuBar(); } - if (ImGui::BeginListBox("File Browser Menu",ImVec2(1280.0f, 720.0f))){ - int total_w = ImGui::GetContentRegionAvail().x; + float total_w = ImGui::GetContentRegionAvail().x; + float total_h = ImGui::GetContentRegionAvail().y; + if (ImGui::BeginListBox("File Browser Menu",ImVec2(total_w, total_h))){ + std::vector thislist = localdir->getCurrList(); + bool triggerselect = false; for (unsigned int n = 0; n < thislist.size(); n++){ + static int selected = -1; if(thislist[n].type == FS::FileEntryType::Directory){ @@ -33,17 +37,24 @@ namespace Windows { } ImGui::SameLine(); ImGui::SetCursorPos({ImGui::GetCursorPos().x, ImGui::GetCursorPos().y + (40 - ImGui::GetFont()->FontSize) / 2}); - if (ImGui::Selectable(thislist[n].name.c_str(), selected == n)){ + std::string itemid = "##" + std::to_string(n); + if (ImGui::Selectable(itemid.c_str(), selected == n)){ if(localdir->getCurrList()[n].type == FS::FileEntryType::Directory){ - item.first_item = true; - + triggerselect = true; localdir->DirList(thislist[n].path,true,Utility::getMediaExtensions()); } else{ - const char *cmd[] = {"loadfile", thislist[n].path.c_str(), NULL}; - mpv_command_async(libmpv->getHandle(), 0, cmd); + libmpv->loadFile(thislist[n].path); + if(configini->getDbActive(true)){ + libmpv->getFileInfo()->resume = sqlitedb->getResume(thislist[n].path); + if(libmpv->getFileInfo()->resume>0){ + item.popupstate = POPUP_STATE_RESUME; + } + } } } + ImGui::SameLine(); + ImGui::Text("%s",thislist[n].name.c_str()); if(thislist[n].type == FS::FileEntryType::File){ ImGui::SameLine(total_w-150); ImGui::Text("%s",Utility::humanSize(thislist[n].size).c_str()); @@ -52,11 +63,14 @@ namespace Windows { if (selected) ImGui::SetItemDefaultFocus(); } - if (first_item && thislist.size() >0) { - ImGui::SetFocusID(ImGui::GetID(thislist[0].name.c_str()), ImGui::GetCurrentWindow()); - ImGui::ScrollToItem(); - first_item = false; - item.first_item = false; + if (*first_item && thislist.size() >0) { + std::string itemid = "##" + std::to_string(0); + ImGui::SetFocusID(ImGui::GetID(itemid.c_str()), ImGui::GetCurrentWindow()); + ImGui::SetScrollY(0.0f); + *first_item = false; + } + if(triggerselect == true){ + *first_item = true; } } ImGui::EndListBox(); diff --git a/source/UI/infoMenu.cpp b/source/UI/infoMenu.cpp index 07ac0aa..88226fe 100644 --- a/source/UI/infoMenu.cpp +++ b/source/UI/infoMenu.cpp @@ -14,7 +14,7 @@ namespace Windows { char nxmptext[32]; char ffmpegtext[32]; char mpvtext[32]; - sprintf(nxmptext,"NXMP v%d.%d.%d",VERSION_MAJOR,VERSION_MINOR,VERSION_MICRO); + sprintf(nxmptext,"NXMP v%d.%d.%d - %s Version",VERSION_MAJOR,VERSION_MINOR,VERSION_MICRO,RELEASE_TYPE ? "Beta":"Stable"); sprintf(ffmpegtext,"FFMPEG %s",libmpv->ffmpeg_version.c_str()); sprintf(mpvtext,"MPV %s",libmpv->mpv_version.c_str()); auto windowWidth = ImGui::GetWindowSize().x; diff --git a/source/UI/mainMenu.cpp b/source/UI/mainMenu.cpp index 5e2f28d..264ef08 100644 --- a/source/UI/mainMenu.cpp +++ b/source/UI/mainMenu.cpp @@ -68,14 +68,12 @@ namespace Windows { } if(topmenu[n] == "Enigma2"){ - enigma2 = new Enigma2(); + enigma2 = new Enigma2(configini->getEnigma()); item.first_item = true; - std::string e2uri = configini->getEnigma(); - if(e2uri == ""){ + if(configini->getEnigma() == ""){ item.state = MENU_STATE_ENIGMABROWSER; }else{ - urlschema e2schema = Utility::parseUrl(e2uri); - enigma2->enigma2ip = e2schema.server; + //urlschema e2schema = Utility::parseUrl(e2uri); enigma2->getServices(); item.state = MENU_STATE_ENIGMABROWSER; } diff --git a/source/UI/networkBrowser.cpp b/source/UI/networkBrowser.cpp index 6384203..7a80d6d 100644 --- a/source/UI/networkBrowser.cpp +++ b/source/UI/networkBrowser.cpp @@ -11,7 +11,7 @@ namespace Windows { void FtpWindow(bool *focus, bool *first_item){ Windows::SetupWindow(); - if (ImGui::Begin("Ftp Browser", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_MenuBar)) { + if (ImGui::Begin("Ftp Browser", nullptr, ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_MenuBar)) { ImGui::SetNextWindowFocus(); @@ -19,10 +19,13 @@ namespace Windows { ImGui::Text("current path: %s",ftpdir->getCurrPath().c_str()); ImGui::EndMenuBar(); } - if (ImGui::BeginListBox("Ftp Browser Menu",ImVec2(1280.0f, 720.0f))){ + float total_w = ImGui::GetContentRegionAvail().x; + float total_h = ImGui::GetContentRegionAvail().y; + if (ImGui::BeginListBox("Ftp Browser Menu",ImVec2(total_w, total_h))){ //ImGui::Text("Current Dir: %s\n",item.networklastpath.c_str()); int total_w = ImGui::GetContentRegionAvail().x; std::vector thislist = ftpdir->getCurrList(); + bool triggerselect = false; for(unsigned int n=0;ngetUrl()); static int selected = -1; - if (ImGui::Selectable(thislist[n].name.c_str(), selected == n)){ + std::string itemid = "##" + std::to_string(n); + if (ImGui::Selectable(itemid.c_str(), selected == n)){ if(thislist[n].type == FS::FileEntryType::Directory){ - item.first_item = true; + triggerselect = true; ftpdir->DirList(thislist[n].path + thislist[n].name,Utility::getMediaExtensions()); }else if (thislist[n].type == FS::FileEntryType::File){ std::string openurl = thisurl.scheme + std::string("://") + thisurl.user + std::string(":") + thisurl.pass + std::string("@") + thisurl.server + std::string("/") + thislist[n].path + thislist[n].name; - const char *cmd[] = {"loadfile", openurl.c_str(), NULL}; - mpv_command_async(libmpv->getHandle(), 0, cmd); + libmpv->loadFile(openurl); + if(configini->getDbActive(true)){ + libmpv->getFileInfo()->resume = sqlitedb->getResume(openurl); + if(libmpv->getFileInfo()->resume>0){ + item.popupstate = POPUP_STATE_RESUME; + } + } + } } - + ImGui::SameLine(); + ImGui::Text("%s",thislist[n].name.c_str()); if(thislist[n].type == FS::FileEntryType::File){ ImGui::SameLine(total_w-150); ImGui::Text("%s",Utility::humanSize(thislist[n].size).c_str()); @@ -57,9 +68,14 @@ namespace Windows { } if (*first_item && thislist.size() >0) { - ImGui::SetFocusID(ImGui::GetID((thislist[0].name.c_str())), ImGui::GetCurrentWindow()); + std::string itemid = "##" + std::to_string(0); + ImGui::SetFocusID(ImGui::GetID((itemid.c_str())), ImGui::GetCurrentWindow()); + ImGui::SetScrollY(0.0f); *first_item = false; } + if(triggerselect == true){ + *first_item = true; + } } ImGui::EndListBox(); } @@ -76,8 +92,10 @@ namespace Windows { ImGui::Text("current path: %s",httpdir->getCurrPath().c_str()); ImGui::EndMenuBar(); } - if (ImGui::BeginListBox("Http Browser Menu",ImVec2(1280.0f, 720.0f))){ - //ImGui::Text("Current Dir: %s\n",item.networklastpath.c_str()); + float total_w = ImGui::GetContentRegionAvail().x; + float total_h = ImGui::GetContentRegionAvail().y; + + if (ImGui::BeginListBox("Http Browser Menu",ImVec2(total_w, total_h))){ std::vector thislist = httpdir->getCurrList(); for(unsigned int n=0;ngetUrl()); std::string openurl = thisurl.scheme + std::string("://") + thisurl.server + std::string("/") + httpdir->getCurrPath() + thislist[n].name; - const char *cmd[] = {"loadfile", openurl.c_str() , NULL}; - mpv_command_async(libmpv->getHandle(), 0, cmd); + libmpv->loadFile(openurl); + libmpv->getFileInfo()->resume = sqlitedb->getResume(openurl); + if(libmpv->getFileInfo()->resume>0){ + item.popupstate = POPUP_STATE_RESUME; + } } } - /* - if(thislist[n].type == FS::FileEntryType::File){ - ImGui::SameLine(total_w-150); - ImGui::Text("%s",Utility::humanSize(thislist[n].size).c_str()); - } - */ - + } if (*first_item && thislist.size() >0) { ImGui::SetFocusID(ImGui::GetID((thislist[0].name.c_str())), ImGui::GetCurrentWindow()); diff --git a/source/UI/playerWindows.cpp b/source/UI/playerWindows.cpp index 5cb1e54..f238209 100644 --- a/source/UI/playerWindows.cpp +++ b/source/UI/playerWindows.cpp @@ -33,45 +33,12 @@ namespace playerWindows{ static float slider_supereq[18] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; static char slider_superhz[][6] = {"65","92","131","185","262","370","523","740","1K","1.4K","2K","2.9K","4K","5.9K","8.3K","11K","16K","20K"}; - std::vector supereqpresets = {"Flat","Lowered bass","Lowered treble","Sine"}; static int supereqpresetsidx = 0; - - void superEQpresets(int presetnum){ - if(presetnum == 0){ - for (int y = 0; y < 18; y++){ - slider_supereq[y] = 1.0; - } - } - else if(presetnum == 1){ - for (int y = 0; y < 18; y++){ - if(y<7){ - slider_supereq[y] = 1.0; - }else{ - slider_supereq[y] = 3.0; - } - } - } - else if(presetnum == 2){ - for (int y = 0; y < 18; y++){ - if(y<12){ - slider_supereq[y] = 3.0; - }else{ - slider_supereq[y] = 1.0; - } - } - } - else if(presetnum == 3){ - slider_supereq[0] = 2.0;slider_supereq[1] = 3.6;slider_supereq[2] = 4.5;slider_supereq[3] = 5.5;slider_supereq[4] = 6.0;slider_supereq[5] = 6.4;slider_supereq[6] = 6.6;slider_supereq[7] = 6.4;slider_supereq[8] = 6.0;slider_supereq[9] = 5.2;slider_supereq[10] = 4.0;slider_supereq[11] = 3.2;slider_supereq[12] = 3.0;slider_supereq[13] = 3.2;slider_supereq[14] = 3.8;slider_supereq[15] = 4.5;slider_supereq[16] = 5.2;slider_supereq[17] = 6.5; - } - - libmpv->setAudioSuperEQ(slider_supereq,false); - } - - - void RightHomeWindow(bool *focus, bool *first_item){ + rightmenuposX = item.rightmenu_startpos; + if(item.rightmenu_startpos>1080)item.rightmenu_startpos-=10; playerWindows::SetupRightWindow(); std::vector topmenu = {"Tracks","Chapters","Aspect Ratio","Image","Audio","Subtitle"}; if (ImGui::Begin("Right Menu Home", nullptr, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoScrollbar)) { @@ -104,8 +71,9 @@ namespace playerWindows{ ImGui::SetFocusID(ImGui::GetID(topmenu[0].c_str()), ImGui::GetCurrentWindow()); *first_item = false; } + ImGui::EndListBox(); } - ImGui::EndListBox(); + } playerWindows::ExitWindow(); } @@ -570,8 +538,10 @@ namespace playerWindows{ ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(colorid / 7.0f, 0.9f, 0.9f)); sliderpos[y] = ImGui::GetCursorPosX(); - if(ImGui::VSliderFloat("##v", ImVec2(32,150), &slider_supereq[y], 0.0f, 10.0f, "%.1f")){ - libmpv->setAudioSuperEQ(slider_supereq,false); + std::string itemid = "##vsuperqslider" + std::to_string(y); + if(ImGui::VSliderFloat(itemid.c_str(), ImVec2(32,150), &slider_supereq[y], 0.0f, 10.0f, "%.1f")){ + libmpv->setAudioSuperEQband(slider_supereq[y],y,false); + //libmpv->setAudioSuperEQ(slider_supereq,false); } ImGui::PopStyleColor(4); ImGui::SameLine(); @@ -591,16 +561,20 @@ namespace playerWindows{ supereqpresetsidx = 0; libmpv->setAudioSuperEQ(slider_supereq,false); } - const char* combo_previewpreset_value = supereqpresets[supereqpresetsidx].c_str(); + const char* combo_previewpreset_value = eqpreset->getPresets()[supereqpresetsidx].name.c_str(); ImGui::PushItemWidth(710*0.5); ImGui::SameLine(); if (ImGui::BeginCombo("Presets", combo_previewpreset_value, 0)) { - for (int n = 0; n < supereqpresets.size(); n++) + for (int n = 0; n < eqpreset->getPresets().size(); n++) { const bool is_selected = (supereqpresetsidx == n); - if (ImGui::Selectable(supereqpresets[n].c_str(), is_selected)){ - superEQpresets(n); + + if (ImGui::Selectable(eqpreset->getPresets()[n].name.c_str(), is_selected)){ + for(int y=0;y<18;y++){ + slider_supereq[y] = eqpreset->getPresets()[n].eqvals[y]; + } + libmpv->setAudioSuperEQ(slider_supereq,false); supereqpresetsidx = n; } if (is_selected) @@ -620,7 +594,7 @@ namespace playerWindows{ auto windowheight = ImGui::GetWindowSize().y; ImGui::SetCursorPosX((windowWidth - ImGui::CalcTextSize("Buffering Media...", NULL, true).x) * 0.5f); ImGui::SetCursorPosY((windowheight - 24) * 0.5f); - ImGui::Text("Buffering Media..."); + ImGui::Text("Buffering Media %c","|/-\\"[(int)(ImGui::GetTime() / 0.05f) & 3]); } playerWindows::ExitWindow(); } @@ -634,6 +608,110 @@ namespace playerWindows{ ImGui::SetCursorPosY((windowheight - 24) * 0.5f); ImGui::Text("Audio Playback"); + } + playerWindows::ExitWindow(); + } + + void playerControls(){ + playerWindows::SetupPlayerControlsWindow(); + static bool selected = -1; + if (ImGui::Begin("Player Controls", nullptr, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoScrollbar)) { + + float centerposition = ImGui::GetWindowSize().x*0.5; + + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(1.0,1.0,1.0,0.2)); + ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(1.0,1.0,1.0,1.0)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 12.0f); + ImGui::ProgressBar(libmpv->getFileInfo()->playbackInfo.getplayPerc(), ImVec2(-1.0f, 10.0f),""); + ImGui::PopStyleColor(2); + ImGui::PopStyleVar(); + ImGui::SetCursorPosX(centerposition-90); + ImGui::SetCursorPosY(ImGui::GetCursorPosY()+5.0f); + + + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.0,0.0,0.0,0.0)); + if (ImGui::Selectable("##Play", selected == 0,0,ImVec2(60, 60))){ + if(libmpv->Paused()){ + libmpv->Resume(); + }else{ + libmpv->Pause(); + } + } + ImGui::PopStyleColor(); + ImGui::SameLine(); + ImGui::SetCursorPosX(centerposition-90); + if(libmpv->Paused()){ + ImGui::Image((void*)(intptr_t)PlayIcon.id, ImVec2(60,60)); + }else{ + ImGui::Image((void*)(intptr_t)PauseIcon.id, ImVec2(60,60)); + } + ImGui::SameLine(); + ImGui::SetCursorPosX(centerposition+20); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.0,0.0,0.0,0.0)); + if (ImGui::Selectable("##Stop", selected == 0,0,ImVec2(60, 60))){ + libmpv->Stop(); + } + ImGui::PopStyleColor(); + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetWindowSize().x-100.0f); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.0,0.0,0.0,0.0)); + if (ImGui::Selectable("##Mute", selected == 0,0,ImVec2(60, 60))){ + libmpv->toggleMute(); + printf("MUTE: %d\n",libmpv->getMute()); + } + ImGui::PopStyleColor(); + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetWindowSize().x-100.0f); + if(libmpv->getMute()){ + ImGui::Image((void*)(intptr_t)MuteIcon.id, ImVec2(60,60)); + }else{ + ImGui::Image((void*)(intptr_t)VolumeIcon.id, ImVec2(60,60)); + } + + ImGui::SameLine(); + ImGui::SetCursorPosX(centerposition+20); + ImGui::Image((void*)(intptr_t)StopIcon.id, ImVec2(60,60)); + ImGui::SameLine(); + + ImGui::SetCursorPosX(centerposition+(centerposition*0.5)); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.0,0.0,0.0,0.0)); + if (ImGui::Selectable("##Loop", selected == 0,0,ImVec2(60, 60))){ + libmpv->setLoop(!libmpv->getLoop()); + } + ImGui::PopStyleColor(); + ImGui::SameLine(); + ImGui::SetCursorPosX(centerposition+(centerposition*0.5)); + if(libmpv->getLoop()){ + ImGui::Image((void*)(intptr_t)LoopIcon.id, ImVec2(60,60)); + }else{ + ImGui::Image((void*)(intptr_t)NoLoopIcon.id, ImVec2(60,60)); + } + ImGui::SameLine(); + + ImGui::PushFont(fontSmall); + ImGui::SetCursorPosX(20); + ImGui::SetCursorPosY(ImGui::GetCursorPosY()+10.0); + if(libmpv->getFileInfo()->playbackInfo.title ==""){ + ImGui::Text("%s",Utility::truncateLen(FS::getFilefromPath(libmpv->getFileInfo()->path),63).c_str()); + }else{ + if(libmpv->getFileInfo()->playbackInfo.artist ==""){ + ImGui::Text("%s",Utility::truncateLen(libmpv->getFileInfo()->playbackInfo.title.c_str(),63).c_str()); + }else{ + std::string titleandartist = libmpv->getFileInfo()->playbackInfo.title + std::string(" - ") + libmpv->getFileInfo()->playbackInfo.artist; + ImGui::Text("%s",Utility::truncateLen(titleandartist,63).c_str()); + } + } + ImGui::SetCursorPosX(20); + ImGui::SetCursorPosY(ImGui::GetCursorPosY()-40.0f); + char timetext[64]; + sprintf(timetext,"%s - %s",Utility::formatTimeShort(libmpv->getFileInfo()->playbackInfo.position).c_str(),Utility::formatTimeShort(libmpv->getFileInfo()->playbackInfo.duration).c_str()); + ImGui::SetCursorPosX(20); + ImGui::Text("%s",timetext); + ImGui::PopFont(); + + + + } playerWindows::ExitWindow(); } diff --git a/source/UI/settingsMenu.cpp b/source/UI/settingsMenu.cpp index 4a4205c..e09cd45 100644 --- a/source/UI/settingsMenu.cpp +++ b/source/UI/settingsMenu.cpp @@ -104,7 +104,79 @@ namespace Windows { ImGui::PopItemWidth(); ImGui::EndTabItem(); } - ImGui::EndTabBar(); + if (ImGui::BeginTabItem("Database")) { + bool usedbbool = configini->getDbActive(true); + if(ImGui::Checkbox("Use Database", &usedbbool)){ + if(sqlitedb != nullptr){ + delete sqlitedb; + sqlitedb = nullptr; + } + if(usedbbool){ + sqlitedb = new SQLiteDB("nxmp.db"); + } + configini->setDbActive(usedbbool); + + } + if(sqlitedb != nullptr){ + if(sqlitedb->getCorrupted()){ + ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f),"Database File Corrupted"); + }else{ + ImGui::Text("Database File Version: "); + ImGui::SameLine(); + ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f),sqlitedb->getDbVersion().c_str()); + } + ImGui::Text("SQLite Version: "); + ImGui::SameLine(); + ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f),sqlitedb->getSQLiteVersion().c_str()); + + + ImGui::SetCursorPosY(ImGui::GetCursorPosY()+50); + ImGui::Text("Start saving resume info @ "); + ImGui::SameLine(300,spacing); + ImGui::PushButtonRepeat(true); + if (ImGui::ArrowButton("##resumestartleft", ImGuiDir_Left)) { + if(configini->getResumeStartPerc(true)-1 >0){ + configini->setResumeStartPerc(configini->getResumeStartPerc(true)-1); + } + } + ImGui::SameLine(0.0f, spacing); + if (ImGui::ArrowButton("##resumestartright", ImGuiDir_Right)) { + configini->setResumeStartPerc(configini->getResumeStartPerc(true)+1); + } + ImGui::PopButtonRepeat(); + ImGui::SameLine(); + ImGui::Text("%d%%", configini->getResumeStartPerc(true)); + + + ImGui::Text("Stop saving resume info @ "); + ImGui::SameLine(300,spacing); + ImGui::PushButtonRepeat(true); + if (ImGui::ArrowButton("##resumestopleft", ImGuiDir_Left)) { + if(configini->getResumeStopPerc(true)-1 >0){ + configini->setResumeStopPerc(configini->getResumeStopPerc(true)-1); + } + } + ImGui::SameLine(0.0f, spacing); + if (ImGui::ArrowButton("##resumestopright", ImGuiDir_Right)) { + if(configini->getResumeStopPerc(true)+1 <=100){ + configini->setResumeStopPerc(configini->getResumeStopPerc(true)+1); + } + } + ImGui::PopButtonRepeat(); + ImGui::SameLine(); + ImGui::Text("%d%%", configini->getResumeStopPerc(true)); + + + + }else{ + ImGui::Text("Database not active"); + } + + + + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); } ImGui::SetCursorPosX(ImGui::GetWindowSize().x/2); diff --git a/source/UI/usbBrowser.cpp b/source/UI/usbBrowser.cpp index 28a86fc..e72c37a 100644 --- a/source/UI/usbBrowser.cpp +++ b/source/UI/usbBrowser.cpp @@ -10,24 +10,24 @@ namespace Windows { void USBBrowserWindow(bool *focus, bool *first_item) { Windows::SetupWindow(); - if (ImGui::Begin("USB Browser", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_MenuBar)) { + if (ImGui::Begin("USB Browser", nullptr, ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_MenuBar)) { #ifdef __SWITCH__ ImGui::SetNextWindowFocus(); if(item.usbpath == ""){ - - if (ImGui::BeginListBox("USB Browser Menu",ImVec2(1280.0f, 720.0f))){ - int total_w = ImGui::GetContentRegionAvail().x; + float total_w = ImGui::GetContentRegionAvail().x; + float total_h = ImGui::GetContentRegionAvail().y; + if (ImGui::BeginListBox("USB Browser Menu",ImVec2(total_w, total_h))){ + bool triggerselect = false; static int selected = -1; std::vector thislist = usbmounter->mounted_devs; for (unsigned int n = 0; n < thislist.size(); n++){ std::string itemid = "##" + std::to_string(n); ImGui::SameLine(); - //float currstartpos = ImGui::GetCursorPosX(); if (ImGui::Selectable(itemid.c_str(), selected == n,0, ImVec2(0, 60))){ item.usbpath = thislist[n].mount_point + std::string("/"); item.usbbasepath = item.usbpath; item.usbfileentries = FS::getDirList(item.usbpath.c_str(),true,Utility::getMediaExtensions()); - item.first_item = true; + triggerselect = true; } ImGui::SameLine(); float currstartYpos = ImGui::GetCursorPosY(); @@ -36,7 +36,6 @@ namespace Windows { ImGui::SameLine(); ImGui::SetCursorPosY(currstartYpos); float currstartXpos = ImGui::GetCursorPosX(); - //ImGui::SetCursorPosX(currstartpos); std::string devname = Utility::trim(usbmounter->mounted_devs[n].name) + std::string(" -> ") + usbmounter->mounted_devs[n].mount_point; ImGui::Text("%s",devname.c_str()); ImGui::SetCursorPosY(ImGui::GetCursorPosY()-30.0f); @@ -52,10 +51,17 @@ namespace Windows { ImGui::SetFocusID(ImGui::GetID(itemid.c_str()), ImGui::GetCurrentWindow()); *first_item = false; } + if(triggerselect == true){ + *first_item = true; + } } ImGui::EndListBox(); }else{ - if (ImGui::BeginListBox("USB Browser Menu",ImVec2(1280.0f, 720.0f))){ + float total_w = ImGui::GetContentRegionAvail().x; + float total_h = ImGui::GetContentRegionAvail().y; + + if (ImGui::BeginListBox("USB Browser Menu",ImVec2(total_w, total_h))){ + bool triggerselect = false; int total_w = ImGui::GetContentRegionAvail().x; static int selected = -1; std::vector thislist = item.usbfileentries; @@ -67,19 +73,26 @@ namespace Windows { } ImGui::SameLine(); ImGui::SetCursorPos({ImGui::GetCursorPos().x, ImGui::GetCursorPos().y + (40 - ImGui::GetFont()->FontSize) / 2}); - - if (ImGui::Selectable(thislist[n].name.c_str(), selected == n)){ + std::string itemid = "##" + std::to_string(n); + if (ImGui::Selectable(itemid.c_str(), selected == n)){ if(thislist[n].type == FS::FileEntryType::Directory){ item.usbpath = item.usbfileentries[n].path; item.usbfileentries = FS::getDirList(item.usbpath.c_str(),true,Utility::getMediaExtensions()); - item.first_item = true; + triggerselect = true; }else if(thislist[n].type == FS::FileEntryType::File){ - const char *cmd[] = {"loadfile", thislist[n].path.c_str(), NULL}; - mpv_command_async(libmpv->getHandle(), 0, cmd); + libmpv->loadFile(thislist[n].path); + if(configini->getDbActive(true)){ + libmpv->getFileInfo()->resume = sqlitedb->getResume(thislist[n].path); + if(libmpv->getFileInfo()->resume>0){ + item.popupstate = POPUP_STATE_RESUME; + } + } } } + ImGui::SameLine(); + ImGui::Text("%s",thislist[n].name.c_str()); if(thislist[n].type == FS::FileEntryType::File){ ImGui::SameLine(total_w-150); @@ -91,9 +104,14 @@ namespace Windows { ImGui::SetItemDefaultFocus(); } if (*first_item && thislist.size() >0) { - ImGui::SetFocusID(ImGui::GetID(thislist[0].name.c_str()), ImGui::GetCurrentWindow()); + std::string itemid = "##" + std::to_string(0); + ImGui::SetFocusID(ImGui::GetID(itemid.c_str()), ImGui::GetCurrentWindow()); + ImGui::SetScrollY(0.0f); *first_item = false; } + if(triggerselect == true){ + *first_item = true; + } } ImGui::EndListBox(); } diff --git a/source/config.cpp b/source/config.cpp index b870933..c972c4e 100644 --- a/source/config.cpp +++ b/source/config.cpp @@ -64,6 +64,23 @@ Config::Config(std::string inifile){ deint = tmpdeint; + const char* usedbpv; + usedbpv = ini->GetValue("Main", "usedb"); + dbactive = false; + if(usedbpv!= nullptr){ + std::string usebdstring = usedbpv; + if(usebdstring == "yes")dbactive=true; + } + tmpdbactive = dbactive; + + startresumeperc = ini->GetLongValue("Main", "startresumeperc"); + stopresumeperc = ini->GetLongValue("Main", "stopresumeperc"); + if(startresumeperc == 0)startresumeperc = 5; + if(stopresumeperc == 0)stopresumeperc = 5; + tmpstartresumeperc = startresumeperc; + tmpstopresumeperc = stopresumeperc; + + topmenu.push_back("Local Files"); topmenu.push_back("USB"); @@ -177,11 +194,47 @@ int Config::getDeinterlace(bool tmpvalue){ return deint; } + +bool Config::getDbActive(bool tmpvalue){ + if(tmpvalue){ + return tmpdbactive; + } + return dbactive; +} + +void Config::setDbActive(bool value){ + tmpdbactive = value; +} + +int Config::getResumeStartPerc(bool tmpvalue){ + if(tmpvalue){ + return tmpstartresumeperc; + } + return startresumeperc; +} +void Config::setResumeStartPerc(int value){ + tmpstartresumeperc = value; +} + +int Config::getResumeStopPerc(bool tmpvalue){ + if(tmpvalue){ + return tmpstopresumeperc; + } + return stopresumeperc; +} +void Config::setResumeStopPerc(int value){ + tmpstopresumeperc = value; +} + void Config::saveSettings(){ longseek = tmplongseek; shortseek = tmpshortseek; usealang = tmpusealang; deint = tmpdeint; + dbactive = tmpdbactive; + + startresumeperc = tmpstartresumeperc; + stopresumeperc = tmpstopresumeperc; ini->Delete("Main", "shortseek"); ini->SetLongValue("Main", "shortseek", shortseek, NULL, false); @@ -196,6 +249,14 @@ void Config::saveSettings(){ std::vector deintopts = {"no","yes","auto"}; ini->Delete("Main", "deinterlace"); ini->SetValue("Main", "deinterlace", deintopts[deint].c_str()); + std::vector usedbintopts = {"no","yes"}; + ini->Delete("Main", "usedb"); + ini->SetValue("Main", "usedb", usedbintopts[dbactive].c_str()); + + ini->Delete("Main", "startresumeperc"); + ini->SetLongValue("Main", "startresumeperc", startresumeperc, NULL, false); + ini->Delete("Main", "stopresumeperc"); + ini->SetLongValue("Main", "stopresumeperc", stopresumeperc, NULL, false); std::string data; ini->Save(data); ini->SaveFile(inifilePath.c_str()); diff --git a/source/database/SQLiteDB.cpp b/source/database/SQLiteDB.cpp new file mode 100644 index 0000000..2d3c034 --- /dev/null +++ b/source/database/SQLiteDB.cpp @@ -0,0 +1,241 @@ +#include "SQLiteDB.h" + + +SQLiteDB::SQLiteDB(std::string _filename){ + dbfilename = _filename; + sqlite3_stmt *res; + bool haveversion = false; + int rc = sqlite3_open(":memory:",&db); + loadOrSaveDb(db,_filename.c_str(),0); + + if (rc != SQLITE_OK ) { + printf("Error Opening DB\n"); + } + char *err_msg = 0; + + sqlite3_extended_result_codes(db, 1); + + /* + rc = sqlite3_exec(db, "PRAGMA journal_mode=MEMORY;", 0, 0, 0); + if (rc != SQLITE_OK ) { + printf("failed to set journal_mode\n"); + } + rc = sqlite3_exec(db, "PRAGMA foreign_keys=ON;", 0, 0, 0); + if (rc != SQLITE_OK ) { + printf("failed to set journal_mode\n"); + } + + */ + char sqlversion[] = "SELECT sqlite_version();"; + rc = sqlite3_prepare_v2(db, sqlversion, -1, &res, NULL); + rc = sqlite3_step(res); + if (rc == SQLITE_ROW) { + sqliteversion = (char *)sqlite3_column_text(res,0); + } + + sqlite3_finalize(res); + + char sql[] = "CREATE TABLE IF NOT EXISTS NXMP(major INTEGER, minor INTEGER, micro INTEGER);"; + rc = sqlite3_exec(db, sql, 0, 0, &err_msg); + if (rc != SQLITE_OK ) { + + } + char sqlfileresume[] = "CREATE TABLE IF NOT EXISTS FILERESUME(Id INTEGER PRIMARY KEY AUTOINCREMENT , Path TEXT, Position INTEGER);"; + rc = sqlite3_exec(db, sqlfileresume, 0, 0, &err_msg); + if (rc == SQLITE_ROW) { + dbmajor = sqlite3_column_int(res, 0); + dbminor = sqlite3_column_int(res, 1); + dbmicro = sqlite3_column_int(res, 2); + printf("File DB Version %d.%d.%d\n", dbmajor,dbminor,dbmicro); + haveversion = true; + } + + + + rc = sqlite3_prepare_v2(db, "SELECT * from NXMP", -1, &res, NULL); + if (rc != SQLITE_OK) { + + } + rc = sqlite3_step(res); + + + if (rc == SQLITE_ROW) { + dbmajor = sqlite3_column_int(res, 0); + dbminor = sqlite3_column_int(res, 1); + dbmicro = sqlite3_column_int(res, 2); + printf("File DB Version %d.%d.%d\n", dbmajor,dbminor,dbmicro); + haveversion = true; + } + sqlite3_finalize(res); + + if(!haveversion){ + char sqlquery[64]; + sprintf(sqlquery,"INSERT INTO NXMP VALUES(%d, %d, %d)",VERSION_MAJOR,VERSION_MINOR,VERSION_MICRO); + rc = sqlite3_exec(db, sqlquery, 0, 0, &err_msg); + + if (rc != SQLITE_OK ) { + dbcorrupted = true; + printf("Error Insert %s\n",err_msg); + + } + if( rc == SQLITE_OK){ + dbmajor = VERSION_MAJOR; + dbminor = VERSION_MINOR; + dbmicro = VERSION_MICRO; + } + } + +} + +SQLiteDB::~SQLiteDB(){ + loadOrSaveDb(db,dbfilename.c_str(),1); + sqlite3_close(db); + +} + +bool SQLiteDB::haveResume(std::string path){ + + std::string sqlquery = "SELECT * from FILERESUME WHERE Path="; + sqlquery.append("\""); + sqlquery.append(path); + sqlquery.append("\""); + + sqlite3_stmt *res; + int rc = sqlite3_prepare_v2(db, sqlquery.c_str(), -1, &res, NULL); + if (rc != SQLITE_OK) { + + } + rc = sqlite3_step(res); + + bool _haveresume = false; + if (rc == SQLITE_ROW) { + _haveresume = true; + } + sqlite3_finalize(res); + return _haveresume; +} + +void SQLiteDB::writeResume(std::string path,int64_t position){ + if(haveResume(path)){ + updateResume(path,position); + }else{ + newResume(path,position); + } +} + + +void SQLiteDB::newResume(std::string path,int64_t position){ + char sqlquery[2048]; + char *err_msg = 0; + sprintf(sqlquery,"INSERT INTO FILERESUME (Path,Position) VALUES(\"%s\",%lld);",path.c_str(),position); + printf("INSERT: %s\n",sqlquery); + int rc = sqlite3_exec(db, sqlquery, 0, 0, &err_msg); + if (rc != SQLITE_OK) { + printf("DB Error: %s\n",err_msg); + } +} + +void SQLiteDB::updateResume(std::string path,int64_t position){ + char sqlquery[2048]; + char *err_msg = 0; + sprintf(sqlquery,"UPDATE FILERESUME set Position = %lld WHERE Path = \"%s\"",position,path.c_str()); + printf("UPDATE: %s\n",sqlquery); + int rc = sqlite3_exec(db, sqlquery, 0, 0, &err_msg); + if (rc != SQLITE_OK) { + printf("DB Error: %s\n",err_msg); + } +} + +int64_t SQLiteDB::getResume(std::string path){ + if(haveResume(path)){ + sqlite3_stmt *res; + char sqlquery[2048]; + sprintf(sqlquery,"SELECT * from FILERESUME WHERE Path = \"%s\"",path.c_str()); + int rc = sqlite3_prepare_v2(db, sqlquery, -1, &res, NULL); + rc = sqlite3_step(res); + if (rc == SQLITE_ROW) { + return sqlite3_column_int(res, 2); + } + sqlite3_finalize(res); + } + return 0; +} + +void SQLiteDB::deleteResume(std::string path){ + if(haveResume(path)){ + char sqlquery[2048]; + char *err_msg = 0; + sprintf(sqlquery,"DELETE FROM FILERESUME WHERE Path = \"%s\"",path.c_str()); + int rc = sqlite3_exec(db, sqlquery, 0, 0, &err_msg); + if (rc != SQLITE_OK) { + printf("DB Entry Delete Error: %s\n",err_msg); + } + + } +} + +std::string SQLiteDB::getDbVersion(){ + + char outver[32]; + sprintf(outver,"v%d.%d.%d", dbmajor,dbminor,dbmicro); + + return outver; +} + +std::string SQLiteDB::getSQLiteVersion(){ + return sqliteversion; +} + +bool SQLiteDB::getCorrupted(){ + return dbcorrupted; +} + +// code taken from https://stackoverflow.com/questions/1437327/saving-to-disk-an-in-memory-database + +int SQLiteDB::loadOrSaveDb(sqlite3 *pInMemory, const char *zFilename, int isSave) +{ + int rc; /* Function return code */ + sqlite3 *pFile; /* Database connection opened on zFilename */ + sqlite3_backup *pBackup; /* Backup object used to copy data */ + sqlite3 *pTo; /* Database to copy to (pFile or pInMemory) */ + sqlite3 *pFrom; /* Database to copy from (pFile or pInMemory) */ + + +#ifdef __SWITCH__ + rc = sqlite3_open_v2(zFilename,&pFile,SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,"unix-dotfile"); +#endif +#ifdef _WIN32 + rc = sqlite3_open_v2(zFilename,&pFile,SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,"win32"); +#endif + if (rc == SQLITE_OK) + { + + rc = sqlite3_exec(pFile, "PRAGMA journal_mode=MEMORY;", 0, 0, 0); + if (rc != SQLITE_OK ) { + printf("failed to set journal_mode\n"); + } + rc = sqlite3_exec(pFile, "PRAGMA foreign_keys=ON;", 0, 0, 0); + if (rc != SQLITE_OK ) { + printf("failed to set journal_mode\n"); + } + + pFrom = (isSave ? pInMemory : pFile); + pTo = (isSave ? pFile : pInMemory); + + pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main"); + if (pBackup) { + int rcstep = sqlite3_backup_step(pBackup, -1); + printf("RC STEP:%d\n",rcstep); + int rcfinish = sqlite3_backup_finish(pBackup); + printf("RC FINISH:%d\n",rcstep); + } + rc = sqlite3_errcode(pTo); + printf("pTO Errocode %d\n",rc); + }else{ + printf("Error Opening File Database\n"); + } + + (void)sqlite3_close(pFile); + return rc; +} + diff --git a/source/database/SQLiteDB.h b/source/database/SQLiteDB.h new file mode 100644 index 0000000..ee716e0 --- /dev/null +++ b/source/database/SQLiteDB.h @@ -0,0 +1,36 @@ +#ifndef NXMP_SQLITEDB_H +#define NXMP_SQLITEDB_H + +#include +#include + +class SQLiteDB{ +public: + SQLiteDB(std::string _filename); + ~SQLiteDB(); + + bool haveResume(std::string path); + void writeResume(std::string path,int64_t position); + void deleteResume(std::string path); + void newResume(std::string path,int64_t position); + void updateResume(std::string path,int64_t position); + int64_t getResume(std::string path); + std::string getDbVersion(); + std::string getSQLiteVersion(); + bool getCorrupted(); + + int loadOrSaveDb(sqlite3 *pInMemory, const char *zFilename, int isSave); + +private: + + + bool dbcorrupted = false; + int dbmajor; + int dbminor; + int dbmicro; + std::string dbfilename; + std::string sqliteversion; + sqlite3 *db; +}; + +#endif \ No newline at end of file diff --git a/source/eqpreset/eqpreset.cpp b/source/eqpreset/eqpreset.cpp new file mode 100644 index 0000000..a2d9719 --- /dev/null +++ b/source/eqpreset/eqpreset.cpp @@ -0,0 +1,41 @@ +#include "eqpreset.h" + +EQPreset::EQPreset(std::string _filename){ + presetsfilePath = _filename; + ini = new CSimpleIniA(true,true); + ini->SetUnicode(); + ini->LoadFile(_filename.c_str()); + + + CSimpleIniA::TNamesDepend sections; + ini->GetAllSections(sections); + + CSimpleIniA::TNamesDepend::const_iterator it; + int i; + preset_struct tmp_presetdefault; + tmp_presetdefault.name = "Flat (Default)"; + for(int y=0;y<18;y++){ + tmp_presetdefault.eqvals[y] = 1.0; + } + presets.push_back(tmp_presetdefault); + for (i = 0, it = sections.begin(); it != sections.end(); ++i, ++it) { + preset_struct tmp_preset; + tmp_preset.name = it->pItem; + for(int y=0;y<18;y++){ + char tmpkey[12]; + sprintf(tmpkey,"f%d",y); + std::string tmpf = ini->GetValue(it->pItem,tmpkey); + tmp_preset.eqvals[y] = std::stof(tmpf); + + } + presets.push_back(tmp_preset); + } +} + +std::vector EQPreset::getPresets(){ + return presets; +} + +float * EQPreset::getPresetNum(int presetidx){ + return presets[presetidx].eqvals; +} \ No newline at end of file diff --git a/source/eqpreset/eqpreset.h b/source/eqpreset/eqpreset.h new file mode 100644 index 0000000..8ec1e6b --- /dev/null +++ b/source/eqpreset/eqpreset.h @@ -0,0 +1,30 @@ +#ifndef NXMP_EQPRESET_H +#define NXMP_EQPRESET_H + +#include +#include +#include "SimpleIni.h" + +class EQPreset{ + +struct preset_struct{ + std::string name; + float eqvals[18]; +}; + +public: + EQPreset(std::string _filename); + + std::vector getPresets(); + float * getPresetNum(int presetidx); + +private: + CSimpleIniA *ini; + std::string presetsfilePath; + std::vector presets; + +}; + + + +#endif \ No newline at end of file diff --git a/source/gui.cpp b/source/gui.cpp index 274e029..fba81ab 100644 --- a/source/gui.cpp +++ b/source/gui.cpp @@ -64,24 +64,43 @@ namespace GUI { #ifndef __SWITCH__ if (event.type == SDL_KEYDOWN) { Uint8 keycode = event.key.keysym.sym; + //printf("Key code :%d\n",keycode); if(keycode == SDLK_ESCAPE){ SDL_Event sdlevent; sdlevent.type = SDL_JOYBUTTONDOWN; sdlevent.jbutton.button = SDL_KEY_PLUS; SDL_PushEvent(&sdlevent); } - if(keycode == SDLK_m){ + if(keycode == 79){ SDL_Event sdlevent; sdlevent.type = SDL_JOYBUTTONDOWN; sdlevent.jbutton.button = SDL_KEY_DRIGHT; SDL_PushEvent(&sdlevent); } - if(keycode == SDLK_n){ + if(keycode == 80){ SDL_Event sdlevent; sdlevent.type = SDL_JOYBUTTONDOWN; sdlevent.jbutton.button = SDL_KEY_DLEFT; SDL_PushEvent(&sdlevent); } + if(keycode == 82){ + SDL_Event sdlevent; + sdlevent.type = SDL_JOYBUTTONDOWN; + sdlevent.jbutton.button = SDL_KEY_DUP; + SDL_PushEvent(&sdlevent); + } + if(keycode == 81){ + SDL_Event sdlevent; + sdlevent.type = SDL_JOYBUTTONDOWN; + sdlevent.jbutton.button = SDL_KEY_DDOWN; + SDL_PushEvent(&sdlevent); + } + if(keycode == 32){ + SDL_Event sdlevent; + sdlevent.type = SDL_JOYBUTTONDOWN; + sdlevent.jbutton.button = SDL_KEY_A; + SDL_PushEvent(&sdlevent); + } if(keycode == SDLK_y){ SDL_Event sdlevent; sdlevent.type = SDL_JOYBUTTONDOWN; @@ -119,10 +138,13 @@ namespace GUI { SDL_PushEvent(&sdlevent); } if(keycode == SDLK_t){ - mpv_set_option_string(libmpv->getHandle(), "gpu-nxmp-deint", "0"); + //mpv_set_option_string(libmpv->getHandle(), "gpu-nxmp-deint", "0"); + //mpv_set_option_string(libmpv->getHandle(), "glsl-shader", "C:\\Users\\Ceco\\C-Dev\\imgui-test\\mpv\\shaders\\test.hook"); + mpv_command_string(libmpv->getHandle(),"no-osd change-list glsl-shaders set C:\\Users\\Ceco\\C-Dev\\imgui-test\\mpv\\shaders\\scale.glsl"); } if(keycode == SDLK_e){ - mpv_set_option_string(libmpv->getHandle(), "gpu-nxmp-deint", "1"); + mpv_command_string(libmpv->getHandle(),"no-osd change-list glsl-shaders clr \"\""); + //mpv_set_option_string(libmpv->getHandle(), "gpu-nxmp-deint", "1"); } } @@ -133,27 +155,41 @@ namespace GUI { if (button == SDL_KEY_PLUS && !item.masterlock) renderloopdone = true; + if (button == SDL_KEY_DUP){ + if(item.state == MENU_STATE_PLAYER && !item.masterlock && item.rightmenustate == PLAYER_RIGHT_MENU_PLAYER && item.popupstate == POPUP_STATE_NONE){ + + } + } + + if (button == SDL_KEY_DDOWN){ + if(item.state == MENU_STATE_PLAYER && !item.masterlock && item.rightmenustate == PLAYER_RIGHT_MENU_PLAYER && item.popupstate == POPUP_STATE_NONE){ + if(item.playercontrolstate == PLAYER_CONTROL_STATE_NONE){ + item.playercontrolstate = PLAYER_CONTROL_STATE_CONTROLS; + }else{ + item.playercontrolstate = PLAYER_CONTROL_STATE_NONE; + } + } + } + if (button == SDL_KEY_DRIGHT){ - if(item.state == MENU_STATE_PLAYER && !item.masterlock){ + if(item.state == MENU_STATE_PLAYER && !item.masterlock && item.playercontrolstate != PLAYER_CONTROL_STATE_CONTROLS && item.popupstate == POPUP_STATE_NONE){ if(item.rightmenustate == PLAYER_RIGHT_MENU_PLAYER){ if(item.rightmenustate != PLAYER_RIGHT_MENU_CUSTOMARATIO && item.rightmenustate != PLAYER_RIGHT_MENU_IMAGE && item.rightmenustate != PLAYER_RIGHT_MENU_AUDIO && item.rightmenustate != PLAYER_RIGHT_MENU_SUB && item.rightmenustate != PLAYER_AUDIOEQ && item.rightmenustate != PLAYER_SUPERAUDIOEQ){ item.rightmenustate = PLAYER_RIGHT_MENU_HOME; } - } - } - } - - if (button == SDL_KEY_DLEFT){ - if(item.state == MENU_STATE_PLAYER && !item.masterlock){ - if(item.rightmenustate != PLAYER_RIGHT_MENU_PLAYER){ + }else if(item.rightmenustate != PLAYER_RIGHT_MENU_PLAYER){ if(item.rightmenustate != PLAYER_RIGHT_MENU_CUSTOMARATIO && item.rightmenustate != PLAYER_RIGHT_MENU_IMAGE && item.rightmenustate != PLAYER_RIGHT_MENU_AUDIO && item.rightmenustate != PLAYER_RIGHT_MENU_SUB && item.rightmenustate != PLAYER_AUDIOEQ && item.rightmenustate != PLAYER_SUPERAUDIOEQ){ item.rightmenustate = PLAYER_RIGHT_MENU_PLAYER; + item.rightmenu_startpos = 1280.0f; } - } } } + if (button == SDL_KEY_DLEFT){ + + } + if (button == SDL_KEY_RSTICK){ if(item.state == MENU_STATE_PLAYER){ toggleMasterLock(); @@ -206,7 +242,7 @@ namespace GUI { } if (button == SDL_KEY_A){ if(item.state == MENU_STATE_PLAYER){ - if(item.rightmenustate == PLAYER_RIGHT_MENU_PLAYER){ + if(item.rightmenustate == PLAYER_RIGHT_MENU_PLAYER && item.playercontrolstate == PLAYER_CONTROL_STATE_NONE && item.popupstate == POPUP_STATE_NONE){ if(libmpv->Paused()){ libmpv->Resume(); }else{ @@ -286,7 +322,7 @@ namespace GUI { } if(item.state == MENU_STATE_PLAYER || item.state == MENU_STATE_PLAYERCACHING){ - if(item.rightmenustate == PLAYER_RIGHT_MENU_PLAYER){ + if(item.rightmenustate == PLAYER_RIGHT_MENU_PLAYER && item.playercontrolstate == PLAYER_CONTROL_STATE_NONE){ if(!libmpv->Stopped() && !item.masterlock){ item.state = item.laststate; @@ -333,30 +369,36 @@ namespace GUI { } if (event.type == wakeup_on_mpv_events) { - int count = 20; - while (count) { + while (1) { mpv_event *mp_event = (mpv_event*) mpv_wait_event(libmpv->getHandle(), 0); if (mp_event->event_id == MPV_EVENT_NONE) break; if (mp_event->event_id == MPV_EVENT_LOG_MESSAGE) { mpv_event_log_message *msg = (mpv_event_log_message *) mp_event->data; - if (strstr(msg->text, "DR image")) - printf("log: %s", msg->text); continue; } if (mp_event->event_id == MPV_EVENT_FILE_LOADED) { libmpv->getfileInfo(); item.state = MENU_STATE_PLAYER; - if(libmpv->getFileInfo()->videos.size() == 0){ - item.playerstate = PLAYER_STATE_AUDIO; + if(libmpv->getFileInfo()->videos.size() == 0 || (libmpv->getFileInfo()->videos.size() == 1 && libmpv->getFileInfo()->videos[0].albumart) ){ + item.playerstate = PLAYER_STATE_AUDIO; + mpv_observe_property(libmpv->getHandle(), 0, "playback-time", MPV_FORMAT_DOUBLE); + mpv_observe_property(libmpv->getHandle(), 0, "duration", MPV_FORMAT_DOUBLE); + mpv_observe_property(libmpv->getHandle(), 0, "metadata", MPV_FORMAT_NODE); + item.playercontrolstate = PLAYER_CONTROL_STATE_CONTROLS; + }else{ - item.playerstate = PLAYER_STATE_VIDEO; + mpv_observe_property(libmpv->getHandle(), 0, "playback-time", MPV_FORMAT_DOUBLE); + mpv_observe_property(libmpv->getHandle(), 0, "duration", MPV_FORMAT_DOUBLE); + mpv_observe_property(libmpv->getHandle(), 0, "metadata", MPV_FORMAT_NODE); + item.playerstate = PLAYER_STATE_VIDEO; } } + if (mp_event->event_id == MPV_EVENT_START_FILE) { #ifdef __SWITCH__ appletSetMediaPlaybackState(true); -#endif +#endif printf("START FILE\n"); item.laststate = item.state; item.state = MENU_STATE_PLAYERCACHING; @@ -365,16 +407,68 @@ namespace GUI { if (mp_event->event_id == MPV_EVENT_END_FILE) { #ifdef __SWITCH__ appletSetMediaPlaybackState(false); -#endif - printf("END FILE\n"); +#endif + struct mpv_event_end_file *eof = (struct mpv_event_end_file *)mp_event->data; + libmpv->setLoop(false); + if(item.playerstate == PLAYER_STATE_VIDEO && libmpv->getFileInfo()->playbackInfo.islive == false && sqlitedb != nullptr){ + if(libmpv->getFileInfoPerc() >= configini->getResumeStartPerc(false) && 100-libmpv->getFileInfoPerc() >= configini->getResumeStopPerc(false)){ + sqlitedb->writeResume(libmpv->getFileInfo()->path,libmpv->getFileInfo()->playbackInfo.position); + }else{ + if(eof->reason != MPV_END_FILE_REASON_EOF){ + sqlitedb->deleteResume(libmpv->getFileInfo()->path); + } + } + if(eof->reason == MPV_END_FILE_REASON_EOF){ + printf("FILE EOF\n"); + sqlitedb->deleteResume(libmpv->getFileInfo()->path); + } + } + printf("END PLAY FILE\n"); item.state = item.laststate; item.rightmenustate = PLAYER_RIGHT_MENU_PLAYER; + item.playercontrolstate = PLAYER_CONTROL_STATE_NONE; item.masterlock = false; printf("MENU STATE: %d\n",item.state ); } - - count --; - printf("event: %s\n", mpv_event_name(mp_event->event_id)); + if(mp_event->event_id == MPV_EVENT_PROPERTY_CHANGE){ + mpv_event_property *prop = (mpv_event_property*)mp_event->data; + if(std::string(prop->name) == "metadata" && !libmpv->Stopped()) + { + mpv_node node = *(mpv_node *)prop->data; + printf("Node format %d\n",node.format); + if (node.format == MPV_FORMAT_NODE_MAP) { + for (int n = 0; n < node.u.list->num; n++) { + std::string key = node.u.list->keys[n]; + if(key == "title"){ + libmpv->getFileInfo()->playbackInfo.title = node.u.list->values[n].u.string; + } + if(key == "artist"){ + libmpv->getFileInfo()->playbackInfo.artist = node.u.list->values[n].u.string; + } + printf("META KEY %s\n",key.c_str()); + } + } + } + if(std::string(prop->name) == "playback-time") + { + if(prop->format == MPV_FORMAT_DOUBLE) + { + double timepos = *(double *)prop->data; + libmpv->getFileInfo()->playbackInfo.position = (int)timepos; + } + } + if(std::string(prop->name) == "duration") + { + if(prop->format == MPV_FORMAT_INT64) + { + int64_t timepos = *(int64_t *)prop->data; + libmpv->getFileInfo()->playbackInfo.duration = timepos; + } + } + } + if(mp_event->event_id!=22){ + printf("event: %s %d\n", mpv_event_name(mp_event->event_id),mp_event->event_id); + } } } } @@ -389,7 +483,7 @@ namespace GUI { Windows::MainMenuWindow(&item.focus, &item.first_item); break; case MENU_STATE_FILEBROWSER: - Windows::FileBrowserWindow(&item.focus, item.first_item); + Windows::FileBrowserWindow(&item.focus, &item.first_item); break; case MENU_STATE_USB: Windows::USBBrowserWindow(&item.focus, &item.first_item); @@ -419,13 +513,25 @@ namespace GUI { playerWindows::CacheWindow(); break; case MENU_STATE_PLAYER: + if(item.popupstate == POPUP_STATE_RESUME){ + Popups::ResumePopup(); + } + if(item.playerstate == PLAYER_STATE_AUDIO){ - playerWindows::AudioplayerWindow(&item.focus, &item.first_item); + } break; } + switch (item.playercontrolstate) { + case PLAYER_CONTROL_STATE_NONE: + break; + case PLAYER_CONTROL_STATE_CONTROLS: + playerWindows::playerControls(); + break; + } + switch (item.rightmenustate) { case PLAYER_RIGHT_MENU_PLAYER: break; diff --git a/source/libmpv.cpp b/source/libmpv.cpp index e4501bf..bbc1700 100644 --- a/source/libmpv.cpp +++ b/source/libmpv.cpp @@ -30,6 +30,7 @@ libMpv::libMpv(const std::string &configDir) { mpv_set_option_string(handle, "fbo-format", "rgba8"); mpv_set_option_string(handle, "gpu-nxmp-deint", std::to_string(configini->getDeinterlace(false)).c_str()); mpv_set_option_string(handle, "volume-max", "200"); + if(configini->getUseAlang(false)){ std::string alangstring = Utility::getLanguages()[configini->getAlang(false)].lang3 + std::string(",") + Utility::getLanguages()[configini->getAlang(false)].lang2 + std::string(",eng,en"); @@ -69,7 +70,7 @@ libMpv::libMpv(const std::string &configDir) { mpv_version = mpv_get_property_string(handle, "mpv-version"); ffmpeg_version = mpv_get_property_string(handle, "ffmpeg-version"); - + mpv_node node; mpv_get_property(handle, "decoder-list", MPV_FORMAT_NODE, &node); if (node.format == MPV_FORMAT_NODE_ARRAY) { @@ -98,12 +99,51 @@ libMpv::libMpv(const std::string &configDir) { } +void libMpv::loadFile(std::string _path){ + if(fileinfo != nullptr){ + delete fileinfo; + } + fileinfo = new fileInfo(); + fileinfo->path = _path; + const char *cmd[] = {"loadfile", _path.c_str(), NULL}; + mpv_command_async(handle, 0, cmd); + setLoop(false); + + +} + +void libMpv::loadFileLive(std::string _path,std::string _changename){ + if(fileinfo != nullptr){ + delete fileinfo; + } + fileinfo = new fileInfo(); + fileinfo->path = _path; + fileinfo->playbackInfo.title = _changename; + fileinfo->playbackInfo.islive = true; + const char *cmd[] = {"loadfile", _path.c_str(), NULL}; + mpv_command_async(handle, 0, cmd); + setLoop(false); +} + int64_t libMpv::getPosition() { int64_t position = 0; mpv_get_property(handle, "playback-time", MPV_FORMAT_INT64, &position); return position; } +int64_t libMpv::getDuration() { + int64_t duration = 0; + mpv_get_property(handle, "duration", MPV_FORMAT_INT64, &duration); + return duration; +} + +int libMpv::getFileInfoPerc() { + if(fileinfo != nullptr){ + return (int)(((double)((double)fileinfo->playbackInfo.position/(double)fileinfo->playbackInfo.duration))*100.0)+0.5f; + } + return 0; +} + void libMpv::Pause() { mpv_command_string(handle, "set pause yes"); } @@ -118,6 +158,7 @@ void libMpv::Stop() { } void libMpv::seek(double position,bool osd) { + if(position <=0)position = 0; if(osd){ std::string cmd = "seek " + std::to_string(position) + " absolute"; mpv_command_string(handle, cmd.c_str()); @@ -179,6 +220,11 @@ void libMpv::getfileInfo() { fileInfo::Track stream{}; for (int n = 0; n < node.u.list->values[i].u.list->num; n++) { std::string key = node.u.list->values[i].u.list->keys[n]; + if(key == "albumart"){ + if (node.u.list->values[i].u.list->values[n].format == MPV_FORMAT_FLAG) { + stream.albumart = node.u.list->values[i].u.list->values[n].u.flag; + } + } if (key == "type") { if (node.u.list->values[i].u.list->values[n].format == MPV_FORMAT_STRING) { stream.type = node.u.list->values[i].u.list->values[n].u.string; @@ -257,11 +303,6 @@ void libMpv::getfileInfo() { - if(fileinfo != nullptr){ - delete fileinfo; - } - fileinfo = new fileInfo(); - fileInfo::Track dummysubstream{}; dummysubstream.id = -1; dummysubstream.title = "None"; @@ -296,6 +337,7 @@ void libMpv::getfileInfo() { fflush(stdout); } + fileinfo->playbackInfo.duration = getDuration(); } @@ -439,6 +481,21 @@ void libMpv::setVolume(int value,bool osd){ std::string cmd = "no-osd set volume " + std::to_string(value); mpv_command_string(handle, cmd.c_str()); } + volume = value; +} + +bool libMpv::getMute(){ + if(volume == 0)return true; + return false; +} + +void libMpv::toggleMute(){ + if(getMute()){ + setVolume(tmpvolume,false); + }else{ + tmpvolume = volume; + setVolume(0,false); + } } void libMpv::setAudioDelay(double value, bool osd){ @@ -471,16 +528,50 @@ void libMpv::setAudioEQ(int *eqval,bool osd){ } + +void libMpv::setAudioSuperEQband(float eqval,int band,bool osd){ + //char eqstring[1024]; + //sprintf(eqstring,"no-osd set af superequalizer=1b=%.1f:2b=%.1f:3b=%.1f:4b=%.1f:5b=%.1f:6b=%.1f:7b=%.1f:8b=%.1f:9b=%.1f:10b=%.1f:11b=%.1f:12b=%.1f:13b=%.1f:14b=%.1f:15b=%.1f:16b=%.1f:17b=%.1f",eqval[0],eqval[1],eqval[2],eqval[3],eqval[4],eqval[5],eqval[6],eqval[7],eqval[8],eqval[9],eqval[10],eqval[11],eqval[12],eqval[13],eqval[14],eqval[15],eqval[16]); + //mpv_command_string(handle, eqstring); + + char eqstring2[512]; + sprintf(eqstring2,"superequalizer=%db=%.1f",band+1,eqval); + const char *args[] = {"set","af",eqstring2,NULL}; + mpv_command_async(handle,0,args); + + +} + void libMpv::setAudioSuperEQ(float *eqval,bool osd){ - char eqstring[1024]; - sprintf(eqstring,"no-osd set af superequalizer=1b=%.1f:2b=%.1f:3b=%.1f:4b=%.1f:5b=%.1f:6b=%.1f:7b=%.1f:8b=%.1f:9b=%.1f:10b=%.1f:11b=%.1f:12b=%.1f:13b=%.1f:14b=%.1f:15b=%.1f:16b=%.1f:17b=%.1f",eqval[0],eqval[1],eqval[2],eqval[3],eqval[4],eqval[5],eqval[6],eqval[7],eqval[8],eqval[9],eqval[10],eqval[11],eqval[12],eqval[13],eqval[14],eqval[15],eqval[16]); - mpv_command_string(handle, eqstring); + //char eqstring[1024]; + //sprintf(eqstring,"no-osd set af superequalizer=1b=%.1f:2b=%.1f:3b=%.1f:4b=%.1f:5b=%.1f:6b=%.1f:7b=%.1f:8b=%.1f:9b=%.1f:10b=%.1f:11b=%.1f:12b=%.1f:13b=%.1f:14b=%.1f:15b=%.1f:16b=%.1f:17b=%.1f",eqval[0],eqval[1],eqval[2],eqval[3],eqval[4],eqval[5],eqval[6],eqval[7],eqval[8],eqval[9],eqval[10],eqval[11],eqval[12],eqval[13],eqval[14],eqval[15],eqval[16]); + //mpv_command_string(handle, eqstring); + + char eqstring2[1024]; + sprintf(eqstring2,"superequalizer=1b=%.1f:2b=%.1f:3b=%.1f:4b=%.1f:5b=%.1f:6b=%.1f:7b=%.1f:8b=%.1f:9b=%.1f:10b=%.1f:11b=%.1f:12b=%.1f:13b=%.1f:14b=%.1f:15b=%.1f:16b=%.1f:17b=%.1f",eqval[0],eqval[1],eqval[2],eqval[3],eqval[4],eqval[5],eqval[6],eqval[7],eqval[8],eqval[9],eqval[10],eqval[11],eqval[12],eqval[13],eqval[14],eqval[15],eqval[16]); + const char *args[] = {"set","af",eqstring2,NULL}; + mpv_command_async(handle,0,args); + + } void libMpv::setDeinterlace(int value){ mpv_set_option_string(handle, "gpu-nxmp-deint", std::to_string(value).c_str()); } +void libMpv::setLoop(bool val){ + if(val){ + mpv_set_option_string(handle,"loop-file","inf"); + }else{ + mpv_set_option_string(handle,"loop-file","no"); + } + loop = val; +} + +bool libMpv::getLoop(){ + return loop; +} + libMpv::~libMpv(){ if (context) { mpv_render_context_free(context); diff --git a/source/localfiles.cpp b/source/localfiles.cpp index e70415f..4e59cf3 100644 --- a/source/localfiles.cpp +++ b/source/localfiles.cpp @@ -96,5 +96,10 @@ namespace FS { if(retpath == "")retpath = "/"; return retpath; } - + + std::string getFilefromPath(std::string path){ + std::string retpath = path.substr(path.find_last_of("\\/")+1); + return retpath; + } + } \ No newline at end of file diff --git a/source/main.cpp b/source/main.cpp index 27fc47b..8bdf254 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -22,6 +22,8 @@ #include "imgui_impl_sdl.h" #include "imgui_impl_opengl3.h" #include "SimpleIni.h" +#include "SQLiteDB.h" +#include "eqpreset.h" //#define NDEBUG 1 @@ -36,7 +38,9 @@ HTTPDir *httpdir = nullptr; #ifdef __SWITCH__ USBMounter *usbmounter = nullptr; #endif -Config *configini; +Config *configini = nullptr; +EQPreset *eqpreset = nullptr; +SQLiteDB *sqlitedb = nullptr; Enigma2 *enigma2 = nullptr; uint32_t wakeup_on_mpv_render_update; uint32_t wakeup_on_mpv_events; @@ -67,6 +71,14 @@ Tex MPVTexture; Tex NXMPBannerTexture; Tex ExitTexture; +Tex PlayIcon; +Tex PauseIcon; +Tex StopIcon; +Tex MuteIcon; +Tex VolumeIcon; +Tex LoopIcon; +Tex NoLoopIcon; + ImFont* fontSmall; const GLuint WIDTH = 1280, HEIGHT = 720; @@ -131,6 +143,12 @@ int main(int argc,char *argv[]){ configini = new Config("config.ini"); + eqpreset = new EQPreset("eqpresets.ini"); + + if(configini->getDbActive(false)){ + sqlitedb = new SQLiteDB("nxmp.db"); + } + #ifdef __SWITCH__ Result ret; @@ -254,6 +272,14 @@ int main(int argc,char *argv[]){ Utility::TxtLoadFromFile("romfs:/mpv.png",&MPVTexture.id,&MPVTexture.width,&MPVTexture.height); Utility::TxtLoadFromFile("romfs:/exit.png",&ExitTexture.id,&ExitTexture.width,&ExitTexture.height); Utility::TxtLoadFromFile("romfs:/nxmp-banner.jpg",&NXMPBannerTexture.id,&NXMPBannerTexture.width,&NXMPBannerTexture.height); + Utility::TxtLoadFromFile("romfs:/player/play.png",&PlayIcon.id,&PlayIcon.width,&PlayIcon.height); + Utility::TxtLoadFromFile("romfs:/player/stop.png",&StopIcon.id,&StopIcon.width,&StopIcon.height); + Utility::TxtLoadFromFile("romfs:/player/pause.png",&PauseIcon.id,&PauseIcon.width,&PauseIcon.height); + Utility::TxtLoadFromFile("romfs:/player/mute.png",&MuteIcon.id,&MuteIcon.width,&MuteIcon.height); + Utility::TxtLoadFromFile("romfs:/player/volume.png",&VolumeIcon.id,&VolumeIcon.width,&VolumeIcon.height); + Utility::TxtLoadFromFile("romfs:/player/loop.png",&LoopIcon.id,&LoopIcon.width,&LoopIcon.height); + Utility::TxtLoadFromFile("romfs:/player/noloop.png",&NoLoopIcon.id,&NoLoopIcon.width,&NoLoopIcon.height); + #else Utility::TxtLoadFromFile("./romfs/sdcard.png",&SdCardTexture.id,&SdCardTexture.width,&SdCardTexture.height); Utility::TxtLoadFromFile("./romfs/usb.png",&UsbTexture.id,&UsbTexture.width,&UsbTexture.height); @@ -269,6 +295,15 @@ int main(int argc,char *argv[]){ Utility::TxtLoadFromFile("./romfs/mpv.png",&MPVTexture.id,&MPVTexture.width,&MPVTexture.height); Utility::TxtLoadFromFile("./romfs/exit.png",&ExitTexture.id,&ExitTexture.width,&ExitTexture.height); Utility::TxtLoadFromFile("./romfs/nxmp-banner.jpg",&NXMPBannerTexture.id,&NXMPBannerTexture.width,&NXMPBannerTexture.height); + Utility::TxtLoadFromFile("./romfs/player/play.png",&PlayIcon.id,&PlayIcon.width,&PlayIcon.height); + Utility::TxtLoadFromFile("./romfs/player/stop.png",&StopIcon.id,&StopIcon.width,&StopIcon.height); + Utility::TxtLoadFromFile("./romfs/player/pause.png",&PauseIcon.id,&PauseIcon.width,&PauseIcon.height); + Utility::TxtLoadFromFile("./romfs/player/mute.png",&MuteIcon.id,&MuteIcon.width,&MuteIcon.height); + Utility::TxtLoadFromFile("./romfs/player/volume.png",&VolumeIcon.id,&VolumeIcon.width,&VolumeIcon.height); + Utility::TxtLoadFromFile("./romfs/player/loop.png",&LoopIcon.id,&LoopIcon.width,&LoopIcon.height); + Utility::TxtLoadFromFile("./romfs/player/noloop.png",&NoLoopIcon.id,&NoLoopIcon.width,&NoLoopIcon.height); + + #endif printf("Init Enigma2\n"); @@ -277,9 +312,37 @@ int main(int argc,char *argv[]){ printf("Ending Render Loop\n"); delete libmpv; libmpv = nullptr; - delete enigma2; - enigma2 = nullptr; - + + + + if(localdir != nullptr){ + delete localdir; + localdir = nullptr; + } +#ifdef __SWITCH__ + if(usbmounter != nullptr){ + delete usbmounter; + usbmounter = nullptr; + } +#endif + if(ftpdir != nullptr){ + delete ftpdir; + ftpdir = nullptr; + } + if(httpdir != nullptr){ + delete httpdir; + httpdir = nullptr; + } + if(enigma2 != nullptr){ + delete enigma2; + enigma2 = nullptr; + } + + if(sqlitedb != nullptr){ + delete sqlitedb; + sqlitedb = nullptr; + } + ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplSDL2_Shutdown(); ImGui::DestroyContext(); @@ -292,6 +355,7 @@ int main(int argc,char *argv[]){ printf("Exit Services\n"); + #ifdef __SWITCH__ ncmExit(); plExit(); diff --git a/source/remotefs/Enigma2/Enigma2.cpp b/source/remotefs/Enigma2/Enigma2.cpp index 88b2b04..40758f3 100644 --- a/source/remotefs/Enigma2/Enigma2.cpp +++ b/source/remotefs/Enigma2/Enigma2.cpp @@ -1,5 +1,5 @@ #include "Enigma2.h" - +#include "utils.h" static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) @@ -99,8 +99,13 @@ vector Enigma2::parseBouquet(char * data){ void Enigma2::m3uParser(char * url){ e2currbouqet.clear(); - string m3uurl = "http://"; - m3uurl.append(enigma2ip); + urlschema e2schema = Utility::parseUrl(enigmaurl); + string m3uurl = e2schema.scheme; + m3uurl.append("://"); + m3uurl.append(e2schema.server); + if(e2schema.port == "")e2schema.port="80"; + m3uurl.append(":"); + m3uurl.append(e2schema.port); m3uurl.append("/web/services.m3u?bRef="); m3uurl.append(urlencode(url)); MemoryStruct *chunk = (MemoryStruct *)malloc(sizeof(MemoryStruct)); @@ -122,8 +127,12 @@ void Enigma2::m3uParser(char * url){ s = sm.suffix(); } - string epguurl = "http://"; - epguurl.append(enigma2ip); + string epguurl = e2schema.scheme; + epguurl.append("://"); + epguurl.append(e2schema.server); + if(e2schema.port == "")e2schema.port="80"; + epguurl.append(":"); + epguurl.append(e2schema.port); epguurl.append("/web/epgnow?bRef="); epguurl.append(urlencode(url)); MemoryStruct *chunk2 = (MemoryStruct *)malloc(sizeof(MemoryStruct)); @@ -162,8 +171,15 @@ void Enigma2::m3uParser(char * url){ bool Enigma2::getServices(){ MemoryStruct *chunk = (MemoryStruct *)malloc(sizeof(MemoryStruct)); - string downurl = "http://"; - downurl.append(enigma2ip); + //string downurl = "http://"; + //downurl.append(enigma2ip); + urlschema e2schema = Utility::parseUrl(enigmaurl); + string downurl = e2schema.scheme; + downurl.append("://"); + downurl.append(e2schema.server); + if(e2schema.port == "")e2schema.port="80"; + downurl.append(":"); + downurl.append(e2schema.port); downurl.append("/web/getservices"); curlDownload((char *)downurl.c_str(),chunk); e2services = parseBouquet(chunk->memory); @@ -184,4 +200,8 @@ void Enigma2::backToTop(){ EnigmaServices dummy; currbouquet = dummy; } + +Enigma2::Enigma2(std::string _url){ + enigmaurl = _url; +} \ No newline at end of file diff --git a/source/remotefs/Enigma2/Enigma2.h b/source/remotefs/Enigma2/Enigma2.h index ed5080f..1a51e64 100644 --- a/source/remotefs/Enigma2/Enigma2.h +++ b/source/remotefs/Enigma2/Enigma2.h @@ -40,6 +40,8 @@ struct EnigmaServices{ class Enigma2{ public: + + Enigma2(std::string url); string enigma2ip; vector parseBouquet(char * data); void m3uParser(char * url); @@ -56,6 +58,7 @@ class Enigma2{ private: + std::string enigmaurl; EnigmaServices currbouquet; diff --git a/source/utils.cpp b/source/utils.cpp index 0e5d4a7..2ead77b 100644 --- a/source/utils.cpp +++ b/source/utils.cpp @@ -15,9 +15,9 @@ namespace Utility{ if (h > 0) { oss << std::setfill('0') << std::setw(2) << h << ":"; } - if (min > 0) { + //if (min > 0) { oss << std::setfill('0') << std::setw(2) << min << ":"; - } + //} oss << std::setfill('0') << std::setw(2) << sec; return oss.str(); @@ -149,6 +149,7 @@ namespace Utility{ ".wav", ".wma", ".wmv", + ".flac", ".m3u", ".m3u8" }; @@ -376,4 +377,10 @@ namespace Utility{ return rtrim(ltrim(s)); } + std::string truncateLen(std::string path,int len){ + if(len>path.length())return path; + std::string retpath = path.substr(0,len); + return retpath + std::string("..."); + } + } \ No newline at end of file