38 Commits

Author SHA1 Message Date
Kun Deng c96ee39c6a Merge pull request #17 from kdeng00/cleanup
Cleanup
2022-08-28 10:53:23 -04:00
Kun Deng 389f41ecea Updates
Updated CMakeLists file, removed conan file, and have all windows configs targeting C++20
2022-08-28 10:53:00 -04:00
Kun Deng 10bf0fb0e1 Clean up and version change 2022-08-28 10:49:28 -04:00
Kun Deng 4429f7e766 Merge pull request #16 from kdeng00/bug_fix
Bug fix
2022-08-28 10:36:11 -04:00
Kun Deng e5d119d343 Bug fix 2022-08-28 10:34:27 -04:00
Kun Deng 1d88a3ccf6 Update README.md 2022-08-07 21:40:23 -04:00
Kun Deng 2768c1e351 Update README.md 2022-08-07 21:40:01 -04:00
Kun Deng 3955942988 Merge pull request #15 from kdeng00/v0.3
V0.3
2022-08-07 21:37:39 -04:00
Kun Deng bfd7a02970 Merge pull request #14 from kdeng00/vs
Vs
2022-08-07 21:35:55 -04:00
kdeng00 77acd15105 Able to debug with Visual Studio 2022-08-07 21:34:41 -04:00
kdeng00 435a0df941 Added build files
Added Visual studio build files
2022-08-07 21:15:54 -04:00
kdeng00 c624c4de51 Missing include 2022-08-07 21:15:07 -04:00
Kun Deng 1d6cd804be Merge pull request #13 from kdeng00/vcpkg
Vcpkg
2022-08-07 20:46:24 -04:00
kdeng00 2743543102 Clean up 2022-08-07 20:44:37 -04:00
kdeng00 3195011f99 vcpkg is operational 2022-08-07 20:42:11 -04:00
kdeng00 ed5ceedb44 vcpkg version
Version 2022.07.25
2022-08-07 20:04:57 -04:00
kdeng00 f70acba704 Added vcpkg 2022-08-07 20:04:02 -04:00
Kun Deng f224b5738b Merge pull request #12 from kdeng00/build_fix
Fixed build issue
2022-08-07 19:59:29 -04:00
kdeng00 c41cd9dbb7 Fixed build issue 2022-08-07 19:51:29 -04:00
Kun Deng 9420ee97b4 Merge pull request #9 from kdeng00/support_new_upload_endpoint
Support new upload endpoint
2022-01-09 18:07:50 -05:00
Kun Deng c46f386d70 Merge branch 'master' into support_new_upload_endpoint 2022-01-09 18:07:44 -05:00
kdeng00 d9962749c8 Ready for release 2022-01-09 18:06:43 -05:00
kdeng00 c8e8c1a460 Changed cmake version 2022-01-09 02:16:51 -05:00
kdeng00 dcfa9951d9 Updated Readme 2022-01-09 02:04:56 -05:00
kdeng00 e90278995a Saving changes 2022-01-09 00:31:43 -05:00
kdeng00 7c8e77f233 Formatting 2022-01-08 23:52:46 -05:00
Kun Deng a1b2e5f64a Merge branch 'master' into support_new_upload_endpoint 2022-01-08 23:46:43 -05:00
kdeng00 25e8774968 Visual Studio support 2022-01-08 21:12:55 -05:00
kdeng00 10ed33d412 Formatting 2022-01-08 21:09:40 -05:00
kdeng00 1ef40bcbfb Got functionality working 2022-01-01 00:39:35 -05:00
kdeng00 3e25dd77b5 Updates
Updating required flags for uploading a song with metadata
2021-12-31 22:15:17 -05:00
kdeng00 14d3c9acc6 Made progress 2021-12-31 19:09:31 -05:00
kdeng00 9930aab985 Updated Readme 2021-12-31 16:00:45 -05:00
kdeng00 0839731ee8 upload-meta command 2021-12-29 15:58:14 -05:00
Kun Deng 7a04b802f0 Merge pull request #8 from kdeng00/package_manager-switch
Package manager switch
2021-12-29 15:50:28 -05:00
kdeng00 63d6022d16 Updated Readme
Added link to conan repo
2021-12-29 15:47:21 -05:00
kdeng00 db1a6302ad Updated Readme 2021-12-29 15:45:12 -05:00
kdeng00 bd819f0332 package manager switch
Moving from Hunter to conan
2021-12-29 15:38:28 -05:00
53 changed files with 2592 additions and 1872 deletions
+3
View File
@@ -0,0 +1,3 @@
/.vs/*
/build
/x64
+3
View File
@@ -0,0 +1,3 @@
[submodule "3rdparty/vcpkg"]
path = 3rdparty/vcpkg
url = https://github.com/microsoft/vcpkg
Vendored Submodule
+1
Submodule 3rdparty/vcpkg added at f93ba152d5
+64 -47
View File
@@ -1,31 +1,63 @@
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.23.3)
set(VCPKG_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/vcpkg)
message("The vcpkg root path ${VCPKG_ROOT_PATH}")
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
set(TOOLCHAIN_PATH ${VCPKG_ROOT_PATH}/scripts/buildsystems/vcpkg.cmake)
set(CMAKE_TOOLCHAIN_FILE
"${TOOLCHAIN_PATH}"
CACHE STRING "Vcpkg toolchain file")
message("Using default toolchain file")
endif()
include("cmake/HunterGate.cmake") set(SOFTWARE_DESCRIPTION
HunterGate( "A tool to interact with the Icarus Music streaming API")
URL "https://github.com/ruslo/hunter/archive/v0.23.184.tar.gz" set(SOFTWARE_VERSION
SHA1 "fe3fb05d51c21499c7eebbe7d0e102742a54a9cd" "0.3.2")
)
project(IcarusDownloadManager)
project(IcarusDownloadManager VERSION ${SOFTWARE_VERSION} DESCRIPTION ${SOFTWARE_DESCRIPTION} LANGUAGES CXX)
message(STATUS "Checking compiler flags for C++20 support.")
# Set C++20 support flags for various compilers
include(CheckCXXCompilerFlag)
if(WIN32)
message("Windows environment")
if (MSVC_VERSION GREATER_EQUAL "1900")
message("Visual Studio version is at least ${vs_ver}")
if(NOT ${CMAKE_VERSION} LESS 3.2)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
else()
message(STATUS "Checking compiler flags for C++17 support.")
# Set C++17 support flags for various compilers
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-std=c++17" COMPILER_SUPPORTS_CXX17) CHECK_CXX_COMPILER_FLAG("/std:c++20" _cpp_latest_flag_supported)
if (_cpp_latest_flag_supported)
add_compile_options("/std:c++20")
endif()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
else()
check_cxx_compiler_flag("-std=c++20" COMPILER_SUPPORTS_CXX20)
check_cxx_compiler_flag("-std=c++0x" COMPILER_SUPPORTS_CXX0X) check_cxx_compiler_flag("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX17)
message(STATUS "C++17 is supported.") if(COMPILER_SUPPORTS_CXX20)
message(STATUS "C++20 is supported.")
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -stdlib=libc++") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20 -stdlib=libc++")
else() else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20")
endif() endif()
elseif(COMPILER_SUPPORTS_CXX0X) elseif(COMPILER_SUPPORTS_CXX0X)
message(STATUS "C++0x is supported.") message(STATUS "C++0x is supported.")
@@ -35,7 +67,7 @@ else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
endif() endif()
else() else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++17 support. Please use a different C++ compiler.") message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++20 support. Please use a different C++ compiler.")
endif() endif()
endif() endif()
@@ -47,6 +79,7 @@ set(SOURCES
src/Managers/FileManager.cpp src/Managers/FileManager.cpp
src/Managers/TokenManager.cpp src/Managers/TokenManager.cpp
src/Managers/UserManager.cpp src/Managers/UserManager.cpp
src/Models/Song.cpp
src/Parsers/APIParser.cpp src/Parsers/APIParser.cpp
src/Syncers/Delete.cpp src/Syncers/Delete.cpp
src/Syncers/Download.cpp src/Syncers/Download.cpp
@@ -54,36 +87,20 @@ set(SOURCES
src/Syncers/Upload.cpp src/Syncers/Upload.cpp
src/Utilities/Conversions.cpp src/Utilities/Conversions.cpp
) )
set(HEADERS
include/Managers/ActionManager.h
include/Managers/CommitManager.h
include/Managers/FileManager.h
include/Managers/TokenManager.h
include/Managers/UserManager.h
include/Models/API.h
include/Models/Flags.h
include/Models/IcarusAction.h
include/Models/Song.h
include/Models/Token.h
include/Models/UploadForm.h
include/Models/User.h
include/Parsers/APIParser.h
include/Syncers/Delete.h
include/Syncers/Download.h
include/Syncers/RetrieveRecords.h
include/Syncers/SyncerBase.h
include/Syncers/Upload.h
include/Utilities/Conversions.h
)
set(IDM_INCLUDE_DIR
"${CMAKE_CURRENT_SOURCE_DIR}/include")
include_directories(${IDM_INCLUDE_DIR})
set(USE_SYSTEM_CURL OFF)
set(BUILD_CPR_TESTS OFF)
hunter_add_package(nlohmann_json)
find_package(nlohmann_json CONFIG REQUIRED) find_package(nlohmann_json CONFIG REQUIRED)
find_package(OpenSSL REQUIRED)
hunter_add_package(cpr) find_package(CURL REQUIRED)
find_package(cpr CONFIG REQUIRED) find_package(cpr CONFIG REQUIRED)
add_executable(icd ${SOURCES} ${HEADERS}) add_executable(icd ${SOURCES})
target_link_libraries(icd PUBLIC nlohmann_json::nlohmann_json cpr::cpr) target_link_libraries(icd PRIVATE nlohmann_json::nlohmann_json OpenSSL::SSL OpenSSL::Crypto CURL::libcurl cpr::cpr)
include_directories(include/)
+99
View File
@@ -0,0 +1,99 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,3,2,0
PRODUCTVERSION 0,3,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "FileDescription", "Tool to interact with Icarus API"
VALUE "FileVersion", "0.3.2.0"
VALUE "InternalName", "IcarusDo.exe"
VALUE "LegalCopyright", "Copyright (C) 2022"
VALUE "OriginalFilename", "IcarusDo.exe"
VALUE "ProductName", "IcarusDownloadManager"
VALUE "ProductVersion", "0.3.2.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
+31
View File
@@ -0,0 +1,31 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32630.192
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IcarusDownloadManager", "IcarusDownloadManager.vcxproj", "{12955990-643F-4A99-95E5-4752AFA179B0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{12955990-643F-4A99-95E5-4752AFA179B0}.Debug|x64.ActiveCfg = Debug|x64
{12955990-643F-4A99-95E5-4752AFA179B0}.Debug|x64.Build.0 = Debug|x64
{12955990-643F-4A99-95E5-4752AFA179B0}.Debug|x86.ActiveCfg = Debug|Win32
{12955990-643F-4A99-95E5-4752AFA179B0}.Debug|x86.Build.0 = Debug|Win32
{12955990-643F-4A99-95E5-4752AFA179B0}.Release|x64.ActiveCfg = Release|x64
{12955990-643F-4A99-95E5-4752AFA179B0}.Release|x64.Build.0 = Release|x64
{12955990-643F-4A99-95E5-4752AFA179B0}.Release|x86.ActiveCfg = Release|Win32
{12955990-643F-4A99-95E5-4752AFA179B0}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EA22B463-3EA6-4452-9AF1-D300C3BDE72D}
EndGlobalSection
EndGlobal
+165
View File
@@ -0,0 +1,165 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<ProjectGuid>{12955990-643F-4A99-95E5-4752AFA179B0}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(ProjectDir)include;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(ProjectDir)include;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="src\Main.cpp" />
<ClCompile Include="src\managers\ActionManager.cpp" />
<ClCompile Include="src\managers\CommitManager.cpp" />
<ClCompile Include="src\managers\FileManager.cpp" />
<ClCompile Include="src\managers\TokenManager.cpp" />
<ClCompile Include="src\managers\UserManager.cpp" />
<ClCompile Include="src\models\Song.cpp" />
<ClCompile Include="src\parsers\APIParser.cpp" />
<ClCompile Include="src\syncers\Delete.cpp" />
<ClCompile Include="src\syncers\Download.cpp" />
<ClCompile Include="src\syncers\RetrieveRecords.cpp" />
<ClCompile Include="src\syncers\Upload.cpp" />
<ClCompile Include="src\utilities\Conversions.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\managers\ActionManager.h" />
<ClInclude Include="include\managers\CommitManager.h" />
<ClInclude Include="include\managers\FileManager.h" />
<ClInclude Include="include\managers\TokenManager.h" />
<ClInclude Include="include\managers\UserManager.h" />
<ClInclude Include="include\models\API.h" />
<ClInclude Include="include\models\Flags.h" />
<ClInclude Include="include\models\IcarusAction.h" />
<ClInclude Include="include\models\Song.h" />
<ClInclude Include="include\models\Token.h" />
<ClInclude Include="include\models\UploadForm.h" />
<ClInclude Include="include\models\User.h" />
<ClInclude Include="include\parsers\APIParser.h" />
<ClInclude Include="include\syncers\Delete.h" />
<ClInclude Include="include\syncers\Download.h" />
<ClInclude Include="include\syncers\RetrieveRecords.h" />
<ClInclude Include="include\syncers\SyncerBase.h" />
<ClInclude Include="include\syncers\Upload.h" />
<ClInclude Include="include\utilities\Checks.h" />
<ClInclude Include="include\utilities\Conversions.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="IcarusDownloadManager.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\Main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\managers\ActionManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\managers\CommitManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\managers\FileManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\managers\TokenManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\managers\UserManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\models\Song.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\parsers\APIParser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\syncers\Delete.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\syncers\Download.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\syncers\RetrieveRecords.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\syncers\Upload.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\utilities\Conversions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\managers\ActionManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\managers\CommitManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\managers\FileManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\managers\TokenManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\managers\UserManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\models\API.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\models\Flags.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\models\IcarusAction.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\models\Song.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\models\Token.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\models\UploadForm.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\models\User.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\parsers\APIParser.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\syncers\Delete.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\syncers\Download.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\syncers\RetrieveRecords.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\syncers\SyncerBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\syncers\Upload.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\utilities\Checks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\utilities\Conversions.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerCommandArguments>upload-meta -u kverse -p demolaugh -h http://localhost:5002 -smca "D:\OneDrive\media\music\mp3\bb_king\paying_the_cost_to_be_the_boss"</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerCommandArguments>upload-meta -u kverse -p demolaugh -h http://localhost:5002 -smca "D:\OneDrive\media\music\mp3\bb_king\paying_the_cost_to_be_the_boss"</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
+62 -18
View File
@@ -1,45 +1,87 @@
# IcarusDownloadManager # IcarusDownloadManager
IcarusDownloadManager is a Linux CLI software client application that has the feature of uploading and downloading songs from the [Icarus](https://github.com/amazing-username/Icarus) Music Server. IcarusDownloadManager is a Linux CLI software client application that has the feature of uploading and downloading songs from the [Icarus](https://github.com/kdeng00/Icarus) Music Server.
## Built With ## Built With
* C++ * C++ with C++20 features
* CMake * CMake
* GCC * GCC >= 10 or Visual Studio >= 17 [2022]
* [Hunter](https://github.com/ruslo/hunter) * [vcpkg](https://github.com/microsoft/vcpkg)
* libCurl
* [json](https://github.com/nlohmann/json) * [json](https://github.com/nlohmann/json)
* [cpr](http://whoshuu.github.io/cpr/) * [openssl](https://github.com/openssl/openssl)
* [curl](https://github.com/curl/curl)
* [cpr](https://github.com/libcpr/cpr)
### Getting Started ### Getting Started
Clone the repo
```
git clone --recursive https://github.com/kdeng00/IcarusDownloadManager
```
Install packages
```
vcpkg install nlohman-json
vcpkg install openssl
vcpkg install curl
vcpkg install cpr
```
Build the project: Build the project:
``` ```
export HUNTER_ROOT=/path/to/download/hunter/files/for/dependencies cd IcarusDownloadManager
mkdir _build mkdir build
cd _build cd build
cmake -H. -B_builds -DHUNTER_STATUS_DEBUG=ON -DCMAKE_BUILD_TYPE=DEBUG
cmake --build _builds --config Debug cmake ..
make cmake --build . --config release -j
``` ```
The program has been built and can be executed by the binary file *icd*. For information on how to use icd, merely execute the program without any command line arguments. The program has been built and can be executed by the binary file *icd*. For information on how to use icd, merely execute the program without any command line arguments.
### Downloading Song ### Downloading Song
``icd download -u spacecadet -p stellar40 -h https://icarus.com -b 15``
```BASH
icd download -u spacecadet -p stellar40 -h https://icarus.com -b 15
```
### Uploading Song ### Uploading Song
``icd upload -u spacecadet -p stellar40 -h https://icarus.com -s /path/of/song.mp3``
```BASH
icd upload -u spacecadet -p stellar40 -h https://icarus.com -s /path/of/song.mp3
```
### Uploading Song with metadata
```BASH
icd upload-meta -u spacecadet -p stellar40 -h https://icarus.com -s /path/of/song.mp3 -t 1 -m /path/to/metadata/config/collection.json -ca /path/to/cover/art/image.png
```
### Uploading Song with metadata from directory
```BASH
icd upload-meta -u spacecadet -p stellar40 -h https://icarus.com -smca /path/where/songs/and/metadata/exists/
```
### Retrieving Song in json ### Retrieving Song in json
``icd retrieve -u spacecadet -p stellar40 -h https://icarus.com -rt songs``
```Bash
icd retrieve -u spacecadet -p stellar40 -h https://icarus.com -rt songs
```
### Deleting Song ### Deleting Song
``icd delete -u spacecadet -p stellar40 -h https://icarus.com -D 15``
```BASH
icd delete -u spacecadet -p stellar40 -h https://icarus.com -D 15
```
## Contributing ## Contributing
@@ -48,14 +90,16 @@ Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on the code of conduc
## Versioning ## Versioning
[v0.3.0](https://github.com/kdeng00/IcarusDownloadManager/releases/tag/v0.3.0)
[v0.2.0](https://github.com/kdeng00/IcarusDownloadManager/releases/tag/v0.2.0)
[v0.1.1](https://github.com/kdeng00/IcarusDownloadManager/releases/tag/v0.1.1) [v0.1.1](https://github.com/kdeng00/IcarusDownloadManager/releases/tag/v0.1.1)
[v0.1.0](https://github.com/kdeng00/IcarusDownloadManager/releases/tag/0.1.0) [v0.1.0](https://github.com/kdeng00/IcarusDownloadManager/releases/tag/0.1.0)
## Authors ## Authors
* **Kun Deng** - [amazing-username](https://github.com/amazing-username) * **Kun Deng** - [kdeng00](https://github.com/kdeng00)
See also the list of [contributors](https://github.com/amazing-username/Icarus/graphs/contributors) who participated in this project. See also the list of [contributors](https://github.com/kdeng00/Icarus/graphs/contributors) who participated in this project.
## License ## License
-528
View File
@@ -1,528 +0,0 @@
# Copyright (c) 2013-2019, Ruslan Baratov
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# This is a gate file to Hunter package manager.
# Include this file using `include` command and add package you need, example:
#
# cmake_minimum_required(VERSION 3.2)
#
# include("cmake/HunterGate.cmake")
# HunterGate(
# URL "https://github.com/path/to/hunter/archive.tar.gz"
# SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d"
# )
#
# project(MyProject)
#
# hunter_add_package(Foo)
# hunter_add_package(Boo COMPONENTS Bar Baz)
#
# Projects:
# * https://github.com/hunter-packages/gate/
# * https://github.com/ruslo/hunter
option(HUNTER_ENABLED "Enable Hunter package manager support" ON)
if(HUNTER_ENABLED)
if(CMAKE_VERSION VERSION_LESS "3.2")
message(
FATAL_ERROR
"At least CMake version 3.2 required for Hunter dependency management."
" Update CMake or set HUNTER_ENABLED to OFF."
)
endif()
endif()
include(CMakeParseArguments) # cmake_parse_arguments
option(HUNTER_STATUS_PRINT "Print working status" ON)
option(HUNTER_STATUS_DEBUG "Print a lot info" OFF)
option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON)
set(HUNTER_ERROR_PAGE "https://docs.hunter.sh/en/latest/reference/errors")
function(hunter_gate_status_print)
if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)
foreach(print_message ${ARGV})
message(STATUS "[hunter] ${print_message}")
endforeach()
endif()
endfunction()
function(hunter_gate_status_debug)
if(HUNTER_STATUS_DEBUG)
foreach(print_message ${ARGV})
string(TIMESTAMP timestamp)
message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}")
endforeach()
endif()
endfunction()
function(hunter_gate_error_page error_page)
message("------------------------------ ERROR ------------------------------")
message(" ${HUNTER_ERROR_PAGE}/${error_page}.html")
message("-------------------------------------------------------------------")
message("")
message(FATAL_ERROR "")
endfunction()
function(hunter_gate_internal_error)
message("")
foreach(print_message ${ARGV})
message("[hunter ** INTERNAL **] ${print_message}")
endforeach()
message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
message("")
hunter_gate_error_page("error.internal")
endfunction()
function(hunter_gate_fatal_error)
cmake_parse_arguments(hunter "" "ERROR_PAGE" "" "${ARGV}")
if("${hunter_ERROR_PAGE}" STREQUAL "")
hunter_gate_internal_error("Expected ERROR_PAGE")
endif()
message("")
foreach(x ${hunter_UNPARSED_ARGUMENTS})
message("[hunter ** FATAL ERROR **] ${x}")
endforeach()
message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
message("")
hunter_gate_error_page("${hunter_ERROR_PAGE}")
endfunction()
function(hunter_gate_user_error)
hunter_gate_fatal_error(${ARGV} ERROR_PAGE "error.incorrect.input.data")
endfunction()
function(hunter_gate_self root version sha1 result)
string(COMPARE EQUAL "${root}" "" is_bad)
if(is_bad)
hunter_gate_internal_error("root is empty")
endif()
string(COMPARE EQUAL "${version}" "" is_bad)
if(is_bad)
hunter_gate_internal_error("version is empty")
endif()
string(COMPARE EQUAL "${sha1}" "" is_bad)
if(is_bad)
hunter_gate_internal_error("sha1 is empty")
endif()
string(SUBSTRING "${sha1}" 0 7 archive_id)
set(
hunter_self
"${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked"
)
set("${result}" "${hunter_self}" PARENT_SCOPE)
endfunction()
# Set HUNTER_GATE_ROOT cmake variable to suitable value.
function(hunter_gate_detect_root)
# Check CMake variable
string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty)
if(not_empty)
set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE)
hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable")
return()
endif()
# Check environment variable
string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty)
if(not_empty)
set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE)
hunter_gate_status_debug("HUNTER_ROOT detected by environment variable")
return()
endif()
# Check HOME environment variable
string(COMPARE NOTEQUAL "$ENV{HOME}" "" result)
if(result)
set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE)
hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable")
return()
endif()
# Check SYSTEMDRIVE and USERPROFILE environment variable (windows only)
if(WIN32)
string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result)
if(result)
set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE)
hunter_gate_status_debug(
"HUNTER_ROOT set using SYSTEMDRIVE environment variable"
)
return()
endif()
string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result)
if(result)
set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE)
hunter_gate_status_debug(
"HUNTER_ROOT set using USERPROFILE environment variable"
)
return()
endif()
endif()
hunter_gate_fatal_error(
"Can't detect HUNTER_ROOT"
ERROR_PAGE "error.detect.hunter.root"
)
endfunction()
function(hunter_gate_download dir)
string(
COMPARE
NOTEQUAL
"$ENV{HUNTER_DISABLE_AUTOINSTALL}"
""
disable_autoinstall
)
if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL)
hunter_gate_fatal_error(
"Hunter not found in '${dir}'"
"Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'"
"Settings:"
" HUNTER_ROOT: ${HUNTER_GATE_ROOT}"
" HUNTER_SHA1: ${HUNTER_GATE_SHA1}"
ERROR_PAGE "error.run.install"
)
endif()
string(COMPARE EQUAL "${dir}" "" is_bad)
if(is_bad)
hunter_gate_internal_error("Empty 'dir' argument")
endif()
string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad)
if(is_bad)
hunter_gate_internal_error("HUNTER_GATE_SHA1 empty")
endif()
string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad)
if(is_bad)
hunter_gate_internal_error("HUNTER_GATE_URL empty")
endif()
set(done_location "${dir}/DONE")
set(sha1_location "${dir}/SHA1")
set(build_dir "${dir}/Build")
set(cmakelists "${dir}/CMakeLists.txt")
hunter_gate_status_debug("Locking directory: ${dir}")
file(LOCK "${dir}" DIRECTORY GUARD FUNCTION)
hunter_gate_status_debug("Lock done")
if(EXISTS "${done_location}")
# while waiting for lock other instance can do all the job
hunter_gate_status_debug("File '${done_location}' found, skip install")
return()
endif()
file(REMOVE_RECURSE "${build_dir}")
file(REMOVE_RECURSE "${cmakelists}")
file(MAKE_DIRECTORY "${build_dir}") # check directory permissions
# Disabling languages speeds up a little bit, reduces noise in the output
# and avoids path too long windows error
file(
WRITE
"${cmakelists}"
"cmake_minimum_required(VERSION 3.2)\n"
"project(HunterDownload LANGUAGES NONE)\n"
"include(ExternalProject)\n"
"ExternalProject_Add(\n"
" Hunter\n"
" URL\n"
" \"${HUNTER_GATE_URL}\"\n"
" URL_HASH\n"
" SHA1=${HUNTER_GATE_SHA1}\n"
" DOWNLOAD_DIR\n"
" \"${dir}\"\n"
" TLS_VERIFY\n"
" ${HUNTER_TLS_VERIFY}\n"
" SOURCE_DIR\n"
" \"${dir}/Unpacked\"\n"
" CONFIGURE_COMMAND\n"
" \"\"\n"
" BUILD_COMMAND\n"
" \"\"\n"
" INSTALL_COMMAND\n"
" \"\"\n"
")\n"
)
if(HUNTER_STATUS_DEBUG)
set(logging_params "")
else()
set(logging_params OUTPUT_QUIET)
endif()
hunter_gate_status_debug("Run generate")
# Need to add toolchain file too.
# Otherwise on Visual Studio + MDD this will fail with error:
# "Could not find an appropriate version of the Windows 10 SDK installed on this machine"
if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE)
set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}")
else()
# 'toolchain_arg' can't be empty
set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=")
endif()
string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make)
if(no_make)
set(make_arg "")
else()
# Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM
set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}")
endif()
execute_process(
COMMAND
"${CMAKE_COMMAND}"
"-H${dir}"
"-B${build_dir}"
"-G${CMAKE_GENERATOR}"
"${toolchain_arg}"
${make_arg}
WORKING_DIRECTORY "${dir}"
RESULT_VARIABLE download_result
${logging_params}
)
if(NOT download_result EQUAL 0)
hunter_gate_internal_error(
"Configure project failed."
"To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}"
"In directory ${dir}"
)
endif()
hunter_gate_status_print(
"Initializing Hunter workspace (${HUNTER_GATE_SHA1})"
" ${HUNTER_GATE_URL}"
" -> ${dir}"
)
execute_process(
COMMAND "${CMAKE_COMMAND}" --build "${build_dir}"
WORKING_DIRECTORY "${dir}"
RESULT_VARIABLE download_result
${logging_params}
)
if(NOT download_result EQUAL 0)
hunter_gate_internal_error("Build project failed")
endif()
file(REMOVE_RECURSE "${build_dir}")
file(REMOVE_RECURSE "${cmakelists}")
file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}")
file(WRITE "${done_location}" "DONE")
hunter_gate_status_debug("Finished")
endfunction()
# Must be a macro so master file 'cmake/Hunter' can
# apply all variables easily just by 'include' command
# (otherwise PARENT_SCOPE magic needed)
macro(HunterGate)
if(HUNTER_GATE_DONE)
# variable HUNTER_GATE_DONE set explicitly for external project
# (see `hunter_download`)
set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
endif()
# First HunterGate command will init Hunter, others will be ignored
get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET)
if(NOT HUNTER_ENABLED)
# Empty function to avoid error "unknown function"
function(hunter_add_package)
endfunction()
set(
_hunter_gate_disabled_mode_dir
"${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode"
)
if(EXISTS "${_hunter_gate_disabled_mode_dir}")
hunter_gate_status_debug(
"Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}"
)
list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}")
endif()
elseif(_hunter_gate_done)
hunter_gate_status_debug("Secondary HunterGate (use old settings)")
hunter_gate_self(
"${HUNTER_CACHED_ROOT}"
"${HUNTER_VERSION}"
"${HUNTER_SHA1}"
_hunter_self
)
include("${_hunter_self}/cmake/Hunter")
else()
set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}")
string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name)
if(_have_project_name)
hunter_gate_fatal_error(
"Please set HunterGate *before* 'project' command. "
"Detected project: ${PROJECT_NAME}"
ERROR_PAGE "error.huntergate.before.project"
)
endif()
cmake_parse_arguments(
HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV}
)
string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1)
string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url)
string(
COMPARE
NOTEQUAL
"${HUNTER_GATE_UNPARSED_ARGUMENTS}"
""
_have_unparsed
)
string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global)
string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath)
if(_have_unparsed)
hunter_gate_user_error(
"HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}"
)
endif()
if(_empty_sha1)
hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory")
endif()
if(_empty_url)
hunter_gate_user_error("URL suboption of HunterGate is mandatory")
endif()
if(_have_global)
if(HUNTER_GATE_LOCAL)
hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)")
endif()
if(_have_filepath)
hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)")
endif()
endif()
if(HUNTER_GATE_LOCAL)
if(_have_global)
hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)")
endif()
if(_have_filepath)
hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)")
endif()
endif()
if(_have_filepath)
if(_have_global)
hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)")
endif()
if(HUNTER_GATE_LOCAL)
hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)")
endif()
endif()
hunter_gate_detect_root() # set HUNTER_GATE_ROOT
# Beautify path, fix probable problems with windows path slashes
get_filename_component(
HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE
)
hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}")
if(NOT HUNTER_ALLOW_SPACES_IN_PATH)
string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces)
if(NOT _contain_spaces EQUAL -1)
hunter_gate_fatal_error(
"HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces."
"Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error"
"(Use at your own risk!)"
ERROR_PAGE "error.spaces.in.hunter.root"
)
endif()
endif()
string(
REGEX
MATCH
"[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*"
HUNTER_GATE_VERSION
"${HUNTER_GATE_URL}"
)
string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty)
if(_is_empty)
set(HUNTER_GATE_VERSION "unknown")
endif()
hunter_gate_self(
"${HUNTER_GATE_ROOT}"
"${HUNTER_GATE_VERSION}"
"${HUNTER_GATE_SHA1}"
_hunter_self
)
set(_master_location "${_hunter_self}/cmake/Hunter")
get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE)
set(_done_location "${_archive_id_location}/DONE")
set(_sha1_location "${_archive_id_location}/SHA1")
# Check Hunter already downloaded by HunterGate
if(NOT EXISTS "${_done_location}")
hunter_gate_download("${_archive_id_location}")
endif()
if(NOT EXISTS "${_done_location}")
hunter_gate_internal_error("hunter_gate_download failed")
endif()
if(NOT EXISTS "${_sha1_location}")
hunter_gate_internal_error("${_sha1_location} not found")
endif()
file(READ "${_sha1_location}" _sha1_value)
string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal)
if(NOT _is_equal)
hunter_gate_internal_error(
"Short SHA1 collision:"
" ${_sha1_value} (from ${_sha1_location})"
" ${HUNTER_GATE_SHA1} (HunterGate)"
)
endif()
if(NOT EXISTS "${_master_location}")
hunter_gate_user_error(
"Master file not found:"
" ${_master_location}"
"try to update Hunter/HunterGate"
)
endif()
include("${_master_location}")
set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
endif()
endmacro()
+69 -19
View File
@@ -1,6 +1,7 @@
#ifndef ACTIONMANAGER_H_ #ifndef ACTIONMANAGER_H_
#define ACTIONMANAGER_H_ #define ACTIONMANAGER_H_
#include<algorithm>
#include<string> #include<string>
#include<string_view> #include<string_view>
#include<array> #include<array>
@@ -11,33 +12,82 @@
namespace Managers namespace Managers
{ {
class ActionManager
class ActionManager
{
public:
ActionManager(char**, int);
Models::IcarusAction retrieveIcarusAction() const;
private:
constexpr std::array<const char*, 16> supportedFlags() noexcept
{ {
public: constexpr std::array<const char*, 16> allFlags{"-u", "-p", "-t", "-h", "-s",
ActionManager(char**, int); "-sd", "-sr", "-d", "-D", "-b", "-rt", "-nc",
"-m", "-ca", "-smca", "-t"};
Models::IcarusAction retrieveIcarusAction() const; return allFlags;
private: }
constexpr std::array<const char*, 12> supportedFlags() noexcept; constexpr std::array<const char*, 4> supportedActions() noexcept;
constexpr std::array<const char*, 4> supportedActions() noexcept;
bool isNumber(const std::string_view) noexcept; void initialize();
void validateFlags();
// Checks to see if the flag is valid
template<typename Str>
bool isValidFlag(const Str flag)
{
const auto flags = supportedFlags();
const auto i = std::find_if(flags.begin(), flags.end(), [&](const Str &f)
{
return f.compare(flag) == 0 ? true : false;
});
void initialize(); auto result = i != flags.end() ? true : false;
void validateFlags();
std::vector<std::string> parsedFlags(); return result;
}
void printAction() noexcept; template<typename Str>
void printFlags() noexcept; bool doesFlagHaveValue(const Str flag)
{
const auto flags = parsedFlags();
auto i = std::find_if(flags.begin(), flags.end(), [&](const Str &f)
{
return f.compare(flag) == 0 ? true : false;
});
std::string action; if (i != flags.end())
{
std::vector<Models::Flags> flags; if (++i != flags.end() && !isValidFlag<Str>(*i))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
void printAction() noexcept;
void printFlags() noexcept;
std::vector<std::string> parsedFlags();
std::string action;
std::vector<Models::Flags> flags;
char **params;
int paramCount;
};
char **params;
int paramCount;
};
} }
#endif #endif
+200 -29
View File
@@ -2,48 +2,219 @@
#define COMMITMANAGER_H_ #define COMMITMANAGER_H_
#include<map> #include<map>
#include<iostream>
#include<filesystem>
#include<string> #include<string>
#include<string_view>
#include"Models/API.h" #include"Models/API.h"
#include"Models/Token.h"
#include"Models/IcarusAction.h" #include"Models/IcarusAction.h"
#include"Models/Song.h"
#include"Models/Token.h"
#include"Utilities/Checks.h"
namespace Managers namespace Managers
{ {
class CommitManager
class CommitManager
{
public:
CommitManager(Models::IcarusAction&);
void commitAction();
enum class RetrieveTypes
{
songs
};
// Used for parsing songs from the metadata file
class Album
{ {
public: public:
CommitManager(Models::IcarusAction&); Album() = default;
void commitAction(); void printInfo();
enum class RetrieveTypes
{
songs
};
private: std::string album;
enum class ActionValues; std::string albumArtist;
std::string genre;
std::map<std::string, ActionValues> mapActions() noexcept; int year;
int trackCount;
Models::Token parseToken(Models::API); int discCount;
std::vector<Models::Song> songs;
void deleteSong();
void downloadSong();
void retrieveObjects();
void uploadSong();
enum class ActionValues
{
deleteAct,
downloadAct,
retrieveAct,
uploadAct
};
Models::IcarusAction icaAction;
}; };
private:
enum class ActionValues;
std::map<std::string, ActionValues> mapActions() noexcept;
void deleteSong();
void downloadSong();
void retrieveObjects();
void uploadSong();
Models::Token parseToken(Models::API);
// Uploads a single song. The song is constructed from a metadata file that contains
// information about the album the song is from. Also, the cover art of the song must
// be present.
//
// Expects
// * Song - mp3 file path
// * TrackID - track number to chose from when retrieving metadata. "1" and "1:1" are similar
// * Metadata - Source file containing metadata of the song
// * Cover art - path to image cover art
void uploadSongWithMetadata();
// Expects the song path, trackID, metadata file path, and cover path
void singTargetUpload(const std::string &songPath, const std::string &trackID,
const std::string &metaPath, const std::string &coverPath);
// Expects the source directory that contains songs, a metadata file, and cover image
// Disc and Track is retrieved from the filename if the filename conforms to a standard.
// If not, then the disc and track will default to 1
//
// Standards
// * track01.mp3 - Disc 1, Track 1
// * track05d02.mp3 - Disc 2, Track 5
void multiTargetUpload(const std::string &sourcePath);
// Standards
// * track01.mp3 - Disc 1, Track 1
// * track05d02.mp3 - Disc 2, Track 5
template<typename Song, typename Str>
void initializeDiscAndTrack(Song &song)
{
auto disc = 1;
auto track = 1;
// If 1 go with first standard, if 2 go with the second, if 0 then will default to 1 for disc and track
auto mode = 0;
const Str &songPath = song.songPath;
auto file = std::filesystem::path(songPath);
auto filename = file.filename().string();;
auto trd = song.songPath.find("trackd");
auto tr = song.songPath.find("track");
if (tr != Str::npos)
{
mode = 1;
}
if (trd != Str::npos)
{
mode = 2;
}
auto dl = [](char c, char t){ return c == t; };
auto d = Utilities::Checks::itemIterInContainer<char, Str>(filename, 'd', dl);
auto k = Utilities::Checks::itemIterInContainer<char, Str>(filename, 'k', dl);
auto dot = Utilities::Checks::itemIterInContainer<char, Str>(filename, '.', dl);
switch(mode)
{
case 1:
{
// if (k != songPath.end() && dot != songPath.end())
if (k != filename.end() && dot != filename.end())
{
auto tStr = std::string(++k, dot);
std::cout << "TStr: " << tStr<<"\n";
if (Utilities::Checks::isNumber(tStr))
{
track = std::atoi(tStr.c_str());
}
}
break;
}
case 2:
{
// if (k != songPath.end() && dot != songPath.end() && d != songPath.end())
if (k != filename.end() && dot != filename.end() && d != filename.end())
{
auto tStr = std::string(++k, d);
auto dStr = std::string(++d, dot);
std::cout<<"DStr: "<<dStr<<" TStr: " << tStr<<"\n";
if (Utilities::Checks::isNumber(tStr))
{
track = std::atoi(tStr.c_str());
}
else if (Utilities::Checks::isNumber(dStr))
{
disc = std::atoi(dStr.c_str());
}
}
break;
}
}
song.disc = disc;
song.track = track;
}
template<typename Song, typename Str>
void parseDiscAndTrack(Song &song, const Str &trackID)
{
auto sep = [](char c, char t) { return c == t; };
auto separator = Utilities::Checks::itemIterInContainer<char, Str>(trackID, ':', sep);
if (separator != trackID.end())
{
auto dStr = Str(trackID.begin(), separator);
auto tStr = Str(++separator, trackID.end());
song.disc = std::atoi(dStr.c_str());
song.track = std::atoi(tStr.c_str());
}
else
{
auto isNumber = Utilities::Checks::isNumber(trackID);
if (isNumber)
{
song.track = std::atoi(trackID.c_str());
}
}
}
// Checks for the no confirm flag. Used when uploading songs from a directory
bool checkForNoConfirm()
{
for (const auto &arg: this->icaAction.flags)
{
if (arg.flag.compare("-nc") == 0)
{
return true;
}
}
return false;
}
Album retrieveMetadata(const std::string_view path);
std::string retrieveFileContent(const std::string_view path);
enum class ActionValues
{
deleteAct,
downloadAct,
retrieveAct,
uploadAct,
UPLOAD_SONG_WITH_METADATA // Uploads the song with metadata, including cover art
};
Models::IcarusAction icaAction;
};
} }
#endif #endif
+18 -16
View File
@@ -5,25 +5,27 @@
namespace Managers namespace Managers
{ {
class FileManager
{
public:
FileManager();
FileManager(std::string);
void saveFile(std::string); class FileManager
void modifyFilePath(std::string); {
public:
FileManager();
FileManager(std::string);
char* retrieveFileBuffer() const; void saveFile(std::string);
int retrieveFileBufferLength() const; void modifyFilePath(std::string);
private:
void readFile(); char* retrieveFileBuffer() const;
int retrieveFileBufferLength() const;
private:
void readFile();
std::string filePath;
char* fileBuffer;
bool fileRead;
int fileBufferLength;
};
std::string filePath;
char* fileBuffer;
bool fileRead;
int fileBufferLength;
};
} }
#endif #endif
+12 -10
View File
@@ -7,17 +7,19 @@
namespace Managers namespace Managers
{ {
class TokenManager
{
public:
TokenManager(const Models::User&);
TokenManager(const Models::User&, Models::API&);
Models::Token requestToken(); class TokenManager
private: {
Models::API api; public:
Models::User user; TokenManager(const Models::User&);
}; TokenManager(const Models::User&, Models::API&);
Models::Token requestToken();
private:
Models::API api;
Models::User user;
};
} }
#endif #endif
+13 -11
View File
@@ -8,19 +8,21 @@
namespace Managers namespace Managers
{ {
class UserManager
{
public:
UserManager(Models::User);
UserManager(const Models::IcarusAction);
Models::User retrieveUser() const; class UserManager
private: {
void parseUserFromActions(); public:
UserManager(Models::User);
UserManager(const Models::IcarusAction);
Models::User retrieveUser() const;
private:
void parseUserFromActions();
Models::User user;
Models::IcarusAction icaAction;
};
Models::User user;
Models::IcarusAction icaAction;
};
} }
#endif #endif
+9 -6
View File
@@ -5,12 +5,15 @@
namespace Models namespace Models
{ {
struct API
{ class API
std::string url; {
std::string endpoint; public:
std::string version; std::string url;
}; std::string endpoint;
std::string version;
};
} }
#endif #endif
+8 -5
View File
@@ -5,11 +5,14 @@
namespace Models namespace Models
{ {
struct Flags
{ class Flags
std::string flag; {
std::string value; public:
}; std::string flag;
std::string value;
};
} }
#endif #endif
+39 -4
View File
@@ -2,17 +2,52 @@
#define ICARUSACTION_H_ #define ICARUSACTION_H_
#include<string> #include<string>
#include<algorithm>
#include<string_view>
#include<vector> #include<vector>
#include<iostream>
#include"Flags.h" #include"Flags.h"
namespace Models namespace Models
{ {
struct IcarusAction
class IcarusAction
{
public:
std::string retrieveFlagValue(const std::string_view flag)
{ {
std::string action; std::string value;
std::vector<Flags> flags;
}; const auto fg = std::find_if(flags.begin(), flags.end(), [&](Flags f)
{
return f.flag.compare(flag) == 0 ? true : false;
});
if (fg != flags.end())
{
value.assign(fg->value);
}
return value;
}
void print_action_and_flags() noexcept
{
std::cout<<"Action: "<<this->action<<"\n";
std::cout<<"Flag count: "<<this->flags.size()<<"\n";
for (const auto &flag : this->flags)
{
std::cout<<"flag "<<flag.flag<<" value "<<flag.value<<"\n";
}
std::cout<<"\n";
}
std::string action;
std::vector<Flags> flags;
};
} }
#endif #endif
+79 -13
View File
@@ -1,24 +1,90 @@
#ifndef SONG_H_ #ifndef SONG_H_
#define SONG_H_ #define SONG_H_
#include<string> #include <string>
#include <iostream>
#include <sstream>
namespace Models namespace Models
{ {
struct Song
class Song
{
public:
Song() = default;
void printInfo()
{ {
int id; std::cout<<"Title: "<<this->title<<"\n";
std::string title; std::cout<<"\n";
std::string artist; }
std::string album;
std::string genre; std::string song_path() noexcept
int year; {
int duration; std::stringstream buffer;
int track;
std::string data; buffer << this->directory;
std::string songPath;
}; const auto count = this->directory.size();
if (this->directory.at(count - 1) != '/' || this->directory.at(count - 1) != '\\')
{
buffer << "/";
}
buffer << this->filename;
return buffer.str();
}
int generate_filename_from_track()
{
auto result = 0;
std::stringstream buffer;
buffer << "track";
// NOTE: Multiple discs in one directory is not being addressed
if (this->track < 10)
{
buffer << "0";
}
buffer << this->track << ".mp3";
this->filename.assign(buffer.str());
return result;
}
std::string toMetadataJson();
int id;
std::string title;
std::string artist;
std::string album;
std::string genre;
int year;
int duration;
int track;
int disc;
std::string data;
[[deprecated("Use song_path() function instead")]]
std::string songPath;
std::string filename;
std::string directory;
};
class CoverArt
{
public:
int id;
std::string title;
std::string path;
};
} }
#endif #endif
+8 -6
View File
@@ -5,12 +5,14 @@
namespace Models namespace Models
{ {
struct Token
{ struct Token
std::string accessToken; {
std::string tokenType; std::string accessToken;
int expiration; std::string tokenType;
}; int expiration;
};
} }
#endif #endif
+7 -5
View File
@@ -6,11 +6,13 @@
namespace Models namespace Models
{ {
struct UploadForm
{ struct UploadForm
std::string url; {
std::string filePath; std::string url;
}; std::string filePath;
};
} }
#endif #endif
+7 -5
View File
@@ -5,11 +5,13 @@
namespace Models namespace Models
{ {
struct User
{ struct User
std::string username; {
std::string password; std::string username;
}; std::string password;
};
} }
#endif #endif
+12 -10
View File
@@ -6,18 +6,20 @@
namespace Parsers namespace Parsers
{ {
class APIParser
{
public:
APIParser(Models::IcarusAction);
Models::API retrieveAPI() const; class APIParser
private: {
void parseAPI(); public:
APIParser(Models::IcarusAction);
Models::API retrieveAPI() const;
private:
void parseAPI();
Models::API api;
Models::IcarusAction icaAct;
};
Models::API api;
Models::IcarusAction icaAct;
};
} }
#endif #endif
+10 -8
View File
@@ -9,15 +9,17 @@
namespace Syncers namespace Syncers
{ {
class Delete : SyncerBase
{
public:
Delete(Models::API);
void deleteSong(const Models::Token, Models::Song); class Delete : SyncerBase
private: {
std::string retrieveUrl(Models::Song); public:
}; Delete(Models::API);
void deleteSong(const Models::Token, Models::Song);
private:
std::string retrieveUrl(Models::Song);
};
} }
#endif #endif
+14 -12
View File
@@ -12,20 +12,22 @@
namespace Syncers namespace Syncers
{ {
class Download : SyncerBase
{
public:
Download();
Download(Models::API);
Download(std::string);
void downloadSong(const Models::Token token, Models::Song); class Download : SyncerBase
private: {
std::string retrieveUrl(Models::Song); public:
Download();
Download(Models::API);
Download(std::string);
void downloadSong(const Models::Token token, Models::Song);
private:
std::string retrieveUrl(Models::Song);
std::string downloadFilePath;
void saveSong(Models::Song&);
};
std::string downloadFilePath;
void saveSong(Models::Song&);
};
} }
#endif #endif
+13 -11
View File
@@ -8,19 +8,21 @@
namespace Syncers namespace Syncers
{ {
class RetrieveRecords: public SyncerBase
{
public:
RetrieveRecords();
RetrieveRecords(Models::API, Models::Token);
void retrieve(Managers::CommitManager::RetrieveTypes); class RetrieveRecords: public SyncerBase
private: {
void fetchSongs(); public:
RetrieveRecords();
RetrieveRecords(Models::API, Models::Token);
void retrieve(Managers::CommitManager::RetrieveTypes);
private:
void fetchSongs();
Models::API api;
Models::Token token;
};
Models::API api;
Models::Token token;
};
} }
#endif #endif
+15 -13
View File
@@ -7,21 +7,23 @@
namespace Syncers namespace Syncers
{ {
class SyncerBase
{
protected:
Models::API api;
const int OK = 200;
const int UNAUTHORIZED = 401;
const int NOTFOUND = 404;
enum class Result class SyncerBase
{ {
OK = 200, protected:
UNAUTHORIZED = 401, Models::API api;
NOTFOUND = 404 const int OK = 200;
}; const int UNAUTHORIZED = 401;
const int NOTFOUND = 404;
enum class Result
{
OK = 200,
UNAUTHORIZED = 401,
NOTFOUND = 404
}; };
};
} }
#endif #endif
+35 -28
View File
@@ -1,48 +1,55 @@
#ifndef UPLOAD_H_ #ifndef UPLOAD_H_
#define UPLOAD_H_ #define UPLOAD_H_
#include<filesystem> #include <filesystem>
#include<string> #include <string>
#include<vector> #include <vector>
#include<nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include"Managers/FileManager.h" #include "Managers/CommitManager.h"
#include"Models/API.h" #include "Managers/FileManager.h"
#include"Models/Song.h" #include "Models/API.h"
#include"Models/Token.h" #include "Models/Song.h"
#include"Models/UploadForm.h" #include "Models/Token.h"
#include "Models/UploadForm.h"
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Syncers namespace Syncers
{ {
class Upload
class Upload
{
public:
Upload() = default;
Upload(Models::API api, Models::Token token) : m_token(token), api(api)
{ {
public: this->api.endpoint = "song/data";
Upload(); }
Upload(Models::API);
Models::Song uploadSong(const Models::Token&, Models::Song&); Models::Song uploadSong(Models::Song&);
void uploadSongsFromDirectory(const Models::Token&, void uploadSongsFromDirectory(const std::string&, const bool, bool);
const std::string&, const bool, bool); void uploadSongWithMetadata(Managers::CommitManager::Album&, Models::Song&, Models::CoverArt&);
private: private:
Managers::FileManager fMgr; Managers::FileManager fMgr;
Models::API api; Models::API api;
Models::Song song; Models::Song song;
Models::Token m_token;
std::vector<Models::Song> retrieveAllSongsFromDirectory(const std::string&, std::vector<Models::Song> retrieveAllSongsFromDirectory(const std::string&,
bool); bool);
std::string retrieveUrl(); std::string retrieveUrl();
Models::Song retrieveSongPath(fs::directory_entry&); Models::Song retrieveSongPath(fs::directory_entry&);
void printSongDetails();
void printSongDetails(std::vector<Models::Song>&);
void printJsonData(const nlohmann::json&);
};
void printSongDetails();
void printSongDetails(std::vector<Models::Song>&);
void printJsonData(const nlohmann::json&);
};
} }
#endif #endif
+15 -13
View File
@@ -13,22 +13,24 @@
namespace UI namespace UI
{ {
class AboutWindow: public QDialog, public CommonWindow
{
Q_OBJECT
public:
AboutWindow(QWidget* parent=0);
~AboutWindow() = default;
private: class AboutWindow: public QDialog, public CommonWindow
void connections(); {
void setupWindow(); Q_OBJECT
public:
AboutWindow(QWidget* parent=0);
~AboutWindow() = default;
std::unique_ptr<QLabel> appName; private:
void connections();
void setupWindow();
std::unique_ptr<QLabel> appName;
private slots:
void closeWindow();
};
private slots:
void closeWindow();
};
} }
#endif #endif
+6
View File
@@ -10,6 +10,9 @@
#include<QPushButton> #include<QPushButton>
namespace UI
{
class CommonWindow class CommonWindow
{ {
public: public:
@@ -24,4 +27,7 @@ protected:
std::unique_ptr<QVBoxLayout> subLayoutTwoQt; std::unique_ptr<QVBoxLayout> subLayoutTwoQt;
int windowHeight, windowWidth; int windowHeight, windowWidth;
}; };
}
#endif #endif
+45 -43
View File
@@ -22,61 +22,63 @@
namespace UI namespace UI
{ {
class MainWindow: public QMainWindow, public CommonWindow
{ class MainWindow: public QMainWindow, public CommonWindow
Q_OBJECT {
public: Q_OBJECT
MainWindow(); public:
~MainWindow() = default; MainWindow();
private: ~MainWindow() = default;
void configureDownloadSection(); private:
void configureUploadSection(); void configureDownloadSection();
void configureWindowDimensions(); void configureUploadSection();
void configureWindowProperties(); void configureWindowDimensions();
void connections(); void configureWindowProperties();
void createMenus(); void connections();
void setupMainWidget(); void createMenus();
void setupMainWindow(); void setupMainWidget();
void setupWindowLists(); void setupMainWindow();
void setupWindowLists();
std::unique_ptr<QStackedWidget> widgetStack; std::unique_ptr<QStackedWidget> widgetStack;
std::unique_ptr<QVBoxLayout> stackLayout; std::unique_ptr<QVBoxLayout> stackLayout;
std::unique_ptr<QHBoxLayout> urlPortion; std::unique_ptr<QHBoxLayout> urlPortion;
std::unique_ptr<QHBoxLayout> songPathPortion; std::unique_ptr<QHBoxLayout> songPathPortion;
std::unique_ptr<QWidget> mainWidgetQt; std::unique_ptr<QWidget> mainWidgetQt;
std::unique_ptr<QWidget> uploadSongWidgetQt; std::unique_ptr<QWidget> uploadSongWidgetQt;
std::unique_ptr<QDockWidget> MainDockWidgetQt; std::unique_ptr<QDockWidget> MainDockWidgetQt;
std::unique_ptr<QComboBox> windowComboBox; std::unique_ptr<QComboBox> windowComboBox;
std::unique_ptr<QPushButton> uploadSongQt; std::unique_ptr<QPushButton> uploadSongQt;
std::unique_ptr<QTextEdit> urlQt; std::unique_ptr<QTextEdit> urlQt;
std::unique_ptr<QTextEdit> sourceFilePathQt; std::unique_ptr<QTextEdit> sourceFilePathQt;
std::unique_ptr<QLabel> urlLabel; std::unique_ptr<QLabel> urlLabel;
std::unique_ptr<QLabel> songPath; std::unique_ptr<QLabel> songPath;
std::unique_ptr<QMenu> fileMenuQt; std::unique_ptr<QMenu> fileMenuQt;
std::unique_ptr<QMenu> editMenuQt; std::unique_ptr<QMenu> editMenuQt;
std::unique_ptr<QMenu> helpMenuQt; std::unique_ptr<QMenu> helpMenuQt;
std::unique_ptr<QAction> closeApplicationQt; std::unique_ptr<QAction> closeApplicationQt;
std::unique_ptr<QAction> aboutApplicationQt; std::unique_ptr<QAction> aboutApplicationQt;
std::unique_ptr<AboutWindow> aboutWindow;
signals:
private slots:
void uploadSong();
void exitApplication();
void displaySoftwareInformation();
void setCurrentIndex(int);
};
std::unique_ptr<AboutWindow> aboutWindow;
signals:
private slots:
void uploadSong();
void exitApplication();
void displaySoftwareInformation();
void setCurrentIndex(int);
};
} }
#endif #endif
+67
View File
@@ -0,0 +1,67 @@
#ifndef CHECKS_H_
#define CHECKS_H_
#include<algorithm>
#include<string>
#include<cstdlib>
#include<ctype.h>
namespace Utilities
{
class Checks
{
public:
Checks() = delete;
static auto isNumber(const std::string &val)
{
return !val.empty() && std::find_if(val.begin(),
val.end(), [](char c)
{
return !std::isdigit(c);
}) == val.end();
}
// Note: Not implemented
template<typename Item, typename Container, typename Func>
static auto itemInContainer(const Container container, const Item item, Func func)
{
auto result = false;
auto i = std::find_if(container.begin(), container.end(), [&](Item i)
{
return func(item, i);
});
if (i != container.end())
{
result = true;
}
return result;
}
template<typename Item, typename Container, typename Func>
static auto itemIterInContainer(const Container &container, const Item &item, Func func)
{
auto result = false;
auto ii = std::find_if(container.begin(), container.end(), [&](Item i)
{
return func(i, item);
});
if (ii == container.end())
{
ii = container.end();
}
return ii;
}
private:
};
}
#endif
+18 -8
View File
@@ -6,17 +6,27 @@
namespace Utilities namespace Utilities
{ {
class Conversions
class Conversions
{
public:
Conversions();
static void toLowerChar(char &c)
{ {
public: if (std::isalpha(c))
Conversions(); {
c = std::tolower(c);
}
}
void initializeValues(); void initializeValues();
template<typename T>
void printValue(T val);
private:
};
template <typename T>
void printValue(T);
private:
};
} }
#endif #endif
+14
View File
@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by IcarusDownloadManager.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
-1
View File
@@ -1 +0,0 @@
cmake -H. -B_builds -DHUNTER_STATUS_DEBUG=ON -DCMAKE_BUILD_TYPE=DEBUG
-1
View File
@@ -1 +0,0 @@
cmake --build _builds --config Debug
-1
View File
@@ -1 +0,0 @@
cmake --build _builds --config Release
+15
View File
@@ -12,6 +12,11 @@ using std::string;
using Managers::ActionManager; using Managers::ActionManager;
using Managers::CommitManager; using Managers::CommitManager;
constexpr static auto IcarusDownloadManager_version()
{
return "v0.3.2";
}
void printHelp() void printHelp()
{ {
cout<<"icd [Action] [flag]\n\n"; cout<<"icd [Action] [flag]\n\n";
@@ -19,6 +24,7 @@ void printHelp()
cout<<"Actions\n"; cout<<"Actions\n";
cout<<"download\n"; cout<<"download\n";
cout<<"upload\n"; cout<<"upload\n";
cout<<"upload-meta\n";
cout<<"retrieve\n"; cout<<"retrieve\n";
cout<<"delete\n\n"; cout<<"delete\n\n";
@@ -34,6 +40,13 @@ void printHelp()
cout<<"-sr directory where to recursively search for songs to upload (Optional)\n"; cout<<"-sr directory where to recursively search for songs to upload (Optional)\n";
cout<<"-nc will not prompt the user when uploading from a directory\n\n"; cout<<"-nc will not prompt the user when uploading from a directory\n\n";
cout<<"Required for upload with metadata\n";
cout<<"-s path of song\n";
cout<<"-t track number\n";
cout<<"-m metadata filepath\n";
cout<<"-ca coverart filepath\n";
cout<<"-scma directory where songs, metadata, and cover art exists and will be uploaded (Optional)\n\n";
cout<<"Required for download\n"; cout<<"Required for download\n";
cout<<"-b song id\n"; cout<<"-b song id\n";
cout<<"-d path to download song (Optional)\n\n"; cout<<"-d path to download song (Optional)\n\n";
@@ -57,6 +70,8 @@ int main(int argc, char** argv)
ActionManager actMgr(argv, argc); ActionManager actMgr(argv, argc);
auto chosenAction = actMgr.retrieveIcarusAction(); auto chosenAction = actMgr.retrieveIcarusAction();
chosenAction.print_action_and_flags();
CommitManager commitMgr(chosenAction); CommitManager commitMgr(chosenAction);
commitMgr.commitAction(); commitMgr.commitAction();
+89 -116
View File
@@ -16,130 +16,103 @@ using Models::IcarusAction;
namespace Managers namespace Managers
{ {
#pragma
ActionManager::ActionManager(char **param, int paramCount) : #pragma region Constructors
params(std::move(param)), paramCount(paramCount) ActionManager::ActionManager(char **param, int paramCount) :
params(std::move(param)), paramCount(paramCount)
{
initialize();
}
#pragma endregion
#pragma region Functions
IcarusAction ActionManager::retrieveIcarusAction() const
{
IcarusAction icarusAction;
icarusAction.flags = flags;
icarusAction.action = action;
return icarusAction;
}
void ActionManager::initialize()
{
validateFlags();
action = std::move(string{params[1]});
transform(action.begin(), action.end(),
action.begin(), ::tolower);
}
void ActionManager::validateFlags()
{
cout<<"Validating flags\n";
const auto flagVals = parsedFlags();
for (auto flag = flagVals.begin(); flag != flagVals.end(); ++flag)
{ {
initialize(); Flags flg;
} cout<<"Value: "<<*flag<<"\n";
#pragma Constructors
if (isValidFlag<string>(*flag) && doesFlagHaveValue<string>(*flag))
#pragma
IcarusAction ActionManager::retrieveIcarusAction() const
{
IcarusAction icarusAction;
icarusAction.flags = flags;
icarusAction.action = action;
return icarusAction;
}
constexpr std::array<const char*, 12> ActionManager::supportedFlags() noexcept
{
constexpr std::array<const char*, 12> allFlags{"-u", "-p", "-t", "-h", "-s",
"-sd", "-sr", "-d", "-D", "-b", "-rt", "-nc"};
return allFlags;
}
bool ActionManager::isNumber(string_view val) noexcept
{
return !val.empty() && std::find_if(val.begin(),
val.end(), [](char c)
{
return !std::isdigit(c);
}) == val.end();
}
void ActionManager::initialize()
{
validateFlags();
action = std::move(string{params[1]});
transform(action.begin(), action.end(),
action.begin(), ::tolower);
}
void ActionManager::validateFlags()
{
cout<<"Validating flags"<<endl;
auto flagVals = parsedFlags();
Flags flg{};
auto allSupportedFlags = supportedFlags();
for (auto flag : flagVals)
{ {
if (flag.compare("-nc") == 0) cout<<"Flag has value\n";
{ flg.flag = *flag;
flg.flag = flag; flg.value = *(++flag);
flags.push_back(flg);
continue;
}
if (flag.size() > 3 || isNumber(flag))
{
flg.value = flag;
//cout<<"flag value "<<flg.value<<endl;
flags.push_back(flg);
flg = Flags{};
continue;
}
if (std::any_of(allSupportedFlags.begin(), allSupportedFlags.end(),
[&](const char *val)
{
return !flag.compare(val);
}))
{
//cout<<"flag "<<flag<<endl;
flg.flag = flag;
}
else
{
cout<<"Flag is not valid"<<endl;
exit(1);
}
} }
} else if (isValidFlag<string>(*flag))
vector<string> ActionManager::parsedFlags()
{
auto parsed = vector<string>();
for (auto i = 2; i < paramCount; ++i)
{ {
const std::string flag(std::move(*(params + i))); cout<<"Flag does not have a value\n";
parsed.push_back(std::move(flag)); flg.flag = *flag;
}
return parsed;
}
#pragma
void ActionManager::printAction() noexcept
{
if (action.empty())
{
printf("Action is empty\n");
} }
else else
{ {
cout<<"Action is "<<action<<endl; cout<<"Flag "<<*flag<<" is not valid"<<endl;
exit(1);
} }
flags.emplace_back(std::move(flg));
} }
void ActionManager::printFlags() noexcept }
{
cout<<"\nPrinting flags..."<<endl; vector<string> ActionManager::parsedFlags()
for (auto flag: flags) {
{ auto parsed = vector<string>();
cout<<"flag "<<flag.flag<<endl;
cout<<"value "<<flag.value<<endl; for (auto i = 2; i < paramCount; ++i)
} {
} const std::string flag(std::move(*(params + i)));
#pragma Testing parsed.push_back(std::move(flag));
#pragma Functions }
return parsed;
}
#pragma region Testing
void ActionManager::printAction() noexcept
{
if (action.empty())
{
printf("Action is empty\n");
}
else
{
cout<<"Action is "<<action<<endl;
}
}
void ActionManager::printFlags() noexcept
{
cout<<"\nPrinting flags..."<<endl;
for (auto flag: flags)
{
cout<<"flag "<<flag.flag<<endl;
cout<<"value "<<flag.value<<endl;
}
}
#pragma endregion
#pragma endregion
} }
+421 -193
View File
@@ -1,18 +1,23 @@
#include"Managers/CommitManager.h" #include"Managers/CommitManager.h"
#include<iostream> #include <iostream>
#include <fstream>
#include <sstream>
#include <filesystem>
#include"Models/API.h" #include "nlohmann/json.hpp"
#include"Models/Song.h"
#include"Models/Token.h"
#include"Parsers/APIParser.h"
#include"Syncers/Delete.h"
#include"Syncers/Download.h"
#include"Syncers/RetrieveRecords.h"
#include"Syncers/Upload.h"
#include"Managers/TokenManager.h" #include "Models/API.h"
#include"Managers/UserManager.h" #include "Models/Song.h"
#include "Models/Token.h"
#include "Parsers/APIParser.h"
#include "Syncers/Delete.h"
#include "Syncers/Download.h"
#include "Syncers/RetrieveRecords.h"
#include "Syncers/Upload.h"
#include "Managers/TokenManager.h"
#include "Managers/UserManager.h"
using std::cout; using std::cout;
using std::endl; using std::endl;
@@ -31,199 +36,422 @@ using Syncers::Download;
using Syncers::RetrieveRecords; using Syncers::RetrieveRecords;
using Syncers::Upload; using Syncers::Upload;
namespace filesystem = std::filesystem;
namespace Managers namespace Managers
{ {
#pragma
CommitManager::CommitManager(IcarusAction& icaAct) : icaAction(std::move(icaAct)) #pragma region Constructors
{ } CommitManager::CommitManager(IcarusAction& icaAct) : icaAction(std::move(icaAct))
#pragma Constructors { }
#pragma endregion
#pragma #pragma region Functions
void CommitManager::commitAction() void CommitManager::commitAction()
{ {
auto action = icaAction.action; auto action = icaAction.action;
cout<<"Commiting "<<action<<" action"<<endl; cout<<"Commiting "<<action<<" action"<<endl;
switch (mapActions()[action])
{
case ActionValues::deleteAct:
deleteSong();
break;
case ActionValues::downloadAct:
downloadSong();
break;
case ActionValues::retrieveAct:
retrieveObjects();
break;
case ActionValues::uploadAct:
uploadSong();
break;
default:
break;
}
}
switch (mapActions()[action])
enum class ActionValues;
std::map<std::string, CommitManager::ActionValues>
CommitManager::mapActions() noexcept
{ {
const std::map<std::string, ActionValues> actions{ case ActionValues::deleteAct:
{"delete", ActionValues::deleteAct}, deleteSong();
{"download", ActionValues::downloadAct}, break;
{"retrieve", ActionValues::retrieveAct}, case ActionValues::downloadAct:
{"upload", ActionValues::uploadAct} downloadSong();
break;
case ActionValues::retrieveAct:
retrieveObjects();
break;
case ActionValues::uploadAct:
uploadSong();
break;
case ActionValues::UPLOAD_SONG_WITH_METADATA:
uploadSongWithMetadata();
break;
default:
break;
}
}
std::map<std::string, CommitManager::ActionValues>
CommitManager::mapActions() noexcept
{
const std::map<std::string, ActionValues> actions{
{"delete", ActionValues::deleteAct},
{"download", ActionValues::downloadAct},
{"retrieve", ActionValues::retrieveAct},
{"upload", ActionValues::uploadAct},
{"upload-meta", ActionValues::UPLOAD_SONG_WITH_METADATA}
};
return actions;
}
Token CommitManager::parseToken(API api)
{
cout<<"fetching token\n";
UserManager usrMgr{icaAction};
auto user = usrMgr.retrieveUser();
TokenManager tk{user, api};
return tk.requestToken();
}
void CommitManager::deleteSong()
{
APIParser apiPrs{icaAction};
auto api = apiPrs.retrieveAPI();
auto token = parseToken(api);
Song song{};
for (auto arg : icaAction.flags)
{
auto flag = arg.flag;
auto value = arg.value;
if (flag.compare("-D") == 0)
{
song.id = atoi(value.c_str());
}
}
Delete del{api};
cout<<"Deleting song..."<<endl;
del.deleteSong(token, song);
}
void CommitManager::downloadSong()
{
cout<<"Starting downloading process..."<<endl;
APIParser apiPrs{icaAction};
auto api = apiPrs.retrieveAPI();
auto token = parseToken(api);
Song song{};
for (auto arg : icaAction.flags)
{
auto flag = arg.flag;
auto value = arg.value;
if (flag.compare("-d") == 0)
{
song.songPath.assign(arg.value);
}
if (flag.compare("-b") == 0)
{
song.id = atoi(value.c_str());
}
}
Download dnld{api};
cout<<"downloading song"<<endl;
dnld.downloadSong(token, song);
}
void CommitManager::retrieveObjects()
{
cout<<"Starting retrieve process..."<<endl;
APIParser apiPrs{icaAction};
auto api = apiPrs.retrieveAPI();
auto token = parseToken(api);
RetrieveTypes retrieveType;
for (auto arg : icaAction.flags)
{
auto flag = arg.flag;
auto value = arg.value;
if (flag.compare("-rt") == 0)
{
if (value.compare("songs") == 0)
{
retrieveType = RetrieveTypes::songs;
break;
}
}
}
RetrieveRecords songs{api, token};
songs.retrieve(retrieveType);
}
void CommitManager::uploadSong()
{
auto uploadSingleSong = true;
auto recursiveDirectory = false;
const auto noConfirm = checkForNoConfirm();
string songDirectory;
APIParser apiPrs{icaAction};
auto api = apiPrs.retrieveAPI();
auto token = parseToken(api);
Song song;
for (auto& arg : icaAction.flags)
{
auto flag = arg.flag;
auto value = arg.value;
if (flag.compare("-s") == 0)
{
song.songPath.assign(arg.value);
}
else if (flag.compare("-sd") == 0)
{
songDirectory = value;
uploadSingleSong = false;
}
else if (flag.compare("-sr") == 0)
{
songDirectory = value;
uploadSingleSong = false;
recursiveDirectory = true;
}
}
Upload upld{api, token};
if (uploadSingleSong)
{
cout<<"Uploading song..."<<endl;
upld.uploadSong(song);
}
else
{
cout<<"Uploading songs from " << songDirectory << endl;
upld.uploadSongsFromDirectory(songDirectory, noConfirm, recursiveDirectory);
}
}
void CommitManager::uploadSongWithMetadata()
{
cout<<"Uploading single song with metadata\n\n";
// Either the set of "-s", "-m", "-ca", "-t" flags or "-smca" must exist with values
// in order to be valid but not both
const auto songPath = this->icaAction.retrieveFlagValue("-s");
const auto metadataPath = this->icaAction.retrieveFlagValue("-m");
const auto coverPath = this->icaAction.retrieveFlagValue("-ca");
const auto trackID = this->icaAction.retrieveFlagValue("-t");
const auto singleTarget = !songPath.empty() && !metadataPath.empty() &&
!coverPath.empty() && !trackID.empty() ? true : false;
const auto uni = this->icaAction.retrieveFlagValue("-smca");
const auto multiTarget = !uni.empty() ? true : false;
if (singleTarget && multiTarget)
{
cout<<"Cannot upload from source and directory\n";
return;
}
cout<<"Song path: "<<songPath<<"\n";
cout<<"TrackID: "<<trackID<<"\n";
cout<<"Metadata path: "<<metadataPath<<"\n";
cout<<"Cover Art path: "<<coverPath<<"\n";
if (singleTarget)
{
singTargetUpload(songPath, trackID, metadataPath, coverPath);
}
else if (multiTarget)
{
multiTargetUpload(uni);
}
}
void CommitManager::singTargetUpload(const std::string &songPath, const std::string &trackID,
const std::string &metaPath, const std::string &coverPath)
{
APIParser apiPrs(icaAction);
auto api = apiPrs.retrieveAPI();
const auto token = parseToken(api);
auto album = retrieveMetadata(metaPath);
album.printInfo();
Song song;
song.track = 1;
song.disc = 1;
cout<<"TrackID: "<<trackID<<"\n";
parseDiscAndTrack<Song, std::string>(song, trackID);
auto c = [](const Song &songA, const Song &songB) { return songA.track == songB.track && songA.disc == songB.disc; };
auto sng = Utilities::Checks::itemIterInContainer<Song, std::vector<Song>>(album.songs, song, c);
if (sng == album.songs.end())
{
cout<<"Not found with disc "<<song.disc<<" track "<<song.track<<"\n";
std::exit(-1);
}
song = *sng;
const auto p = filesystem::path(songPath);
song.directory = p.parent_path().string();
song.generate_filename_from_track();
Models::CoverArt cover;
cover.title = song.title;
cover.path = coverPath;
Upload up(api, token);
up.uploadSongWithMetadata(album, song, cover);
}
void CommitManager::multiTargetUpload(const std::string &sourcePath)
{
APIParser apiPrs(icaAction);
auto api = apiPrs.retrieveAPI();
const auto token = parseToken(api);
if (!fs::is_directory(sourcePath))
{
cout<<sourcePath<<" is not a directory\n";
std::exit(-1);
}
std::vector<Song> songs;
Models::CoverArt cover;
string metadataPath;
for (auto &p: fs::directory_iterator(sourcePath))
{
const auto &pp = p.path();
const auto stem = pp.stem();
const auto file = pp.filename();
const auto extension = pp.extension();
cout<<"Stem "<<stem<<" Extension "<<extension<<"\n";
auto validImg = [](const std::string& ext)
{
std::vector<string> extensions;
extensions.reserve(3);
extensions.push_back(".jpg");
extensions.push_back(".jpeg");
extensions.push_back(".");
return ext.compare(extensions[0]) == 0 || ext.compare(extensions[1]) == 0 || ext.compare(extensions[2]) == 0;
}; };
return actions; if (extension.compare(".mp3") == 0)
{
Song song;
song.songPath = pp.string();
initializeDiscAndTrack<Song, std::string>(song);
songs.emplace_back(std::move(song));
}
// else if (extension.compare(".jpg") == 0 || extension.compare(".png") == 0)
else if (validImg(extension.string()))
{
cover.path.assign(pp.string());
}
else if (extension.compare(".json") == 0)
{
metadataPath.assign(pp.string());
}
} }
auto album = retrieveMetadata(metadataPath);
songs.clear();
songs.assign(album.songs.begin(), album.songs.end());
Token CommitManager::parseToken(API api) Upload up(api, token);
for (auto &song : songs)
{ {
cout<<"fetching token"<<endl; up.uploadSongWithMetadata(album, song, cover);
UserManager usrMgr{icaAction};
auto user = usrMgr.retrieveUser();
TokenManager tk{user, api};
return tk.requestToken();
} }
}
void CommitManager::deleteSong()
{ #pragma region private
APIParser apiPrs{icaAction}; CommitManager::Album CommitManager::retrieveMetadata(const std::string_view path)
auto api = apiPrs.retrieveAPI(); {
CommitManager::Album album;
auto token = parseToken(api); const auto fileContent = retrieveFileContent(path);
cout<<"Parsing...\n";
Song song{}; auto serialized = nlohmann::json::parse(fileContent);
cout<<"Parsed\n";
for (auto arg : icaAction.flags)
{ album.album = serialized["album"].get<std::string>();
auto flag = arg.flag; album.albumArtist = serialized["album_artist"].get<std::string>();
auto value = arg.value; album.genre = serialized["genre"].get<std::string>();
album.year = serialized["year"].get<int>();
if (flag.compare("-D") == 0) album.trackCount = serialized["track_count"].get<int>();
{ album.discCount = serialized["disc_count"].get<int>();
song.id = atoi(value.c_str()); album.songs.reserve(album.trackCount);
}
} for (auto &j : serialized["tracks"])
{
Delete del{api}; Song song;
cout<<"Deleting song..."<<endl; song.title = j["title"].get<std::string>();
del.deleteSong(token, song); song.track = j["track"].get<int>();
} song.disc = j["disc"].get<int>();
void CommitManager::downloadSong() song.artist = j["artist"].get<std::string>();
{ song.album = album.album;
cout<<"Starting downloading process..."<<endl; song.year = album.year;
song.genre = album.genre;
APIParser apiPrs{icaAction}; song.generate_filename_from_track();
auto api = apiPrs.retrieveAPI(); const auto p = fs::path(path);
song.directory = p.parent_path().string();
auto token = parseToken(api);
album.songs.push_back(song);
Song song{}; }
for (auto arg : icaAction.flags) return album;
{ }
auto flag = arg.flag;
auto value = arg.value; string CommitManager::retrieveFileContent(const std::string_view path)
{
if (flag.compare("-d") == 0) string path_str(path);
{ string value;
song.songPath.assign(arg.value);
} std::stringstream buffer;
if (flag.compare("-b") == 0) std::fstream file(path_str, std::ios::in);
{ buffer<<file.rdbuf();
song.id = atoi(value.c_str()); file.close();
}
} value.assign(buffer.str());
Download dnld{api}; return value;
cout<<"downloading song"<<endl; }
dnld.downloadSong(token, song); #pragma endregion
}
void CommitManager::retrieveObjects() void CommitManager::Album::printInfo()
{ {
cout<<"Starting retrieve process..."<<endl; std::cout<<"Album: "<<this->album<<"\n";
std::cout<<"Album Artist: "<<this->albumArtist<<"\n";
APIParser apiPrs{icaAction}; std::cout<<"Genre: "<<this->genre<<"\n";
auto api = apiPrs.retrieveAPI(); std::cout<<"Year: "<<this->year<<"\n";
std::cout<<"Track count: "<<this->trackCount<<"\n";
auto token = parseToken(api); std::cout<<"Disc count: "<<this->discCount<<"\n";
RetrieveTypes retrieveType; std::cout<<"\n";
}
for (auto arg : icaAction.flags)
{ #pragma region Functions
auto flag = arg.flag;
auto value = arg.value;
if (flag.compare("-rt") == 0)
{
if (value.compare("songs") == 0)
{
retrieveType = RetrieveTypes::songs;
break;
}
}
}
RetrieveRecords songs{api, token};
songs.retrieve(retrieveType);
}
void CommitManager::uploadSong()
{
auto uploadSingleSong = true;
auto recursiveDirectory = false;
auto noConfirm = false;
string songDirectory;
APIParser apiPrs{icaAction};
auto api = apiPrs.retrieveAPI();
auto token = parseToken(api);
Song song;
for (auto& arg : icaAction.flags)
{
auto flag = arg.flag;
auto value = arg.value;
if (flag.compare("-s") == 0)
{
song.songPath.assign(arg.value);
}
else if (flag.compare("-sd") == 0)
{
songDirectory = value;
uploadSingleSong = false;
}
else if (flag.compare("-sr") == 0)
{
songDirectory = value;
uploadSingleSong = false;
recursiveDirectory = true;
}
else if (flag.compare("-nc") == 0)
{
noConfirm = true;
}
}
Upload upld{api};
if (uploadSingleSong)
{
cout<<"Uploading song..."<<endl;
upld.uploadSong(token, song);
}
else
{
cout<<"Uploading songs from " << songDirectory << endl;
upld.uploadSongsFromDirectory(token, songDirectory, noConfirm, recursiveDirectory);
}
}
#pragma Functions
} }
+57 -50
View File
@@ -11,56 +11,63 @@ using std::string;
namespace Managers namespace Managers
{ {
FileManager::FileManager() {}
FileManager::FileManager(string filePath) #pragma region Constructors
{ FileManager::FileManager() {}
this->filePath = filePath; FileManager::FileManager(string filePath)
{
this->filePath = filePath;
readFile();
}
#pragma endregion
#pragma region Functions
void FileManager::saveFile(string newFilePath)
{
if (!fileRead)
readFile(); readFile();
}
ofstream of{newFilePath, ofstream::binary};
void FileManager::saveFile(string newFilePath) of.write(fileBuffer, fileBufferLength);
{ of.close();
if (!fileRead) }
readFile();
void FileManager::readFile()
ofstream of{newFilePath, ofstream::binary}; {
of.write(fileBuffer, fileBufferLength); ifstream is{filePath, ifstream::binary};
of.close(); if (is)
} {
is.seekg (0, is.end);
void FileManager::readFile() fileBufferLength = is.tellg();
{ is.seekg (0, is.beg);
ifstream is{filePath, ifstream::binary};
if (is) fileBuffer = new char [fileBufferLength];
{
is.seekg (0, is.end); cout<< "Reading "<<fileBufferLength<<" characters... "<<endl;;
fileBufferLength = is.tellg(); is.read (fileBuffer,fileBufferLength);
is.seekg (0, is.beg);
if (is)
fileBuffer = new char [fileBufferLength]; cout<<"all characters read successfully.";
else
cout<< "Reading "<<fileBufferLength<<" characters... "<<endl;; cout<<"error: only "<<is.gcount()<<" could be read";
is.read (fileBuffer,fileBufferLength); cout<<endl;
is.close();
if (is) fileRead = true;
cout<<"all characters read successfully."; }
else }
cout<<"error: only "<<is.gcount()<<" could be read"; void FileManager::modifyFilePath(string filePath)
cout<<endl; {
is.close(); this->filePath = filePath;
fileRead = true; }
}
} char* FileManager::retrieveFileBuffer() const
void FileManager::modifyFilePath(string filePath) {
{ return fileBuffer;
this->filePath = filePath; }
}
int FileManager::retrieveFileBufferLength() const { return fileBufferLength; }
char* FileManager::retrieveFileBuffer() const
{ #pragma endregion
return fileBuffer;
}
int FileManager::retrieveFileBufferLength() const { return fileBufferLength; }
} }
+41 -39
View File
@@ -17,44 +17,46 @@ using Models::User;
namespace Managers namespace Managers
{ {
#pragma
TokenManager::TokenManager(const User& user)
{
this->user = user;
}
TokenManager::TokenManager(const User& user, API& api)
{
this->user = user;
this->api = api;
this->api.endpoint = "api/" + api.version
+ "/login";
}
#pragma Constructors
#pragma region Constructors
#pragma TokenManager::TokenManager(const User& user)
Token TokenManager::requestToken() {
{ this->user = user;
Token token{}; }
json usrObj; TokenManager::TokenManager(const User& user, API& api)
{
usrObj["username"] = user.username; this->user = user;
usrObj["password"] = user.password; this->api = api;
this->api.endpoint = "api/" + api.version
cout<<"Sending request for token"<<endl; + "/login";
auto url = api.url + api.endpoint; }
cout<<url<<endl; #pragma endregion
auto r = cpr::Post(cpr::Url{url},
cpr::Body{usrObj.dump()},
cpr::Header{{"Content-Type", "application/json"}}); #pragma region Functions
Token TokenManager::requestToken()
json res = json::parse(r.text); {
token.accessToken = res["token"]; Token token{};
token.tokenType = res["token_type"]; json usrObj;
cout<<"status code "<<r.status_code<<endl; usrObj["username"] = user.username;
usrObj["password"] = user.password;
return token;
} cout<<"Sending request for token"<<endl;
#pragma Functions auto url = api.url + api.endpoint;
cout<<url<<endl;
auto r = cpr::Post(cpr::Url{url},
cpr::Body{usrObj.dump()},
cpr::Header{{"Content-Type", "application/json"}});
json res = json::parse(r.text);
token.accessToken = res["token"];
token.tokenType = res["token_type"];
cout<<"status code "<<r.status_code<<endl;
return token;
}
#pragma endregion
} }
+33 -31
View File
@@ -12,42 +12,44 @@ using Models::User;
namespace Managers namespace Managers
{ {
#pragma
UserManager::UserManager(User user) #pragma region Constructors
{ UserManager::UserManager(User user)
this->user = user; {
} this->user = user;
UserManager::UserManager(const IcarusAction icaAct) }
{ UserManager::UserManager(const IcarusAction icaAct)
this->icaAction = icaAct; {
this->user = User{}; this->icaAction = icaAct;
parseUserFromActions(); this->user = User{};
} parseUserFromActions();
#pragma Constructors }
#pragma endregion
#pragma #pragma region Functions
User UserManager::retrieveUser() const User UserManager::retrieveUser() const
{ {
return user; return user;
} }
void UserManager::parseUserFromActions() void UserManager::parseUserFromActions()
{ {
auto args = icaAction.flags; auto args = icaAction.flags;
for (auto arg : args) for (auto arg : args)
{
auto flag = arg.flag;
if (flag.compare("-u") == 0)
{ {
auto flag = arg.flag; user.username = arg.value;
if (flag.compare("-u") == 0) }
{ if (flag.compare("-p") == 0)
user.username = arg.value; {
} user.password = arg.value;
if (flag.compare("-p") == 0)
{
user.password = arg.value;
}
} }
} }
#pragma Functions }
#pragma endregion
} }
+22
View File
@@ -0,0 +1,22 @@
#include "Models/Song.h"
#include "nlohmann/json.hpp"
using std::string;
namespace Models
{
string Song::toMetadataJson()
{
nlohmann::json s;
s["title"] = this->title;
s["artist"] = this->artist;
s["album"] = this->album;
s["genre"] = this->genre;
s["year"] = this->year;
s["track"] = this->track;
s["disc"] = this->disc;
return s.dump();
}
}
+41 -40
View File
@@ -1,6 +1,6 @@
#include"Parsers/APIParser.h" #include "Parsers/APIParser.h"
#include<iostream> #include <iostream>
using std::cout; using std::cout;
using std::endl; using std::endl;
@@ -10,43 +10,44 @@ using Models::IcarusAction;
namespace Parsers namespace Parsers
{ {
#pragma
APIParser::APIParser(IcarusAction icaAct) : icaAct(icaAct)
{
api = API{};
parseAPI();
}
#pragma endregion
#pragma region Constructors
#pragma APIParser::APIParser(IcarusAction icaAct) : icaAct(icaAct)
API APIParser::retrieveAPI() const {
{ api = API{};
return api; parseAPI();
} }
#pragma endregion
void APIParser::parseAPI()
{
auto flags = icaAct.flags; #pragma region Functions
cout<<"Parsing api"<<endl; API APIParser::retrieveAPI() const
{
for (auto i =0; i < flags.size(); ++i) return api;
{ }
auto arg = flags[i].flag;
auto value = flags[i].value; void APIParser::parseAPI()
{
if (arg.compare("-h") == 0) auto flags = icaAct.flags;
{ cout << "Parsing api" << endl;
api.url = (value[value.size()-1] == '/') ? value : value + "/";
break; for (auto i =0; i < flags.size(); ++i)
} {
auto arg = flags[i].flag;
} auto value = flags[i].value;
// TODO: For now I will hard code if (arg.compare("-h") == 0)
// the api version since I am only {
// on version 1 api.url = (value[value.size()-1] == '/') ? value : value + "/";
api.version = "v1"; break;
} }
#pragma functions }
// NOTE: For now I will hard code
// the api version since I am only
// on version 1
api.version = "v1";
}
#pragma endregion
} }
+48 -46
View File
@@ -1,9 +1,9 @@
#include"Syncers/Delete.h" #include "Syncers/Delete.h"
#include<exception> #include <exception>
#include<iostream> #include <iostream>
#include<cpr/cpr.h> #include <cpr/cpr.h>
using std::cout; using std::cout;
using std::endl; using std::endl;
@@ -16,47 +16,49 @@ using Models::Token;
namespace Syncers namespace Syncers
{ {
#pragma
Delete::Delete(API api)
{
this->api = api;
this->api.endpoint = "song/data";
}
#pragma Constructors
#pragma region Constructors
#pragma Delete::Delete(API api)
void Delete::deleteSong(const Token token, Song song) {
{ this->api = api;
try this->api.endpoint = "song/data";
{ }
auto url = retrieveUrl(song); #pragma endregion
string auth{token.tokenType};
auth.append(" " + token.accessToken);
auto r = cpr::Delete(cpr::Url(url), #pragma region Functions
cpr::Header{{"authorization", auth}}); void Delete::deleteSong(const Token token, Song song)
{
auto statusCode = r.status_code; try
{
cout<<"Status code "<<statusCode<<endl; auto url = retrieveUrl(song);
} string auth{token.tokenType};
catch (exception e) auth.append(" " + token.accessToken);
{ auto r = cpr::Delete(cpr::Url(url),
auto msg = e.what(); cpr::Header{{"authorization", auth}});
cout<<msg<<endl;
} auto statusCode = r.status_code;
cout<<"Finished"<<endl;
} cout<<"Status code "<<statusCode<<endl;
}
string Delete::retrieveUrl(Song song) catch (exception e)
{ {
string url{api.url + "api/" + api.version + "/" + auto msg = e.what();
api.endpoint + "/"}; cout<<msg<<endl;
}
url.append(std::to_string(song.id)); cout<<"Finished"<<endl;
cout<<"url "<<url<<endl; }
return url; string Delete::retrieveUrl(Song song)
} {
#pragma Functions string url{api.url + "api/" + api.version + "/" +
api.endpoint + "/"};
url.append(std::to_string(song.id));
cout<<"url "<<url<<endl;
return url;
}
#pragma endregion
} }
+76 -74
View File
@@ -1,10 +1,10 @@
#include"Syncers/Download.h" #include "Syncers/Download.h"
#include<exception> #include <exception>
#include<iostream> #include <iostream>
#include<fstream> #include <fstream>
#include<cpr/cpr.h> #include <cpr/cpr.h>
using std::cout; using std::cout;
using std::endl; using std::endl;
@@ -18,74 +18,76 @@ using Models::Token;
namespace Syncers namespace Syncers
{ {
#pragma
Download::Download() { }
Download::Download(API api)
{
this->api = api;
this->api.endpoint = "song/data";
}
Download::Download(string filePath)
{
downloadFilePath = filePath;
}
#pragma Constructors
#pragma region Constructors
#pragma Download::Download() { }
void Download::downloadSong(const Token token, Song song) Download::Download(API api)
{ {
try this->api = api;
{ this->api.endpoint = "song/data";
string url = retrieveUrl(song); }
song.songPath.append("track.mp3"); Download::Download(string filePath)
cout<<"song path "<<song.songPath<<endl; {
string auth{token.tokenType}; downloadFilePath = filePath;
auth.append(" " + token.accessToken); }
#pragma endregion
auto r = cpr::Get(cpr::Url(url),
cpr::Header{{"Content-type", "audio/mpeg"},
{"Authorization", auth}}); #pragma region Functions
void Download::downloadSong(const Token token, Song song)
{
int statusCode = r.status_code; try
{
if (statusCode == OK) { string url = retrieveUrl(song);
song.data = r.text; song.songPath.append("track.mp3");
saveSong(song); cout<<"song path "<<song.songPath<<endl;
} string auth{token.tokenType};
auth.append(" " + token.accessToken);
cout<<"finsihed with status code "<<statusCode<<endl; auto r = cpr::Get(cpr::Url(url),
} cpr::Header{{"Content-type", "audio/mpeg"},
catch (exception e) {"Authorization", auth}});
{
auto msg = e.what();
cout<<msg<<endl; int statusCode = r.status_code;
}
} if (statusCode == OK) {
song.data = r.text;
string Download::retrieveUrl(Song song) saveSong(song);
{ }
string url{api.url + "api/" + api.version + "/" +
api.endpoint + "/"};
cout<<"finsihed with status code "<<statusCode<<endl;
url.append(std::to_string(song.id)); }
cout<<"url "<<url<<endl; catch (exception e)
{
return url; auto msg = e.what();
} cout<<msg<<endl;
}
void Download::saveSong(Song& song) }
{
cout<<"\nSaving song to: "<<song.songPath<<endl; string Download::retrieveUrl(Song song)
int bufferLength = song.data.length(); {
const char *data = song.data.c_str(); string url{api.url + "api/" + api.version + "/" +
cout<<"buff length "<<bufferLength<<endl; api.endpoint + "/"};
ofstream saveSong{song.songPath, std::ios::binary}; url.append(std::to_string(song.id));
saveSong.write(data, bufferLength); cout<<"url "<<url<<endl;
saveSong.close();
} return url;
#pragma Functions }
void Download::saveSong(Song& song)
{
cout<<"\nSaving song to: "<<song.songPath<<endl;
int bufferLength = song.data.length();
const char *data = song.data.c_str();
cout<<"buff length "<<bufferLength<<endl;
ofstream saveSong{song.songPath, std::ios::binary};
saveSong.write(data, bufferLength);
saveSong.close();
}
#pragma endregion
} }
+41 -36
View File
@@ -20,43 +20,48 @@ using Utilities::Conversions;
namespace Syncers namespace Syncers
{ {
RetrieveRecords::RetrieveRecords() { } #pragma region Constructors
RetrieveRecords::RetrieveRecords(API api, Token token) RetrieveRecords::RetrieveRecords() { }
: token(token), api(api) { } RetrieveRecords::RetrieveRecords(API api, Token token)
: token(token), api(api) { }
#pragma endregion
void RetrieveRecords::retrieve(CommitManager::RetrieveTypes type) #pragma region Functions
void RetrieveRecords::retrieve(CommitManager::RetrieveTypes type)
{
switch (type)
{ {
switch (type) case CommitManager::RetrieveTypes::songs:
{ fetchSongs();
case CommitManager::RetrieveTypes::songs: break;
fetchSongs(); default:
break; break;
default:
break;
}
}
void RetrieveRecords::fetchSongs()
{
cout<<"fetching songs"<<endl;
auto url = api.url + "api/" + api.version + "/" + "song";
auto auth = token.tokenType;
auth.append(" " + token.accessToken);
auto r = cpr::Get(cpr::Url{url},
cpr::Header{{"authorization", auth},
});
if (r.status_code != (int)Result::OK) {
cout<<"something went wrong\n";
cout<<"status code: "<<r.status_code<<endl;
cout<<"message: "<<r.text<<endl;
return;
}
auto songData = nlohmann::json::parse(r.text);
ofstream writeData{};
writeData.open("songs.json");
writeData<<songData.dump(4);
writeData.close();
} }
} }
void RetrieveRecords::fetchSongs()
{
cout<<"fetching songs"<<endl;
auto url = api.url + "api/" + api.version + "/" + "song";
auto auth = token.tokenType;
auth.append(" " + token.accessToken);
auto r = cpr::Get(cpr::Url{url},
cpr::Header{{"authorization", auth},
});
if (r.status_code != (int)Result::OK) {
cout<<"something went wrong\n";
cout<<"status code: "<<r.status_code<<endl;
cout<<"message: "<<r.text<<endl;
return;
}
auto songData = nlohmann::json::parse(r.text);
ofstream writeData{};
writeData.open("songs.json");
writeData<<songData.dump(4);
writeData.close();
}
#pragma endregion
}
+188 -161
View File
@@ -1,11 +1,11 @@
#include<iostream> #include <iostream>
#include<filesystem> #include <filesystem>
#include<exception> #include <exception>
#include<cpr/cpr.h> #include "cpr/cpr.h"
#include<nlohmann/json.hpp>
#include"Syncers/Upload.h" #include "Syncers/Upload.h"
#include "Utilities/Conversions.h"
using std::cout; using std::cout;
using std::cin; using std::cin;
@@ -24,154 +24,192 @@ using namespace cpr;
namespace Syncers namespace Syncers
{ {
Upload::Upload() { }
Upload::Upload(API api) : api(api) #pragma region Constructors
#pragma endregion
#pragma region Functions
Song Upload::uploadSong(Song& song)
{
try
{ {
this->api.endpoint = "song/data"; auto url = retrieveUrl();
}
cout<<"url "<<url<<endl;
string auth{this->m_token.tokenType};
auth.append(" " + this->m_token.accessToken);
auto r = cpr::Post(cpr::Url{url},
cpr::Multipart{{"key", "small value"},
{"file", cpr::File{song.songPath}}},
cpr::Header{{"authorization", auth}}
);
Song Upload::uploadSong(const Models::Token& token, Song& song) cout << "status code: " << r.status_code<< std::endl;
{ cout << r.text << endl;
try auto result = nlohmann::json::parse(r.text);
{ cout<<"Finished"<<endl;
auto url = retrieveUrl(); song.id = result["id"].get<int>();
song.title = result["title"].get<std::string>();
cout<<"url "<<url<<endl; song.artist = result["artist"].get<std::string>();
string auth{token.tokenType}; song.album = result["album"].get<std::string>();
auth.append(" " + token.accessToken); song.genre = result["genre"].get<std::string>();
auto r = cpr::Post(cpr::Url{url}, song.year = result["year"].get<int>();
cpr::Multipart{{"key", "small value"}, song.duration = result["duration"].get<int>();
{"file", cpr::File{song.songPath}}}, song.track = result["track"].get<int>();
cpr::Header{{"authorization", auth}}
);
cout << "status code: " << r.status_code<< std::endl;
cout << r.text << endl;
auto result = nlohmann::json::parse(r.text);
cout<<"Finished"<<endl;
song.id = result["id"].get<int>();
song.title = result["title"].get<std::string>();
song.artist = result["artist"].get<std::string>();
song.album = result["album"].get<std::string>();
song.genre = result["genre"].get<std::string>();
song.year = result["year"].get<int>();
song.duration = result["duration"].get<int>();
song.track = result["track"].get<int>();
return song;
}
catch (exception& e)
{
auto msg = e.what();
cout<<msg<<endl;
}
return song; return song;
} }
catch (exception& e)
void Upload::uploadSongsFromDirectory(const Models::Token& token,
const std::string& directory,
const bool noConfirm, bool recursive = false)
{ {
try auto msg = e.what();
cout<<msg<<endl;
}
return song;
}
void Upload::uploadSongsFromDirectory(const std::string& directory,
const bool noConfirm, bool recursive = false)
{
try
{
auto songs = retrieveAllSongsFromDirectory(directory, recursive);
auto confirmUpload = true;
while (!noConfirm)
{ {
auto songs = retrieveAllSongsFromDirectory(directory, recursive); auto answer = 'a';
auto confirmUpload = true; cout << "are you sure you want to upload " << songs.size() << " songs? [y/n]";
cin >> answer;
Utilities::Conversions::toLowerChar(answer);
while (!noConfirm) if (answer == 'y' || answer == 'Y')
{ {
auto answer = 'a'; confirmUpload = true;
cout << "are you sure you want to upload " << songs.size() << " songs? [y/n]"; break;
cin >> answer; }
if (answer == 'y' || answer == 'Y')
{
confirmUpload = true;
break;
}
else if (answer == 'n' || answer == 'N')
{
confirmUpload = false;
break;
}
}
if (!confirmUpload)
{
cout << "exiting...\n";
std::exit(-1);
}
cout << "uploading songs\n";
for (auto& song: songs)
{
song = uploadSong(token, song);
}
} }
catch (exception& e)
cout << "uploading songs\n";
for (auto& song: songs)
{ {
cout<<e.what()<<endl; song = uploadSong(song);
}
}
catch (exception& e)
{
cout<<e.what()<<endl;
}
}
void Upload::uploadSongWithMetadata(Managers::CommitManager::Album &album, Models::Song& song, Models::CoverArt &cover)
{
this->api.endpoint.assign("song/data/upload/with/data");
try
{
auto url = retrieveUrl();
cout << "url " << url << "\n";
string auth(this->m_token.tokenType);
auth.append(" " + this->m_token.accessToken);
nlohmann::json s;
s["title"] = song.title;
s["album"] = album.album;
s["album_artist"] = album.albumArtist;
s["artist"] = song.artist;
s["year"] = album.year;
s["genre"] = album.genre;
s["disc"] = song.disc;
s["track"] = song.track;
s["disc_count"] = album.discCount;
s["track_count"] = album.trackCount;
const auto meta = s.dump();
cout<<"\n\nMeta:\n"<<meta<<"\n";
cout << "Filepath: " << song.song_path() << "\n";
auto multipart = cpr::Multipart{{"cover", cpr::File{cover.path}},
{"metadata", meta},
{"file", cpr::File{song.song_path()}}};
auto r = cpr::Post(cpr::Url{url}, multipart,
cpr::Header{{"authorization", auth}}
);
cout << "status code: " << r.status_code<< std::endl;
cout << r.text << endl;
}
catch (exception &e)
{
auto msg = e.what();
cout<<"Error: "<<msg<<"\n";
}
}
std::vector<Song> Upload::retrieveAllSongsFromDirectory(const std::string& directory,
bool recursive)
{
std::vector<Song> allSongs;
if (recursive)
{
for (auto p: fs::recursive_directory_iterator(directory))
{
auto song = retrieveSongPath(p);
if (!song.songPath.empty())
allSongs.push_back(song);
}
}
else
{
for (auto p: fs::directory_iterator(directory))
{
auto song = retrieveSongPath(p);
if (!song.songPath.empty())
allSongs.push_back(song);
} }
} }
return allSongs;
}
std::vector<Song> Upload::retrieveAllSongsFromDirectory(const std::string& directory,
bool recursive) string Upload::retrieveUrl()
{
const string url{api.url + "api/" + api.version + "/" +
api.endpoint};
return url;
}
Song Upload::retrieveSongPath(fs::directory_entry& dirEntry)
{
constexpr auto mp3Ext = ".mp3";
Song song;
if (fs::is_regular_file(dirEntry.path()))
{ {
std::vector<Song> allSongs; const auto ext = dirEntry.path().extension().string();
if (recursive) if (ext.compare(mp3Ext) == 0)
{ {
for (auto p: fs::recursive_directory_iterator(directory)) cout << "found mp3 file" << endl;
{ song.songPath = dirEntry.path().string();
auto song = retrieveSongPath(p);
if (!song.songPath.empty())
allSongs.push_back(song);
}
} }
else
{
for (auto p: fs::directory_iterator(directory))
{
auto song = retrieveSongPath(p);
if (!song.songPath.empty())
allSongs.push_back(song);
}
}
return allSongs;
} }
return song;
string Upload::retrieveUrl() }
{
const string url{api.url + "api/" + api.version + "/" +
api.endpoint};
return url;
}
Song Upload::retrieveSongPath(fs::directory_entry& dirEntry) #pragma region Testing
{
constexpr auto mp3Ext = ".mp3";
Song song;
if (fs::is_regular_file(dirEntry.path()))
{
const auto ext = dirEntry.path().extension().string();
if (ext.compare(mp3Ext) == 0)
{
cout << "found mp3 file" << endl;
song.songPath = dirEntry.path().string();
}
}
return song; void Upload::printSongDetails(std::vector<Song>& songs)
} {
for (auto& song: songs)
#pragma
void Upload::printSongDetails()
{ {
cout<<"Song details: "<<endl; cout<<"Song details: "<<endl;
cout<<"Id: "<<song.id<<endl; cout<<"Id: "<<song.id<<endl;
@@ -181,36 +219,25 @@ namespace Syncers
cout<<"Genre: "<<song.genre<<endl; cout<<"Genre: "<<song.genre<<endl;
cout<<"Year: "<<song.year<<endl; cout<<"Year: "<<song.year<<endl;
cout<<"Duration: "<<song.duration<<endl; cout<<"Duration: "<<song.duration<<endl;
cout<<"Path: "<<song.songPath<<endl;
} }
void Upload::printSongDetails(std::vector<Song>& songs) }
{
for (auto& song: songs) void Upload::printJsonData(const json& obj)
{ {
cout<<"Song details: "<<endl; cout<<endl<<endl<<"JSon data: "<<endl;
cout<<"Id: "<<song.id<<endl; cout<<"id: "<<obj["id"]<<endl;
cout<<"Title: "<<song.title<<endl; cout<<"title: "<<obj["title"]<<endl;
cout<<"Artist: "<<song.artist<<endl; cout<<"artist: "<<obj["artist"]<<endl;
cout<<"Album: "<<song.album<<endl; cout<<"album: "<<obj["album"]<<endl;
cout<<"Genre: "<<song.genre<<endl; cout<<"genre: "<<obj["genre"]<<endl;
cout<<"Year: "<<song.year<<endl; cout<<"year: "<<obj["year"]<<endl;
cout<<"Duration: "<<song.duration<<endl; cout<<"duration: "<<obj["duration"]<<endl;
cout<<"Path: "<<song.songPath<<endl; cout<<"song_data: "<<obj["song_data"]<<endl;
}
} cout<<endl<<endl;
void Upload::printJsonData(const json& obj) }
{ #pragma endregion
cout<<endl<<endl<<"JSon data: "<<endl; #pragma endregion
cout<<"id: "<<obj["id"]<<endl;
cout<<"title: "<<obj["title"]<<endl;
cout<<"artist: "<<obj["artist"]<<endl;
cout<<"album: "<<obj["album"]<<endl;
cout<<"genre: "<<obj["genre"]<<endl;
cout<<"year: "<<obj["year"]<<endl;
cout<<"duration: "<<obj["duration"]<<endl;
cout<<"song_data: "<<obj["song_data"]<<endl;
cout<<endl<<endl;;
}
#pragma Testing
#pragma Functions
} }
+46 -41
View File
@@ -1,47 +1,52 @@
#include"UI/AboutWindow.h" #include "UI/AboutWindow.h"
using std::unique_ptr; using std::unique_ptr;
namespace UI namespace UI
{ {
AboutWindow::AboutWindow(QWidget* parent): QDialog(parent) #pragma region Constructors
{ AboutWindow::AboutWindow(QWidget* parent): QDialog(parent)
setupWindow(); {
} setupWindow();
}
#pragma endregion
void AboutWindow::setupWindow()
{
windowWidth = 250; #pragma region Functions
windowHeight = 300; void AboutWindow::setupWindow()
{
mainLayoutQt = unique_ptr<QVBoxLayout>{new QVBoxLayout}; windowWidth = 250;
windowHeight = 300;
appName = unique_ptr<QLabel>{new QLabel(tr("IcarusDownloadManager"))};
actionButtonQt = unique_ptr<QPushButton>{new QPushButton(tr("Close"))}; mainLayoutQt = unique_ptr<QVBoxLayout>{new QVBoxLayout};
mainLayoutQt->addWidget(appName.get()); appName = unique_ptr<QLabel>{new QLabel(tr("IcarusDownloadManager"))};
mainLayoutQt->addWidget(actionButtonQt.get()); actionButtonQt = unique_ptr<QPushButton>{new QPushButton(tr("Close"))};
mainLayoutQt->addWidget(appName.get());
setFixedWidth(windowWidth); mainLayoutQt->addWidget(actionButtonQt.get());
setFixedHeight(windowHeight);
setLayout(mainLayoutQt.get()); setFixedWidth(windowWidth);
setFixedHeight(windowHeight);
setWindowTitle("About");
setLayout(mainLayoutQt.get());
connections();
} setWindowTitle("About");
void AboutWindow::connections()
{ connections();
QObject::connect(actionButtonQt.get(), SIGNAL(clicked()), this, }
SLOT(closeWindow())); void AboutWindow::connections()
} {
QObject::connect(actionButtonQt.get(), SIGNAL(clicked()), this,
SLOT(closeWindow()));
void AboutWindow::closeWindow() }
{
this->hide();
} void AboutWindow::closeWindow()
{
this->hide();
}
#pragma endregion
} }
+165 -159
View File
@@ -1,11 +1,11 @@
#include"UI/MainWindow.h" #include "UI/MainWindow.h"
#include<iostream> #include <iostream>
#include<string> #include <string>
#include"Models/UploadForm.h" #include "Models/UploadForm.h"
#include"Syncers/Upload.h" #include "Syncers/Upload.h"
#include"Utilities/Conversions.h" #include "Utilities/Conversions.h"
using std::cout; using std::cout;
using std::endl; using std::endl;
@@ -17,158 +17,164 @@ using Syncers::Upload;
namespace UI namespace UI
{ {
MainWindow::MainWindow()
{
setupMainWindow();
aboutWindow = unique_ptr<AboutWindow>{new AboutWindow};
}
#pragma region Constructors
void MainWindow::configureDownloadSection() MainWindow::MainWindow()
{ {
} setupMainWindow();
void MainWindow::configureUploadSection() aboutWindow = unique_ptr<AboutWindow>{new AboutWindow};
{ }
uploadSongQt = unique_ptr<QPushButton>{new QPushButton(tr("Upload"))}; #pragma endregion
urlQt = unique_ptr<QTextEdit>{new QTextEdit()};
sourceFilePathQt = unique_ptr<QTextEdit>{new QTextEdit()};
#pragma region Functions
urlLabel = unique_ptr<QLabel>{new QLabel(tr("URL"))}; void MainWindow::configureDownloadSection()
songPath = unique_ptr<QLabel>{new QLabel(tr("Song Path"))}; {
}
urlPortion = unique_ptr<QHBoxLayout>{new QHBoxLayout}; void MainWindow::configureUploadSection()
songPathPortion = unique_ptr<QHBoxLayout>{new QHBoxLayout}; {
uploadSongQt = unique_ptr<QPushButton>{new QPushButton(tr("Upload"))};
urlPortion.get()->addWidget(urlLabel.get()); urlQt = unique_ptr<QTextEdit>{new QTextEdit()};
urlPortion.get()->addWidget(urlQt.get()); sourceFilePathQt = unique_ptr<QTextEdit>{new QTextEdit()};
songPathPortion->addWidget(songPath.get()); urlLabel = unique_ptr<QLabel>{new QLabel(tr("URL"))};
songPathPortion->addWidget(sourceFilePathQt.get()); songPath = unique_ptr<QLabel>{new QLabel(tr("Song Path"))};
subLayoutOneQt = unique_ptr<QVBoxLayout>{new QVBoxLayout}; urlPortion = unique_ptr<QHBoxLayout>{new QHBoxLayout};
subLayoutOneQt.get()->addLayout(urlPortion.get()); songPathPortion = unique_ptr<QHBoxLayout>{new QHBoxLayout};
subLayoutOneQt->addLayout(songPathPortion.get());
mainLayoutQt.get()->addLayout(subLayoutOneQt.get()); urlPortion.get()->addWidget(urlLabel.get());
} urlPortion.get()->addWidget(urlQt.get());
void MainWindow::configureWindowDimensions()
{ songPathPortion->addWidget(songPath.get());
windowWidth = 450; songPathPortion->addWidget(sourceFilePathQt.get());
windowHeight = 450;
} subLayoutOneQt = unique_ptr<QVBoxLayout>{new QVBoxLayout};
void MainWindow::configureWindowProperties() subLayoutOneQt.get()->addLayout(urlPortion.get());
{ subLayoutOneQt->addLayout(songPathPortion.get());
setWindowTitle("IcarusDownloadManager"); mainLayoutQt.get()->addLayout(subLayoutOneQt.get());
setFixedHeight(windowHeight); }
setFixedWidth(windowWidth); void MainWindow::configureWindowDimensions()
} {
void MainWindow::connections() windowWidth = 450;
{ windowHeight = 450;
QObject::connect(uploadSongQt.get(), SIGNAL(clicked()), this, SLOT(uploadSong())); }
QObject::connect(closeApplicationQt.get(), SIGNAL(triggered()), this, void MainWindow::configureWindowProperties()
SLOT(exitApplication())); {
QObject::connect(aboutApplicationQt.get(), SIGNAL(triggered()), this, setWindowTitle("IcarusDownloadManager");
SLOT(displaySoftwareInformation())); setFixedHeight(windowHeight);
QObject::connect(windowComboBox.get(), SIGNAL(activated(int)), setFixedWidth(windowWidth);
this, SLOT(setCurrentIndex(int))); }
} void MainWindow::connections()
void MainWindow::createMenus() {
{ QObject::connect(uploadSongQt.get(), SIGNAL(clicked()), this, SLOT(uploadSong()));
fileMenuQt = unique_ptr<QMenu>{menuBar()->addMenu(tr("File"))}; QObject::connect(closeApplicationQt.get(), SIGNAL(triggered()), this,
editMenuQt = unique_ptr<QMenu>{menuBar()->addMenu(tr("Edit"))}; SLOT(exitApplication()));
helpMenuQt = unique_ptr<QMenu>{menuBar()->addMenu(tr("Help"))}; QObject::connect(aboutApplicationQt.get(), SIGNAL(triggered()), this,
SLOT(displaySoftwareInformation()));
closeApplicationQt = unique_ptr<QAction>{new QAction(new QObject(nullptr))}; QObject::connect(windowComboBox.get(), SIGNAL(activated(int)),
closeApplicationQt->setText("Exit Application"); this, SLOT(setCurrentIndex(int)));
}
aboutApplicationQt = unique_ptr<QAction>{new QAction(new QObject(nullptr))}; void MainWindow::createMenus()
aboutApplicationQt->setText("About"); {
fileMenuQt = unique_ptr<QMenu>{menuBar()->addMenu(tr("File"))};
fileMenuQt->addAction(closeApplicationQt.get()); editMenuQt = unique_ptr<QMenu>{menuBar()->addMenu(tr("Edit"))};
helpMenuQt->addAction(aboutApplicationQt.get()); helpMenuQt = unique_ptr<QMenu>{menuBar()->addMenu(tr("Help"))};
} closeApplicationQt = unique_ptr<QAction>{new QAction(new QObject(nullptr))};
void MainWindow::setupMainWidget() closeApplicationQt->setText("Exit Application");
{
mainWidgetQt = unique_ptr<QWidget>{new QWidget}; aboutApplicationQt = unique_ptr<QAction>{new QAction(new QObject(nullptr))};
aboutApplicationQt->setText("About");
windowComboBox = unique_ptr<QComboBox>{new QComboBox};
setupWindowLists(); fileMenuQt->addAction(closeApplicationQt.get());
helpMenuQt->addAction(aboutApplicationQt.get());
stackLayout = unique_ptr<QVBoxLayout>{new QVBoxLayout}; }
stackLayout->addWidget(windowComboBox.get()); void MainWindow::setupMainWidget()
{
uploadSongWidgetQt = unique_ptr<QWidget>{new QWidget}; mainWidgetQt = unique_ptr<QWidget>{new QWidget};
uploadSongWidgetQt->setLayout(mainLayoutQt.get());
windowComboBox = unique_ptr<QComboBox>{new QComboBox};
stackLayout->addWidget(uploadSongWidgetQt.get()); setupWindowLists();
mainWidgetQt->setLayout(stackLayout.get());
} stackLayout = unique_ptr<QVBoxLayout>{new QVBoxLayout};
void MainWindow::setupMainWindow() stackLayout->addWidget(windowComboBox.get());
{
configureWindowDimensions(); uploadSongWidgetQt = unique_ptr<QWidget>{new QWidget};
uploadSongWidgetQt->setLayout(mainLayoutQt.get());
mainLayoutQt = unique_ptr<QVBoxLayout>{new QVBoxLayout};
widgetStack = unique_ptr<QStackedWidget>{new QStackedWidget}; stackLayout->addWidget(uploadSongWidgetQt.get());
configureUploadSection(); mainWidgetQt->setLayout(stackLayout.get());
}
setupMainWidget(); void MainWindow::setupMainWindow()
{
widgetStack->addWidget(mainWidgetQt.get()); configureWindowDimensions();
MainDockWidgetQt = unique_ptr<QDockWidget>{new QDockWidget}; mainLayoutQt = unique_ptr<QVBoxLayout>{new QVBoxLayout};
MainDockWidgetQt.get()->setWindowTitle(tr("Music Manager")); widgetStack = unique_ptr<QStackedWidget>{new QStackedWidget};
MainDockWidgetQt->setWidget(widgetStack.get());
MainDockWidgetQt.get()->setFeatures(QDockWidget::NoDockWidgetFeatures); configureUploadSection();
setCentralWidget(MainDockWidgetQt.get()); setupMainWidget();
createMenus(); widgetStack->addWidget(mainWidgetQt.get());
configureWindowProperties(); MainDockWidgetQt = unique_ptr<QDockWidget>{new QDockWidget};
MainDockWidgetQt.get()->setWindowTitle(tr("Music Manager"));
connections(); MainDockWidgetQt->setWidget(widgetStack.get());
} MainDockWidgetQt.get()->setFeatures(QDockWidget::NoDockWidgetFeatures);
void MainWindow::setupWindowLists()
{ setCentralWidget(MainDockWidgetQt.get());
windowComboBox->addItem(tr("Upload song"));
windowComboBox->addItem(tr("Download song")); createMenus();
windowComboBox->addItem(tr("Display all songs"));
windowComboBox->addItem(tr("Display songs")); configureWindowProperties();
}
connections();
}
void MainWindow::exitApplication() void MainWindow::setupWindowLists()
{ {
exit(0); windowComboBox->addItem(tr("Upload song"));
} windowComboBox->addItem(tr("Download song"));
void MainWindow::displaySoftwareInformation() windowComboBox->addItem(tr("Display all songs"));
{ windowComboBox->addItem(tr("Display songs"));
aboutWindow->show(); }
}
void MainWindow::setCurrentIndex(int index)
{ void MainWindow::exitApplication()
cout<<"index "<<index<<endl; {
QString qText = windowComboBox->itemText(index); exit(0);
auto cnvert = Utilities::Conversions(qText); }
auto convertedStr = cnvert.convertQStringToString(); void MainWindow::displaySoftwareInformation()
cout<<"item text"<<endl; {
} aboutWindow->show();
void MainWindow::uploadSong() }
{ void MainWindow::setCurrentIndex(int index)
uploadSongQt->setEnabled(false); {
cout<<"index "<<index<<endl;
string url = urlQt->toPlainText().toUtf8().constData(); QString qText = windowComboBox->itemText(index);
string filePath = sourceFilePathQt->toPlainText().toUtf8().constData(); auto cnvert = Utilities::Conversions(qText);
cout<<"URL endpoint: "<<url<<endl; auto convertedStr = cnvert.convertQStringToString();
cout<<"Music file path: "<<filePath<<endl; cout<<"item text"<<endl;
UploadForm formData{url, filePath}; }
void MainWindow::uploadSong()
Upload upld{formData}; {
upld.uploadSong(); uploadSongQt->setEnabled(false);
uploadSongQt->setEnabled(true); string url = urlQt->toPlainText().toUtf8().constData();
} string filePath = sourceFilePathQt->toPlainText().toUtf8().constData();
cout<<"URL endpoint: "<<url<<endl;
cout<<"Music file path: "<<filePath<<endl;
UploadForm formData{url, filePath};
Upload upld{formData};
upld.uploadSong();
uploadSongQt->setEnabled(true);
}
#pragma endregion
} }
+17 -15
View File
@@ -1,24 +1,26 @@
#include"Utilities/Conversions.h" #include "Utilities/Conversions.h"
#include<iostream> #include <iostream>
using std::string; using std::string;
using std::unique_ptr; using std::unique_ptr;
namespace Utilities namespace Utilities
{ {
Conversions::Conversions()
{
initializeValues();
}
void Conversions::initializeValues() Conversions::Conversions()
{ {
} initializeValues();
template <typename T> }
void Conversions::printValue(T val)
{ void Conversions::initializeValues()
std::cout<<"going to print value"<<std::endl; {
std::cout<<val<<std::endl; }
} template <typename T>
void Conversions::printValue(T val)
{
std::cout<<"going to print value\n";
std::cout<<val<< "\n";
}
} }