50 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
kdeng00 7177b01a98 added flag to prevent the user from being prompted when uploading songs from a directory 2019-11-12 22:07:44 -05:00
kdeng00 996b84c25c Prompt user when uploading songs from a directory 2019-11-11 22:54:53 -05:00
Kun Deng 9d8122df5c Update README.md 2019-10-26 10:22:12 -04:00
kdeng00 d7d980a4fd Added information on actions and flags to use the program when no arguments are supplied 2019-10-26 10:09:22 -04:00
kdeng00 f4845d70ec Authorization HTTP header was missing from the download request 2019-10-24 22:07:09 -04:00
kdeng00 81892cc52e Added feature to upload all songs from a directory (optional recursive). Need to document the use of it as well as how to even use this CLI 2019-10-23 20:48:42 -04:00
kdeng00 27aecc7a0d minor changes 2019-08-10 10:49:40 -04:00
kdeng00 271921d55b Changed containers the two containers that help actions and flags respectively to std::array, removed some unneeded functions 2019-08-07 21:13:35 -04:00
kdeng00 98748b383c Fixed issue where if / was not provided in the host value then it would not send the request. Fixed issue where song records are formatted correctly 2019-08-01 20:55:09 -04:00
kdeng00 f81b481f38 Added feature to retrieve song records in json format. One issue is that the json file is in one line 2019-07-31 21:52:06 -04:00
kdeng00 24a111e8e9 Changed C++ standard to C++17 and will implement functionality to retrieve songs, albums, artists, genres, cover art, and year records in json. Will add explicit versioning too 2019-07-30 22:08:55 -04:00
Kun Deng 63bee45f95 Update README.md 2019-06-16 11:57:56 -04:00
71 changed files with 3084 additions and 2160 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
+76 -57
View File
@@ -1,31 +1,63 @@
cmake_minimum_required(VERSION 3.2)
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")
HunterGate(
URL "https://github.com/ruslo/hunter/archive/v0.23.184.tar.gz"
SHA1 "fe3fb05d51c21499c7eebbe7d0e102742a54a9cd"
)
project(IcarusDownloadManager)
set(SOFTWARE_DESCRIPTION
"A tool to interact with the Icarus Music streaming API")
set(SOFTWARE_VERSION
"0.3.2")
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++11 support.")
# Set C++11 support flags for various compilers
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-std=c++11" COMPILER_SUPPORTS_CXX11)
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)
if(COMPILER_SUPPORTS_CXX11)
message(STATUS "C++11 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")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20 -stdlib=libc++")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20")
endif()
elseif(COMPILER_SUPPORTS_CXX0X)
message(STATUS "C++0x is supported.")
@@ -35,53 +67,40 @@ else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
endif()
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 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()
set(SOURCES
src/Main.cpp
src/Managers/ActionManager.cpp
src/Managers/CommitManager.cpp
src/Managers/FileManager.cpp
src/Managers/TokenManager.cpp
src/Managers/UserManager.cpp
src/Parsers/APIParser.cpp
src/Syncers/Delete.cpp
src/Syncers/Download.cpp
src/Syncers/Upload.cpp
src/Utilities/Conversions.cpp
)
set(HEADERS
src/Managers/ActionManager.h
src/Managers/CommitManager.h
src/Managers/FileManager.h
src/Managers/TokenManager.h
src/Managers/UserManager.h
src/Models/API.h
src/Models/Flags.h
src/Models/IcarusAction.h
src/Models/Song.h
src/Models/Token.h
src/Models/UploadForm.h
src/Models/User.h
src/Parsers/APIParser.h
src/Syncers/Delete.h
src/Syncers/Download.h
src/Syncers/SyncerBase.h
src/Syncers/Upload.h
src/Utilities/Conversions.h
src/Main.cpp
src/Managers/ActionManager.cpp
src/Managers/CommitManager.cpp
src/Managers/FileManager.cpp
src/Managers/TokenManager.cpp
src/Managers/UserManager.cpp
src/Models/Song.cpp
src/Parsers/APIParser.cpp
src/Syncers/Delete.cpp
src/Syncers/Download.cpp
src/Syncers/RetrieveRecords.cpp
src/Syncers/Upload.cpp
src/Utilities/Conversions.cpp
)
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)
hunter_add_package(cpr)
find_package(OpenSSL REQUIRED)
find_package(CURL REQUIRED)
find_package(cpr CONFIG REQUIRED)
add_executable(icd ${SOURCES} ${HEADERS})
target_link_libraries(icd PUBLIC nlohmann_json::nlohmann_json cpr::cpr)
include_directories(src/)
add_executable(icd ${SOURCES})
target_link_libraries(icd PRIVATE nlohmann_json::nlohmann_json OpenSSL::SSL OpenSSL::Crypto CURL::libcurl cpr::cpr)
+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>
+84 -28
View File
@@ -1,35 +1,88 @@
# IcarusDownloadManager
IcarusDownloadManager is a Linux UI software client application that has the feature of uploading and downloading songs from the [Icarus](https://github.com/amazing-username/Icarus) Music Server.
### Getting Started
Clone the repository and esnure that the cpr c++ module is implemented by checking the contents of the cpr directory. If you notice a directory structure and a *CMakeList.txt* file then you are fine. Otherwise implement the modules with the following command:
```
git submodule update --init --recursive
```
Once that is complete, verify the contents of the cpr directory and there should be a *CMakeList.txt* file. Now you must compile and link the project
```
cmake .
make
```
The program has been built and can be executed by the binary file *icd*
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
* C++
* C++ with C++20 features
* CMake
* GCC
* libCurl
* Qt 5
* [cpr](http://whoshuu.github.io/cpr/)
* GCC >= 10 or Visual Studio >= 17 [2022]
* [vcpkg](https://github.com/microsoft/vcpkg)
* [json](https://github.com/nlohmann/json)
* [openssl](https://github.com/openssl/openssl)
* [curl](https://github.com/curl/curl)
* [cpr](https://github.com/libcpr/cpr)
### 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:
```
cd IcarusDownloadManager
mkdir build
cd build
cmake ..
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.
### Downloading Song
```BASH
icd download -u spacecadet -p stellar40 -h https://icarus.com -b 15
```
### Uploading Song
```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
```Bash
icd retrieve -u spacecadet -p stellar40 -h https://icarus.com -rt songs
```
### Deleting Song
```BASH
icd delete -u spacecadet -p stellar40 -h https://icarus.com -D 15
```
## Contributing
@@ -37,13 +90,16 @@ Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on the code of conduc
## Versioning
No version has been released
[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.0](https://github.com/kdeng00/IcarusDownloadManager/releases/tag/0.1.0)
## 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
-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()
+93
View File
@@ -0,0 +1,93 @@
#ifndef ACTIONMANAGER_H_
#define ACTIONMANAGER_H_
#include<algorithm>
#include<string>
#include<string_view>
#include<array>
#include<vector>
#include"Models/Flags.h"
#include"Models/IcarusAction.h"
namespace Managers
{
class ActionManager
{
public:
ActionManager(char**, int);
Models::IcarusAction retrieveIcarusAction() const;
private:
constexpr std::array<const char*, 16> supportedFlags() noexcept
{
constexpr std::array<const char*, 16> allFlags{"-u", "-p", "-t", "-h", "-s",
"-sd", "-sr", "-d", "-D", "-b", "-rt", "-nc",
"-m", "-ca", "-smca", "-t"};
return allFlags;
}
constexpr std::array<const char*, 4> supportedActions() 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;
});
auto result = i != flags.end() ? true : false;
return result;
}
template<typename Str>
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;
});
if (i != flags.end())
{
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;
};
}
#endif
+220
View File
@@ -0,0 +1,220 @@
#ifndef COMMITMANAGER_H_
#define COMMITMANAGER_H_
#include<map>
#include<iostream>
#include<filesystem>
#include<string>
#include<string_view>
#include"Models/API.h"
#include"Models/IcarusAction.h"
#include"Models/Song.h"
#include"Models/Token.h"
#include"Utilities/Checks.h"
namespace Managers
{
class CommitManager
{
public:
CommitManager(Models::IcarusAction&);
void commitAction();
enum class RetrieveTypes
{
songs
};
// Used for parsing songs from the metadata file
class Album
{
public:
Album() = default;
void printInfo();
std::string album;
std::string albumArtist;
std::string genre;
int year;
int trackCount;
int discCount;
std::vector<Models::Song> songs;
};
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
+31
View File
@@ -0,0 +1,31 @@
#ifndef FILEMANAGER_H_
#define FILEMANAGER_H_
#include<string>
namespace Managers
{
class FileManager
{
public:
FileManager();
FileManager(std::string);
void saveFile(std::string);
void modifyFilePath(std::string);
char* retrieveFileBuffer() const;
int retrieveFileBufferLength() const;
private:
void readFile();
std::string filePath;
char* fileBuffer;
bool fileRead;
int fileBufferLength;
};
}
#endif
+25
View File
@@ -0,0 +1,25 @@
#ifndef TOKENMANAGER_H_
#define TOKENMANAGER_H_
#include"Models/API.h"
#include"Models/Token.h"
#include"Models/User.h"
namespace Managers
{
class TokenManager
{
public:
TokenManager(const Models::User&);
TokenManager(const Models::User&, Models::API&);
Models::Token requestToken();
private:
Models::API api;
Models::User user;
};
}
#endif
+28
View File
@@ -0,0 +1,28 @@
#ifndef USERMANAGER_H_
#define USERMANAGER_H_
#include<iostream>
#include"Models/IcarusAction.h"
#include"Models/User.h"
namespace Managers
{
class UserManager
{
public:
UserManager(Models::User);
UserManager(const Models::IcarusAction);
Models::User retrieveUser() const;
private:
void parseUserFromActions();
Models::User user;
Models::IcarusAction icaAction;
};
}
#endif
+19
View File
@@ -0,0 +1,19 @@
#ifndef API_H_
#define API_H_
#include<string>
namespace Models
{
class API
{
public:
std::string url;
std::string endpoint;
std::string version;
};
}
#endif
@@ -5,11 +5,14 @@
namespace Models
{
struct Flags
{
std::string flag;
std::string value;
};
class Flags
{
public:
std::string flag;
std::string value;
};
}
#endif
+53
View File
@@ -0,0 +1,53 @@
#ifndef ICARUSACTION_H_
#define ICARUSACTION_H_
#include<string>
#include<algorithm>
#include<string_view>
#include<vector>
#include<iostream>
#include"Flags.h"
namespace Models
{
class IcarusAction
{
public:
std::string retrieveFlagValue(const std::string_view flag)
{
std::string value;
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
+90
View File
@@ -0,0 +1,90 @@
#ifndef SONG_H_
#define SONG_H_
#include <string>
#include <iostream>
#include <sstream>
namespace Models
{
class Song
{
public:
Song() = default;
void printInfo()
{
std::cout<<"Title: "<<this->title<<"\n";
std::cout<<"\n";
}
std::string song_path() noexcept
{
std::stringstream buffer;
buffer << this->directory;
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
+18
View File
@@ -0,0 +1,18 @@
#ifndef TOKEN_H_
#define TOKEN_H_
#include<string>
namespace Models
{
struct Token
{
std::string accessToken;
std::string tokenType;
int expiration;
};
}
#endif
@@ -6,11 +6,13 @@
namespace Models
{
struct UploadForm
{
std::string url;
std::string filePath;
};
struct UploadForm
{
std::string url;
std::string filePath;
};
}
#endif
+7 -5
View File
@@ -5,11 +5,13 @@
namespace Models
{
struct User
{
std::string username;
std::string password;
};
struct User
{
std::string username;
std::string password;
};
}
#endif
+25
View File
@@ -0,0 +1,25 @@
#ifndef APIPARSER_H_
#define APIPARSER_H_
#include"Models/API.h"
#include"Models/IcarusAction.h"
namespace Parsers
{
class APIParser
{
public:
APIParser(Models::IcarusAction);
Models::API retrieveAPI() const;
private:
void parseAPI();
Models::API api;
Models::IcarusAction icaAct;
};
}
#endif
+25
View File
@@ -0,0 +1,25 @@
#ifndef DELETE_H_
#define DELETE_H_
#include"Models/API.h"
#include"Models/Song.h"
#include"Models/Token.h"
#include"SyncerBase.h"
namespace Syncers
{
class Delete : SyncerBase
{
public:
Delete(Models::API);
void deleteSong(const Models::Token, Models::Song);
private:
std::string retrieveUrl(Models::Song);
};
}
#endif
+33
View File
@@ -0,0 +1,33 @@
#ifndef DOWNLOAD_H_
#define DOWNLOAD_H_
#include<iostream>
#include<string>
#include"Models/API.h"
#include"Models/Song.h"
#include"Models/Token.h"
#include"SyncerBase.h"
namespace Syncers
{
class Download : SyncerBase
{
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&);
};
}
#endif
+28
View File
@@ -0,0 +1,28 @@
#ifndef RETRIEVERECORDS_H_
#define RETRIEVERECORDS_H_
#include "Managers/CommitManager.h"
#include "Models/API.h"
#include "Models/Token.h"
#include "Syncers/SyncerBase.h"
namespace Syncers
{
class RetrieveRecords: public SyncerBase
{
public:
RetrieveRecords();
RetrieveRecords(Models::API, Models::Token);
void retrieve(Managers::CommitManager::RetrieveTypes);
private:
void fetchSongs();
Models::API api;
Models::Token token;
};
}
#endif
+29
View File
@@ -0,0 +1,29 @@
#ifndef SYNCERBASE_H_
#define SYNCERBASE_H_
#include<string>
#include"Models/API.h"
namespace Syncers
{
class SyncerBase
{
protected:
Models::API api;
const int OK = 200;
const int UNAUTHORIZED = 401;
const int NOTFOUND = 404;
enum class Result
{
OK = 200,
UNAUTHORIZED = 401,
NOTFOUND = 404
};
};
}
#endif
+55
View File
@@ -0,0 +1,55 @@
#ifndef UPLOAD_H_
#define UPLOAD_H_
#include <filesystem>
#include <string>
#include <vector>
#include <nlohmann/json.hpp>
#include "Managers/CommitManager.h"
#include "Managers/FileManager.h"
#include "Models/API.h"
#include "Models/Song.h"
#include "Models/Token.h"
#include "Models/UploadForm.h"
namespace fs = std::filesystem;
namespace Syncers
{
class Upload
{
public:
Upload() = default;
Upload(Models::API api, Models::Token token) : m_token(token), api(api)
{
this->api.endpoint = "song/data";
}
Models::Song uploadSong(Models::Song&);
void uploadSongsFromDirectory(const std::string&, const bool, bool);
void uploadSongWithMetadata(Managers::CommitManager::Album&, Models::Song&, Models::CoverArt&);
private:
Managers::FileManager fMgr;
Models::API api;
Models::Song song;
Models::Token m_token;
std::vector<Models::Song> retrieveAllSongsFromDirectory(const std::string&,
bool);
std::string retrieveUrl();
Models::Song retrieveSongPath(fs::directory_entry&);
void printSongDetails();
void printSongDetails(std::vector<Models::Song>&);
void printJsonData(const nlohmann::json&);
};
}
#endif
+36
View File
@@ -0,0 +1,36 @@
#ifndef ABOUTWINDOW_H_
#define ABOUTWINDOW_H_
#include<memory>
#include<QDialog>
#include<QDockWidget>
#include<QLabel>
#include<QPushButton>
#include<QWidget>
#include"UI/CommonWindow.h"
namespace UI
{
class AboutWindow: public QDialog, public CommonWindow
{
Q_OBJECT
public:
AboutWindow(QWidget* parent=0);
~AboutWindow() = default;
private:
void connections();
void setupWindow();
std::unique_ptr<QLabel> appName;
private slots:
void closeWindow();
};
}
#endif
+33
View File
@@ -0,0 +1,33 @@
#ifndef COMMONWINDOW_H_
#define COMMONWINDOW_H_
#include<memory>
#include<QDialog>
#include<QHBoxLayout>
#include<QVBoxLayout>
#include<QComboBox>
#include<QPushButton>
namespace UI
{
class CommonWindow
{
public:
CommonWindow() = default;
~CommonWindow() = default;
protected:
virtual void connections()=0;
std::unique_ptr<QComboBox> selectionBoxQt;
std::unique_ptr<QPushButton> actionButtonQt;
std::unique_ptr<QVBoxLayout> mainLayoutQt;
std::unique_ptr<QVBoxLayout> subLayoutOneQt;
std::unique_ptr<QVBoxLayout> subLayoutTwoQt;
int windowHeight, windowWidth;
};
}
#endif
+84
View File
@@ -0,0 +1,84 @@
#ifndef MAINWINDOW_H_
#define MAINWINDOW_H_
#include<iostream>
#include<memory>
#include<QAction>
#include<QComboBox>
#include<QDialog>
#include<QDockWidget>
#include<QLabel>
#include<QMenu>
#include<QMenuBar>
#include<QMainWindow>
#include<QPushButton>
#include<QStackedWidget>
#include<QTextEdit>
#include<QWidget>
#include"UI/CommonWindow.h"
#include"UI/AboutWindow.h"
namespace UI
{
class MainWindow: public QMainWindow, public CommonWindow
{
Q_OBJECT
public:
MainWindow();
~MainWindow() = default;
private:
void configureDownloadSection();
void configureUploadSection();
void configureWindowDimensions();
void configureWindowProperties();
void connections();
void createMenus();
void setupMainWidget();
void setupMainWindow();
void setupWindowLists();
std::unique_ptr<QStackedWidget> widgetStack;
std::unique_ptr<QVBoxLayout> stackLayout;
std::unique_ptr<QHBoxLayout> urlPortion;
std::unique_ptr<QHBoxLayout> songPathPortion;
std::unique_ptr<QWidget> mainWidgetQt;
std::unique_ptr<QWidget> uploadSongWidgetQt;
std::unique_ptr<QDockWidget> MainDockWidgetQt;
std::unique_ptr<QComboBox> windowComboBox;
std::unique_ptr<QPushButton> uploadSongQt;
std::unique_ptr<QTextEdit> urlQt;
std::unique_ptr<QTextEdit> sourceFilePathQt;
std::unique_ptr<QLabel> urlLabel;
std::unique_ptr<QLabel> songPath;
std::unique_ptr<QMenu> fileMenuQt;
std::unique_ptr<QMenu> editMenuQt;
std::unique_ptr<QMenu> helpMenuQt;
std::unique_ptr<QAction> closeApplicationQt;
std::unique_ptr<QAction> aboutApplicationQt;
std::unique_ptr<AboutWindow> aboutWindow;
signals:
private slots:
void uploadSong();
void exitApplication();
void displaySoftwareInformation();
void setCurrentIndex(int);
};
}
#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
+32
View File
@@ -0,0 +1,32 @@
#ifndef CONVERSIONS_H_
#define CONVERSIONS_H_
#include<memory>
#include<string>
namespace Utilities
{
class Conversions
{
public:
Conversions();
static void toLowerChar(char &c)
{
if (std::isalpha(c))
{
c = std::tolower(c);
}
}
void initializeValues();
template<typename T>
void printValue(T val);
private:
};
}
#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
+58 -12
View File
@@ -12,22 +12,68 @@ using std::string;
using Managers::ActionManager;
using Managers::CommitManager;
string songPath{};
string newSongPath{};
constexpr static auto IcarusDownloadManager_version()
{
return "v0.3.2";
}
void printHelp()
{
cout<<"icd [Action] [flag]\n\n";
cout<<"Actions\n";
cout<<"download\n";
cout<<"upload\n";
cout<<"upload-meta\n";
cout<<"retrieve\n";
cout<<"delete\n\n";
cout<<"Flags\n";
cout<<"Required for all actions\n";
cout<<"-u username\n";
cout<<"-p password\n";
cout<<"-h host\n\n";
cout<<"Required for upload\n";
cout<<"-s path of song\n";
cout<<"-sd directory where to 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<<"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<<"-b song id\n";
cout<<"-d path to download song (Optional)\n\n";
cout<<"Required for retrieving records\n";
cout<<"-rt retrieve type (songs is only accepted)\n\n";
cout<<"Required for deleting a song\n";
cout<<"-D song id\n\n";
}
int main(int argc, char** argv)
{
if (argc < 2)
{
cout<<"No actions provided"<<endl;
return 1;
}
if (argc < 2)
{
printHelp();
return -1;
}
ActionManager actMgr{argv};
auto chosenAction = actMgr.retrieveIcarusAction();
ActionManager actMgr(argv, argc);
auto chosenAction = actMgr.retrieveIcarusAction();
CommitManager commitMgr{chosenAction};
commitMgr.commitAction();
chosenAction.print_action_and_flags();
return 0;
CommitManager commitMgr(chosenAction);
commitMgr.commitAction();
return 0;
}
+102 -178
View File
@@ -1,12 +1,14 @@
#include"ActionManager.h"
#include"Managers/ActionManager.h"
#include<algorithm>
#include<iostream>
#include<exception>
#include<utility>
#include<cstring>
using std::cout;
using std::endl;
using std::string;
using std::string_view;
using std::vector;
using Models::Flags;
@@ -14,181 +16,103 @@ using Models::IcarusAction;
namespace Managers
{
#pragma
ActionManager::ActionManager(char **param)
{
this->params = param;
action = string{params[1]};
transform(action.begin(), action.end(),
action.begin(), ::tolower);
initialize();
}
#pragma Constructors
#pragma
IcarusAction ActionManager::retrieveIcarusAction() const
{
auto icarusAction = IcarusAction{};
icarusAction.flags = flags;
icarusAction.action = action;
return icarusAction;
}
vector<Flags> ActionManager::retrieveFlags() const
{
return flags;
}
string ActionManager::retrieveAction() const
{
return action;
}
bool ActionManager::isNumber(string val)
{
return !val.empty() && std::find_if(val.begin(),
val.end(), [](char c)
{
return !std::isdigit(c);
}) == val.end();
}
void ActionManager::initialize()
{
initializeSupportedActions();
validateAction();
validateFlags();
}
void ActionManager::initializeSupportedActions()
{
supportedActions = vector<string>{
"download", "delete",
"retrieve", "upload"
};
}
void ActionManager::initializeSupportedFlags()
{
supportedFlags = vector<string>{
"-u", "-p", "-t", "-h", "-s",
"-d", "-D", "-b"
};
}
void ActionManager::validateAction()
{
cout<<"Validating action"<<endl;
if (std::any_of(supportedActions.begin(), supportedActions.end(),
[&](string val)
{
return !val.compare(action);
}))
{
cout<<"Action: "<<action<<" is valid"<<endl;
}
else
{
cout<<"Action is not valid"<<endl;
exit(1);
}
}
void ActionManager::validateFlags()
{
cout<<"Validating flags"<<endl;
auto flagVals = parsedFlags();
initializeSupportedFlags();
Flags flg{};
for (auto flag : flagVals)
{
//if (flag.size() > 3 || flg.flag.compare("-D"))
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(supportedFlags.begin(), supportedFlags.end(),
[&](string val)
{
return !val.compare(flag);
}))
{
cout<<"flag "<<flag<<endl;
flg.flag = flag;
}
else
{
cout<<"Action is not valid"<<endl;
exit(1);
}
}
}
vector<string> ActionManager::parsedFlags()
{
auto parsed = vector<string>{};
try
{
for (auto i = 2; true; ++i)
{
string val{*(params + i)};
cout<<"Parsed flag "<<val<<endl;
parsed.push_back(val);
}
}
catch (std::exception e)
{
auto msg = e.what();
cout<<"This happend: "<<msg<<endl<<endl;
}
return parsed;
}
#pragma
void ActionManager::printAction()
{
if (action.empty())
{
printf("Action is empty\n");
}
else
{
cout<<"Action is "<<action<<endl;
}
}
void ActionManager::printFlags(vector<string> flagVals)
{
if (flagVals.empty())
{
printf("Flags and values are empty\n");
}
else
{
printf("Printing flags and values..\n");
for (auto flgVal : flagVals)
{
cout<<flgVal<<endl;
}
}
}
void ActionManager::printFlags()
{
cout<<"\nPrinting flags..."<<endl;
for (auto flag: flags)
{
cout<<"flag "<<flag.flag<<endl;
cout<<"value "<<flag.value<<endl;
}
}
#pragma Testing
#pragma Functions
#pragma region Constructors
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)
{
Flags flg;
cout<<"Value: "<<*flag<<"\n";
if (isValidFlag<string>(*flag) && doesFlagHaveValue<string>(*flag))
{
cout<<"Flag has value\n";
flg.flag = *flag;
flg.value = *(++flag);
}
else if (isValidFlag<string>(*flag))
{
cout<<"Flag does not have a value\n";
flg.flag = *flag;
}
else
{
cout<<"Flag "<<*flag<<" is not valid"<<endl;
exit(1);
}
flags.emplace_back(std::move(flg));
}
}
vector<string> ActionManager::parsedFlags()
{
auto parsed = vector<string>();
for (auto i = 2; i < paramCount; ++i)
{
const std::string flag(std::move(*(params + i)));
parsed.push_back(std::move(flag));
}
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
}
-43
View File
@@ -1,43 +0,0 @@
#ifndef ACTIONMANAGER_H_
#define ACTIONMANAGER_H_
#include<string>
#include<vector>
#include"Models/Flags.h"
#include"Models/IcarusAction.h"
namespace Managers
{
class ActionManager
{
public:
ActionManager(char**);
Models::IcarusAction retrieveIcarusAction() const;
std::vector<Models::Flags> retrieveFlags() const;
std::string retrieveAction() const;
private:
bool isNumber(std::string);
void initialize();
void initializeSupportedActions();
void initializeSupportedFlags();
void validateAction();
void validateFlags();
std::vector<std::string> parsedFlags();
void printAction();
void printFlags(std::vector<std::string>);
void printFlags();
std::string action;
std::vector<std::string> supportedActions;
std::vector<std::string> supportedFlags;
std::vector<Models::Flags> flags;
char **params;
};
}
#endif
+432 -135
View File
@@ -1,16 +1,23 @@
#include"CommitManager.h"
#include"Managers/CommitManager.h"
#include<iostream>
#include <iostream>
#include <fstream>
#include <sstream>
#include <filesystem>
#include"Models/API.h"
#include"Models/Song.h"
#include"Parsers/APIParser.h"
#include"Syncers/Delete.h"
#include"Syncers/Download.h"
#include"Syncers/Upload.h"
#include "nlohmann/json.hpp"
#include"TokenManager.h"
#include"UserManager.h"
#include "Models/API.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::endl;
@@ -21,140 +28,430 @@ using Managers::TokenManager;
using Managers::UserManager;
using Models::API;
using Models::Song;
using Models::Token;
using Parsers::APIParser;
using Models::IcarusAction;
using Syncers::Delete;
using Syncers::Download;
using Syncers::RetrieveRecords;
using Syncers::Upload;
namespace filesystem = std::filesystem;
namespace Managers
{
#pragma
CommitManager::CommitManager(IcarusAction icaAct)
{
icaAction = icaAct;
initializeMapActions();
}
#pragma Constructors;
#pragma region Constructors
CommitManager::CommitManager(IcarusAction& icaAct) : icaAction(std::move(icaAct))
{ }
#pragma endregion
#pragma
void CommitManager::commitAction()
{
auto action = icaAction.action;
cout<<"Commitning "<<action<<" action"<<endl;
switch (mapActions[action])
{
case deleteAct:
deleteSong();
break;
case downloadAct:
downloadSong();
break;
case retrieveAct: // No plans to imeplement
break;
case uploadAct:
uploadSong();
break;
}
}
#pragma region Functions
void CommitManager::commitAction()
{
auto action = icaAction.action;
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;
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;
};
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());
Upload up(api, token);
for (auto &song : songs)
{
up.uploadSongWithMetadata(album, song, cover);
}
}
#pragma region private
CommitManager::Album CommitManager::retrieveMetadata(const std::string_view path)
{
CommitManager::Album album;
const auto fileContent = retrieveFileContent(path);
cout<<"Parsing...\n";
auto serialized = nlohmann::json::parse(fileContent);
cout<<"Parsed\n";
album.album = serialized["album"].get<std::string>();
album.albumArtist = serialized["album_artist"].get<std::string>();
album.genre = serialized["genre"].get<std::string>();
album.year = serialized["year"].get<int>();
album.trackCount = serialized["track_count"].get<int>();
album.discCount = serialized["disc_count"].get<int>();
album.songs.reserve(album.trackCount);
for (auto &j : serialized["tracks"])
{
Song song;
song.title = j["title"].get<std::string>();
song.track = j["track"].get<int>();
song.disc = j["disc"].get<int>();
song.artist = j["artist"].get<std::string>();
song.album = album.album;
song.year = album.year;
song.genre = album.genre;
song.generate_filename_from_track();
const auto p = fs::path(path);
song.directory = p.parent_path().string();
album.songs.push_back(song);
}
return album;
}
string CommitManager::retrieveFileContent(const std::string_view path)
{
string path_str(path);
string value;
std::stringstream buffer;
std::fstream file(path_str, std::ios::in);
buffer<<file.rdbuf();
file.close();
value.assign(buffer.str());
return value;
}
#pragma endregion
void CommitManager::Album::printInfo()
{
std::cout<<"Album: "<<this->album<<"\n";
std::cout<<"Album Artist: "<<this->albumArtist<<"\n";
std::cout<<"Genre: "<<this->genre<<"\n";
std::cout<<"Year: "<<this->year<<"\n";
std::cout<<"Track count: "<<this->trackCount<<"\n";
std::cout<<"Disc count: "<<this->discCount<<"\n";
std::cout<<"\n";
}
#pragma region Functions
void CommitManager::initializeMapActions()
{
mapActions = map<string, ActionValues>{
{"delete", deleteAct}, {"download", downloadAct},
{"retrieve", retrieveAct},
{"upload", uploadAct}
};
}
void CommitManager::deleteSong()
{
cout<<"Deleting song..."<<endl;
UserManager usrMgr{icaAction};
auto user = usrMgr.retrieveUser();
APIParser apiPrs{icaAction};
auto api = apiPrs.retrieveAPI();
TokenManager tk{user, api};
auto token = tk.requestToken();
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};
del.deleteSong(token, song);
}
void CommitManager::downloadSong()
{
cout<<"Starting downloading process..."<<endl;
UserManager usrMgr{icaAction};
auto user = usrMgr.retrieveUser();
APIParser apiPrs{icaAction};
auto api = apiPrs.retrieveAPI();
TokenManager tk{user, api};
auto token = tk.requestToken();
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};
dnld.downloadSong(token, song);
}
void CommitManager::uploadSong()
{
cout<<"Uploading song..."<<endl;
UserManager usrMgr{icaAction};
auto user = usrMgr.retrieveUser();
APIParser apiPrs{icaAction};
auto api = apiPrs.retrieveAPI();
TokenManager tk{user, api};
auto token = tk.requestToken();
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);
}
}
Upload upld{api};
upld.uploadSong(token, song);
}
#pragma Functions
}
-35
View File
@@ -1,35 +0,0 @@
#ifndef COMMITMANAGER_H_
#define COMMITMANAGER_H_
#include<map>
#include<string>
#include"Models/IcarusAction.h"
namespace Managers
{
class CommitManager
{
public:
CommitManager(Models::IcarusAction);
void commitAction();
private:
void initializeMapActions();
void deleteSong();
void downloadSong();
void uploadSong();
enum ActionValues
{
deleteAct,
downloadAct,
retrieveAct,
uploadAct
};
std::map<std::string, ActionValues> mapActions;
Models::IcarusAction icaAction;
};
}
#endif
+59 -52
View File
@@ -1,7 +1,7 @@
#include<iostream>
#include<fstream>
#include"FileManager.h"
#include"Managers/FileManager.h"
using std::cout;
using std::endl;
@@ -11,56 +11,63 @@ using std::string;
namespace Managers
{
FileManager::FileManager() {}
FileManager::FileManager(string filePath)
{
this->filePath = filePath;
readFile();
}
void FileManager::saveFile(string newFilePath)
{
if (!fileRead)
readFile();
ofstream of{newFilePath, ofstream::binary};
of.write(fileBuffer, fileBufferLength);
of.close();
}
void FileManager::readFile()
{
ifstream is{filePath, ifstream::binary};
if (is)
{
is.seekg (0, is.end);
fileBufferLength = is.tellg();
is.seekg (0, is.beg);
fileBuffer = new char [fileBufferLength];
cout<< "Reading "<<fileBufferLength<<" characters... "<<endl;;
is.read (fileBuffer,fileBufferLength);
if (is)
cout<<"all characters read successfully.";
else
cout<<"error: only "<<is.gcount()<<" could be read";
cout<<endl;
is.close();
fileRead = true;
}
}
void FileManager::modifyFilePath(string filePath)
{
this->filePath = filePath;
}
char* FileManager::retrieveFileBuffer() const
{
return fileBuffer;
}
int FileManager::retrieveFileBufferLength() const { return fileBufferLength; }
#pragma region Constructors
FileManager::FileManager() {}
FileManager::FileManager(string filePath)
{
this->filePath = filePath;
readFile();
}
#pragma endregion
#pragma region Functions
void FileManager::saveFile(string newFilePath)
{
if (!fileRead)
readFile();
ofstream of{newFilePath, ofstream::binary};
of.write(fileBuffer, fileBufferLength);
of.close();
}
void FileManager::readFile()
{
ifstream is{filePath, ifstream::binary};
if (is)
{
is.seekg (0, is.end);
fileBufferLength = is.tellg();
is.seekg (0, is.beg);
fileBuffer = new char [fileBufferLength];
cout<< "Reading "<<fileBufferLength<<" characters... "<<endl;;
is.read (fileBuffer,fileBufferLength);
if (is)
cout<<"all characters read successfully.";
else
cout<<"error: only "<<is.gcount()<<" could be read";
cout<<endl;
is.close();
fileRead = true;
}
}
void FileManager::modifyFilePath(string filePath)
{
this->filePath = filePath;
}
char* FileManager::retrieveFileBuffer() const
{
return fileBuffer;
}
int FileManager::retrieveFileBufferLength() const { return fileBufferLength; }
#pragma endregion
}
-29
View File
@@ -1,29 +0,0 @@
#ifndef FILEMANAGER_H_
#define FILEMANAGER_H_
#include<string>
namespace Managers
{
class FileManager
{
public:
FileManager();
FileManager(std::string);
void saveFile(std::string);
void modifyFilePath(std::string);
char* retrieveFileBuffer() const;
int retrieveFileBufferLength() const;
private:
void readFile();
std::string filePath;
char* fileBuffer;
bool fileRead;
int fileBufferLength;
};
}
#endif
+42 -42
View File
@@ -1,4 +1,4 @@
#include"TokenManager.h"
#include"Managers/TokenManager.h"
#include<iostream>
@@ -17,46 +17,46 @@ using Models::User;
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
Token TokenManager::requestToken()
{
Token token{};
json usrObj;
usrObj["username"] = user.username;
usrObj["password"] = user.password;
cout<<user.username<<" "<<user.password<<endl;
cout<<"Sending request for token"<<endl;
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"}});
cout<<r.text<<endl;
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 Functions
#pragma region Constructors
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 endregion
#pragma region Functions
Token TokenManager::requestToken()
{
Token token{};
json usrObj;
usrObj["username"] = user.username;
usrObj["password"] = user.password;
cout<<"Sending request for token"<<endl;
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
}
-23
View File
@@ -1,23 +0,0 @@
#ifndef TOKENMANAGER_H_
#define TOKENMANAGER_H_
#include"Models/API.h"
#include"Models/Token.h"
#include"Models/User.h"
namespace Managers
{
class TokenManager
{
public:
TokenManager(const Models::User);
TokenManager(const Models::User, Models::API);
Models::Token requestToken();
private:
Models::API api;
Models::User user;
};
}
#endif
+40 -38
View File
@@ -1,4 +1,4 @@
#include"UserManager.h"
#include"Managers/UserManager.h"
#include<iostream>
#include<string>
@@ -12,42 +12,44 @@ using Models::User;
namespace Managers
{
#pragma
UserManager::UserManager(User user)
{
this->user = user;
}
UserManager::UserManager(const IcarusAction icaAct)
{
this->icaAction = icaAct;
this->user = User{};
parseUserFromActions();
}
#pragma Constructors
#pragma
User UserManager::retrieveUser() const
{
return user;
}
void UserManager::parseUserFromActions()
{
auto args = icaAction.flags;
for (auto arg : args)
{
auto flag = arg.flag;
if (flag.compare("-u") == 0)
{
user.username = arg.value;
}
if (flag.compare("-p") == 0)
{
user.password = arg.value;
}
}
}
#pragma Functions
#pragma region Constructors
UserManager::UserManager(User user)
{
this->user = user;
}
UserManager::UserManager(const IcarusAction icaAct)
{
this->icaAction = icaAct;
this->user = User{};
parseUserFromActions();
}
#pragma endregion
#pragma region Functions
User UserManager::retrieveUser() const
{
return user;
}
void UserManager::parseUserFromActions()
{
auto args = icaAction.flags;
for (auto arg : args)
{
auto flag = arg.flag;
if (flag.compare("-u") == 0)
{
user.username = arg.value;
}
if (flag.compare("-p") == 0)
{
user.password = arg.value;
}
}
}
#pragma endregion
}
-26
View File
@@ -1,26 +0,0 @@
#ifndef USERMANAGER_H_
#define USERMANAGER_H_
#include<iostream>
#include"Models/IcarusAction.h"
#include"Models/User.h"
namespace Managers
{
class UserManager
{
public:
UserManager(Models::User);
UserManager(const Models::IcarusAction);
Models::User retrieveUser() const;
private:
void parseUserFromActions();
Models::User user;
Models::IcarusAction icaAction;
};
}
#endif
-16
View File
@@ -1,16 +0,0 @@
#ifndef API_H_
#define API_H_
#include<string>
namespace Models
{
struct API
{
std::string url;
std::string endpoint;
std::string version;
};
}
#endif
-18
View File
@@ -1,18 +0,0 @@
#ifndef ICARUSACTION_H_
#define ICARUSACTION_H_
#include<string>
#include<vector>
#include"Flags.h"
namespace Models
{
struct IcarusAction
{
std::string action;
std::vector<Flags> flags;
};
}
#endif
+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();
}
}
-24
View File
@@ -1,24 +0,0 @@
#ifndef SONG_H_
#define SONG_H_
#include<string>
namespace Models
{
struct Song
{
int id;
std::string title;
std::string artist;
std::string album;
std::string genre;
int year;
int duration;
char *songData;
std::string data;
std::string songPath;
};
}
#endif
-17
View File
@@ -1,17 +0,0 @@
#ifndef TOKEN_H_
#define TOKEN_H_
#include<string>
namespace Models
{
struct Token
{
std::string accessToken;
std::string tokenType;
int expiration;
};
}
#endif
+41 -47
View File
@@ -1,6 +1,6 @@
#include"APIParser.h"
#include "Parsers/APIParser.h"
#include<iostream>
#include <iostream>
using std::cout;
using std::endl;
@@ -10,50 +10,44 @@ using Models::IcarusAction;
namespace Parsers
{
#pragma
APIParser::APIParser(IcarusAction icaAct)
{
this->icaAct = icaAct;
api = API{};
parseAPI();
}
#pragma endregion
#pragma
API APIParser::retrieveAPI() const
{
return api;
}
void APIParser::parseAPI()
{
auto flags = icaAct.flags;
cout<<"Parsing api"<<endl;
//for (auto flag : flags)
for (auto i =0; i < flags.size(); ++i)
{
auto arg = flags[i].flag;
auto value = flags[i].value;
if (arg.compare("-h") == 0)
{
api.url = value;
}
if (value.compare("-h") == 0)
{
api.url = flags[i + 1].value;
}
cout<<"url is "<<api.url<<endl;
}
// TODO: For now I will hard code
// the api version since I am only
// on version 1
api.version = "v1";
}
#pragma functions
#pragma region Constructors
APIParser::APIParser(IcarusAction icaAct) : icaAct(icaAct)
{
api = API{};
parseAPI();
}
#pragma endregion
#pragma region Functions
API APIParser::retrieveAPI() const
{
return api;
}
void APIParser::parseAPI()
{
auto flags = icaAct.flags;
cout << "Parsing api" << endl;
for (auto i =0; i < flags.size(); ++i)
{
auto arg = flags[i].flag;
auto value = flags[i].value;
if (arg.compare("-h") == 0)
{
api.url = (value[value.size()-1] == '/') ? value : value + "/";
break;
}
}
// NOTE: For now I will hard code
// the api version since I am only
// on version 1
api.version = "v1";
}
#pragma endregion
}
-23
View File
@@ -1,23 +0,0 @@
#ifndef APIPARSER_H_
#define APIPARSER_H_
#include"Models/API.h"
#include"Models/IcarusAction.h"
namespace Parsers
{
class APIParser
{
public:
APIParser(Models::IcarusAction);
Models::API retrieveAPI() const;
private:
void parseAPI();
Models::API api;
Models::IcarusAction icaAct;
};
}
#endif
+48 -46
View File
@@ -1,9 +1,9 @@
#include"Delete.h"
#include "Syncers/Delete.h"
#include<exception>
#include<iostream>
#include <exception>
#include <iostream>
#include<cpr/cpr.h>
#include <cpr/cpr.h>
using std::cout;
using std::endl;
@@ -16,47 +16,49 @@ using Models::Token;
namespace Syncers
{
#pragma
Delete::Delete(API api)
{
this->api = api;
this->api.endpoint = "song/data";
}
#pragma Constructors
#pragma
void Delete::deleteSong(const Token token, Song song)
{
try
{
auto url = retrieveUrl(song);
string auth{token.tokenType};
auth.append(" " + token.accessToken);
auto r = cpr::Delete(cpr::Url(url),
cpr::Header{{"authorization", auth}});
auto statusCode = r.status_code;
cout<<"Status code "<<statusCode<<endl;
}
catch (exception e)
{
auto msg = e.what();
cout<<msg<<endl;
}
cout<<"Finished"<<endl;
}
string Delete::retrieveUrl(Song song)
{
string url{api.url + "api/" + api.version + "/" +
api.endpoint + "/"};
url.append(std::to_string(song.id));
cout<<"url "<<url<<endl;
return url;
}
#pragma Functions
#pragma region Constructors
Delete::Delete(API api)
{
this->api = api;
this->api.endpoint = "song/data";
}
#pragma endregion
#pragma region Functions
void Delete::deleteSong(const Token token, Song song)
{
try
{
auto url = retrieveUrl(song);
string auth{token.tokenType};
auth.append(" " + token.accessToken);
auto r = cpr::Delete(cpr::Url(url),
cpr::Header{{"authorization", auth}});
auto statusCode = r.status_code;
cout<<"Status code "<<statusCode<<endl;
}
catch (exception e)
{
auto msg = e.what();
cout<<msg<<endl;
}
cout<<"Finished"<<endl;
}
string Delete::retrieveUrl(Song song)
{
string url{api.url + "api/" + api.version + "/" +
api.endpoint + "/"};
url.append(std::to_string(song.id));
cout<<"url "<<url<<endl;
return url;
}
#pragma endregion
}
-23
View File
@@ -1,23 +0,0 @@
#ifndef DELETE_H_
#define DELETE_H_
#include"Models/API.h"
#include"Models/Song.h"
#include"Models/Token.h"
#include"SyncerBase.h"
namespace Syncers
{
class Delete : SyncerBase
{
public:
Delete(Models::API);
void deleteSong(const Models::Token, Models::Song);
private:
std::string retrieveUrl(Models::Song);
};
}
#endif
+76 -92
View File
@@ -1,10 +1,10 @@
#include"Download.h"
#include "Syncers/Download.h"
#include<exception>
#include<iostream>
#include<fstream>
#include <exception>
#include <iostream>
#include <fstream>
#include<cpr/cpr.h>
#include <cpr/cpr.h>
using std::cout;
using std::endl;
@@ -18,92 +18,76 @@ using Models::Token;
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
void Download::downloadSong(const int id)
{
string urlRoot = "http://192.168.1.5";
int port = 9349;
string endpoint = "api/song/data/" + std::to_string(id);
string url = urlRoot + ":" + std::to_string(port) + "/" +
endpoint;
auto r = cpr::Get(cpr::Url{url});
const char* newBuff = r.text.c_str();
int bufferLength = r.text.size();
ofstream saveSong{downloadFilePath, ofstream::binary};
saveSong.write(newBuff, bufferLength);
cout<<"HTTP status code: "<<r.status_code<<endl;
cout<<"Header info: "<<r.header["content-type"]<<endl;
cout<<"Header info: "<<endl;
cout<<r.header["content-type"]<<endl;
cout<<r.header["content-disposition"]<<endl;
}
void Download::downloadSong(const Token token, Song song)
{
try
{
string url = retrieveUrl(song);
song.songPath.append("track.mp3");
cout<<"song path "<<song.songPath<<endl;
string auth{token.tokenType};
auth.append(" " + token.accessToken);
auto r = cpr::Get(cpr::Url(url),
cpr::Header{{"authorization", auth}});
int statusCode = r.status_code;
if (statusCode == OK)
{
song.data = r.text;
saveSong(&song);
}
cout<<"finsihed with status code "<<statusCode<<endl;
}
catch (exception e)
{
auto msg = e.what();
cout<<msg<<endl;
}
}
string Download::retrieveUrl(Song song)
{
string url{api.url + "api/" + api.version + "/" +
api.endpoint + "/"};
url.append(std::to_string(song.id));
cout<<"url "<<url<<endl;
return url;
}
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 Functions
#pragma region Constructors
Download::Download() { }
Download::Download(API api)
{
this->api = api;
this->api.endpoint = "song/data";
}
Download::Download(string filePath)
{
downloadFilePath = filePath;
}
#pragma endregion
#pragma region Functions
void Download::downloadSong(const Token token, Song song)
{
try
{
string url = retrieveUrl(song);
song.songPath.append("track.mp3");
cout<<"song path "<<song.songPath<<endl;
string auth{token.tokenType};
auth.append(" " + token.accessToken);
auto r = cpr::Get(cpr::Url(url),
cpr::Header{{"Content-type", "audio/mpeg"},
{"Authorization", auth}});
int statusCode = r.status_code;
if (statusCode == OK) {
song.data = r.text;
saveSong(song);
}
cout<<"finsihed with status code "<<statusCode<<endl;
}
catch (exception e)
{
auto msg = e.what();
cout<<msg<<endl;
}
}
string Download::retrieveUrl(Song song)
{
string url{api.url + "api/" + api.version + "/" +
api.endpoint + "/"};
url.append(std::to_string(song.id));
cout<<"url "<<url<<endl;
return url;
}
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
}
-32
View File
@@ -1,32 +0,0 @@
#ifndef DOWNLOAD_H_
#define DOWNLOAD_H_
#include<iostream>
#include<string>
#include"Models/API.h"
#include"Models/Song.h"
#include"Models/Token.h"
#include"SyncerBase.h"
namespace Syncers
{
class Download : SyncerBase
{
public:
Download();
Download(Models::API);
Download(std::string);
void downloadSong(int);
void downloadSong(const Models::Token token, Models::Song);
private:
std::string retrieveUrl(Models::Song);
std::string downloadFilePath;
void saveSong(Models::Song*);
};
}
#endif
+67
View File
@@ -0,0 +1,67 @@
#include "Syncers/RetrieveRecords.h"
#include <iostream>
#include <fstream>
#include <cpr/cpr.h>
#include <nlohmann/json.hpp>
#include "Utilities/Conversions.h"
using std::cout;
using std::endl;
using std::ofstream;
using Managers::CommitManager;
using Models::API;
using Models::Token;
using Utilities::Conversions;
namespace Syncers
{
#pragma region Constructors
RetrieveRecords::RetrieveRecords() { }
RetrieveRecords::RetrieveRecords(API api, Token token)
: token(token), api(api) { }
#pragma endregion
#pragma region Functions
void RetrieveRecords::retrieve(CommitManager::RetrieveTypes type)
{
switch (type)
{
case CommitManager::RetrieveTypes::songs:
fetchSongs();
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();
}
#pragma endregion
}
-20
View File
@@ -1,20 +0,0 @@
#ifndef SYNCERBASE_H_
#define SYNCERBASE_H_
#include<string>
#include"Models/API.h"
namespace Syncers
{
class SyncerBase
{
protected:
Models::API api;
const int OK = 200;
const int UNAUTHORIZED = 401;
const int NOTFOUND = 404;
};
}
#endif
+217 -132
View File
@@ -1,13 +1,14 @@
#include<iostream>
#include<exception>
#include<string>
#include <iostream>
#include <filesystem>
#include <exception>
#include<cpr/cpr.h>
#include<nlohmann/json.hpp>
#include "cpr/cpr.h"
#include"Upload.h"
#include "Syncers/Upload.h"
#include "Utilities/Conversions.h"
using std::cout;
using std::cin;
using std::endl;
using std::exception;
using std::string;
@@ -23,136 +24,220 @@ using namespace cpr;
namespace Syncers
{
Upload::Upload() { }
Upload::Upload(string filePath)
{
this->songPath = filePath;
this->fMgr = FileManager(songPath);
}
Upload::Upload(API api)
{
this->api = api;
this->api.endpoint = "song/data";
}
Upload::Upload(UploadForm formData)
{
this->url = formData.url;
this->songPath = formData.filePath;
}
#pragma region Constructors
#pragma endregion
void Upload::uploadSong()
{
try
{
auto r = cpr::Post(cpr::Url{url},
cpr::Multipart{{"key", "small value"},
{"file", cpr::File{songPath}}});
cout << r.status_code<< std::endl;
#pragma region Functions
Song Upload::uploadSong(Song& song)
{
try
{
auto url = retrieveUrl();
cout<<"Success"<<endl;
}
catch(std::exception& e)
{
cout<<e.what()<<endl;
}
cout<<"Finished"<<endl;
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}}
);
}
void Upload::uploadSong(const Models::Token token, Song song)
{
try
{
auto url = retrieveUrl();
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>();
cout<<"url "<<url<<endl;
string auth{token.tokenType};
auth.append(" " + token.accessToken);
auto r = cpr::Post(cpr::Url{url},
cpr::Multipart{{"key", "small value"},
{"file", cpr::File{song.songPath}}},
cpr::Header{{"authorization", auth}}
);
return song;
}
catch (exception& e)
{
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 answer = 'a';
cout << "are you sure you want to upload " << songs.size() << " songs? [y/n]";
cin >> answer;
Utilities::Conversions::toLowerChar(answer);
if (answer == 'y' || answer == 'Y')
{
confirmUpload = true;
break;
}
}
cout << "uploading songs\n";
for (auto& song: songs)
{
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;
}
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()))
{
const auto ext = dirEntry.path().extension().string();
if (ext.compare(mp3Ext) == 0)
{
cout << "found mp3 file" << endl;
song.songPath = dirEntry.path().string();
}
}
return song;
}
#pragma region Testing
void Upload::printSongDetails(std::vector<Song>& songs)
{
for (auto& song: songs)
{
cout<<"Song details: "<<endl;
cout<<"Id: "<<song.id<<endl;
cout<<"Title: "<<song.title<<endl;
cout<<"Artist: "<<song.artist<<endl;
cout<<"Album: "<<song.album<<endl;
cout<<"Genre: "<<song.genre<<endl;
cout<<"Year: "<<song.year<<endl;
cout<<"Duration: "<<song.duration<<endl;
cout<<"Path: "<<song.songPath<<endl;
}
}
void Upload::printJsonData(const json& obj)
{
cout<<endl<<endl<<"JSon data: "<<endl;
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 endregion
#pragma endregion
cout << r.status_code<< std::endl;
}
catch (exception e)
{
auto msg = e.what();
cout<<msg<<endl;
}
cout<<"Finished"<<endl;
}
string Upload::retrieveUrl()
{
string url = api.url + "api/" + api.version + "/" +
api.endpoint;
return url;
}
#pragma
void Upload::configureSongDemo()
{
int id = 0;
string title = "What of it?";
string artist = "Kuoth";
string album = "I";
string genre = "Untitled";
int year = 2019;
int duration = 260;
this->song = Models::Song{};
this->song.id = id;
this->song.title = title;
this->song.artist = artist;
this->song.album = album;
this->song.genre = genre;
this->song.year = year;
this->song.duration = duration;
this->song.songData = fMgr.retrieveFileBuffer();
cout<<*song.songData<<endl;
}
void Upload::printSongDetails()
{
cout<<"Song details: "<<endl;
cout<<"Id: "<<song.id<<endl;
cout<<"Title: "<<song.title<<endl;
cout<<"Artist: "<<song.artist<<endl;
cout<<"Album: "<<song.album<<endl;
cout<<"Genre: "<<song.genre<<endl;
cout<<"Year: "<<song.year<<endl;
cout<<"Duration: "<<song.duration<<endl;
}
void Upload::printJsonData(json obj)
{
cout<<endl<<endl<<"JSon data: "<<endl;
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;;
}
json Upload::serializeObject()
{
json jObj{};
jObj["id"] = song.id;
jObj["title"] = song.title;
jObj["artist"] = song.artist;
jObj["album"] = song.album;
jObj["genre"] = song.genre;
jObj["year"] = song.year;
jObj["duration"] = song.duration;
jObj["song_data"] = *song.songData;
return jObj;
}
#pragma Testing
#pragma Functions
}
-47
View File
@@ -1,47 +0,0 @@
#ifndef UPLOAD_H_
#define UPLOAD_H_
#include<string>
#include<nlohmann/json.hpp>
#include"Managers/FileManager.h"
#include"Models/API.h"
#include"Models/Song.h"
#include"Models/Token.h"
#include"Models/UploadForm.h"
namespace Syncers
{
class Upload
{
public:
Upload();
Upload(std::string);
Upload(Models::API);
Upload(Models::UploadForm);
void uploadSong();
void uploadSong(const Models::Token, Models::Song);
private:
Managers::FileManager fMgr;
Models::API api;
Models::Song song;
std::string apiUrl{""}; // Not being used
std::string apiEndPoint{""}; // Not being used
std::string songPath; // Not being used
std::string url; // Not being used
int port{9349}; // Not being used
std::string retrieveUrl();
void configureSongDemo();
void printSongDetails();
void printJsonData(nlohmann::json);
nlohmann::json serializeObject(); // Not being used
};
}
#endif
+46 -41
View File
@@ -1,47 +1,52 @@
#include"AboutWindow.h"
#include "UI/AboutWindow.h"
using std::unique_ptr;
namespace UI
{
AboutWindow::AboutWindow(QWidget* parent): QDialog(parent)
{
setupWindow();
}
void AboutWindow::setupWindow()
{
windowWidth = 250;
windowHeight = 300;
mainLayoutQt = unique_ptr<QVBoxLayout>{new QVBoxLayout};
appName = unique_ptr<QLabel>{new QLabel(tr("IcarusDownloadManager"))};
actionButtonQt = unique_ptr<QPushButton>{new QPushButton(tr("Close"))};
mainLayoutQt->addWidget(appName.get());
mainLayoutQt->addWidget(actionButtonQt.get());
setFixedWidth(windowWidth);
setFixedHeight(windowHeight);
setLayout(mainLayoutQt.get());
setWindowTitle("About");
connections();
}
void AboutWindow::connections()
{
QObject::connect(actionButtonQt.get(), SIGNAL(clicked()), this,
SLOT(closeWindow()));
}
void AboutWindow::closeWindow()
{
this->hide();
}
#pragma region Constructors
AboutWindow::AboutWindow(QWidget* parent): QDialog(parent)
{
setupWindow();
}
#pragma endregion
#pragma region Functions
void AboutWindow::setupWindow()
{
windowWidth = 250;
windowHeight = 300;
mainLayoutQt = unique_ptr<QVBoxLayout>{new QVBoxLayout};
appName = unique_ptr<QLabel>{new QLabel(tr("IcarusDownloadManager"))};
actionButtonQt = unique_ptr<QPushButton>{new QPushButton(tr("Close"))};
mainLayoutQt->addWidget(appName.get());
mainLayoutQt->addWidget(actionButtonQt.get());
setFixedWidth(windowWidth);
setFixedHeight(windowHeight);
setLayout(mainLayoutQt.get());
setWindowTitle("About");
connections();
}
void AboutWindow::connections()
{
QObject::connect(actionButtonQt.get(), SIGNAL(clicked()), this,
SLOT(closeWindow()));
}
void AboutWindow::closeWindow()
{
this->hide();
}
#pragma endregion
}
-34
View File
@@ -1,34 +0,0 @@
#ifndef ABOUTWINDOW_H_
#define ABOUTWINDOW_H_
#include<memory>
#include<QDialog>
#include<QDockWidget>
#include<QLabel>
#include<QPushButton>
#include<QWidget>
#include"UI/CommonWindow.h"
namespace UI
{
class AboutWindow: public QDialog, public CommonWindow
{
Q_OBJECT
public:
AboutWindow(QWidget* parent=0);
~AboutWindow() = default;
private:
void connections();
void setupWindow();
std::unique_ptr<QLabel> appName;
private slots:
void closeWindow();
};
}
#endif
-27
View File
@@ -1,27 +0,0 @@
#ifndef COMMONWINDOW_H_
#define COMMONWINDOW_H_
#include<memory>
#include<QDialog>
#include<QHBoxLayout>
#include<QVBoxLayout>
#include<QComboBox>
#include<QPushButton>
class CommonWindow
{
public:
CommonWindow() = default;
~CommonWindow() = default;
protected:
virtual void connections()=0;
std::unique_ptr<QComboBox> selectionBoxQt;
std::unique_ptr<QPushButton> actionButtonQt;
std::unique_ptr<QVBoxLayout> mainLayoutQt;
std::unique_ptr<QVBoxLayout> subLayoutOneQt;
std::unique_ptr<QVBoxLayout> subLayoutTwoQt;
int windowHeight, windowWidth;
};
#endif
+165 -159
View File
@@ -1,11 +1,11 @@
#include"MainWindow.h"
#include "UI/MainWindow.h"
#include<iostream>
#include<string>
#include <iostream>
#include <string>
#include"Models/UploadForm.h"
#include"Syncers/Upload.h"
#include"Utilities/Conversions.h"
#include "Models/UploadForm.h"
#include "Syncers/Upload.h"
#include "Utilities/Conversions.h"
using std::cout;
using std::endl;
@@ -17,158 +17,164 @@ using Syncers::Upload;
namespace UI
{
MainWindow::MainWindow()
{
setupMainWindow();
aboutWindow = unique_ptr<AboutWindow>{new AboutWindow};
}
void MainWindow::configureDownloadSection()
{
}
void MainWindow::configureUploadSection()
{
uploadSongQt = unique_ptr<QPushButton>{new QPushButton(tr("Upload"))};
urlQt = unique_ptr<QTextEdit>{new QTextEdit()};
sourceFilePathQt = unique_ptr<QTextEdit>{new QTextEdit()};
urlLabel = unique_ptr<QLabel>{new QLabel(tr("URL"))};
songPath = unique_ptr<QLabel>{new QLabel(tr("Song Path"))};
urlPortion = unique_ptr<QHBoxLayout>{new QHBoxLayout};
songPathPortion = unique_ptr<QHBoxLayout>{new QHBoxLayout};
urlPortion.get()->addWidget(urlLabel.get());
urlPortion.get()->addWidget(urlQt.get());
songPathPortion->addWidget(songPath.get());
songPathPortion->addWidget(sourceFilePathQt.get());
subLayoutOneQt = unique_ptr<QVBoxLayout>{new QVBoxLayout};
subLayoutOneQt.get()->addLayout(urlPortion.get());
subLayoutOneQt->addLayout(songPathPortion.get());
mainLayoutQt.get()->addLayout(subLayoutOneQt.get());
}
void MainWindow::configureWindowDimensions()
{
windowWidth = 450;
windowHeight = 450;
}
void MainWindow::configureWindowProperties()
{
setWindowTitle("IcarusDownloadManager");
setFixedHeight(windowHeight);
setFixedWidth(windowWidth);
}
void MainWindow::connections()
{
QObject::connect(uploadSongQt.get(), SIGNAL(clicked()), this, SLOT(uploadSong()));
QObject::connect(closeApplicationQt.get(), SIGNAL(triggered()), this,
SLOT(exitApplication()));
QObject::connect(aboutApplicationQt.get(), SIGNAL(triggered()), this,
SLOT(displaySoftwareInformation()));
QObject::connect(windowComboBox.get(), SIGNAL(activated(int)),
this, SLOT(setCurrentIndex(int)));
}
void MainWindow::createMenus()
{
fileMenuQt = unique_ptr<QMenu>{menuBar()->addMenu(tr("File"))};
editMenuQt = unique_ptr<QMenu>{menuBar()->addMenu(tr("Edit"))};
helpMenuQt = unique_ptr<QMenu>{menuBar()->addMenu(tr("Help"))};
closeApplicationQt = unique_ptr<QAction>{new QAction(new QObject(nullptr))};
closeApplicationQt->setText("Exit Application");
aboutApplicationQt = unique_ptr<QAction>{new QAction(new QObject(nullptr))};
aboutApplicationQt->setText("About");
fileMenuQt->addAction(closeApplicationQt.get());
helpMenuQt->addAction(aboutApplicationQt.get());
}
void MainWindow::setupMainWidget()
{
mainWidgetQt = unique_ptr<QWidget>{new QWidget};
windowComboBox = unique_ptr<QComboBox>{new QComboBox};
setupWindowLists();
stackLayout = unique_ptr<QVBoxLayout>{new QVBoxLayout};
stackLayout->addWidget(windowComboBox.get());
uploadSongWidgetQt = unique_ptr<QWidget>{new QWidget};
uploadSongWidgetQt->setLayout(mainLayoutQt.get());
stackLayout->addWidget(uploadSongWidgetQt.get());
mainWidgetQt->setLayout(stackLayout.get());
}
void MainWindow::setupMainWindow()
{
configureWindowDimensions();
mainLayoutQt = unique_ptr<QVBoxLayout>{new QVBoxLayout};
widgetStack = unique_ptr<QStackedWidget>{new QStackedWidget};
configureUploadSection();
setupMainWidget();
widgetStack->addWidget(mainWidgetQt.get());
MainDockWidgetQt = unique_ptr<QDockWidget>{new QDockWidget};
MainDockWidgetQt.get()->setWindowTitle(tr("Music Manager"));
MainDockWidgetQt->setWidget(widgetStack.get());
MainDockWidgetQt.get()->setFeatures(QDockWidget::NoDockWidgetFeatures);
setCentralWidget(MainDockWidgetQt.get());
createMenus();
configureWindowProperties();
connections();
}
void MainWindow::setupWindowLists()
{
windowComboBox->addItem(tr("Upload song"));
windowComboBox->addItem(tr("Download song"));
windowComboBox->addItem(tr("Display all songs"));
windowComboBox->addItem(tr("Display songs"));
}
void MainWindow::exitApplication()
{
exit(0);
}
void MainWindow::displaySoftwareInformation()
{
aboutWindow->show();
}
void MainWindow::setCurrentIndex(int index)
{
cout<<"index "<<index<<endl;
QString qText = windowComboBox->itemText(index);
auto cnvert = Utilities::Conversions(qText);
auto convertedStr = cnvert.convertQStringToString();
cout<<"item text"<<endl;
}
void MainWindow::uploadSong()
{
uploadSongQt->setEnabled(false);
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 region Constructors
MainWindow::MainWindow()
{
setupMainWindow();
aboutWindow = unique_ptr<AboutWindow>{new AboutWindow};
}
#pragma endregion
#pragma region Functions
void MainWindow::configureDownloadSection()
{
}
void MainWindow::configureUploadSection()
{
uploadSongQt = unique_ptr<QPushButton>{new QPushButton(tr("Upload"))};
urlQt = unique_ptr<QTextEdit>{new QTextEdit()};
sourceFilePathQt = unique_ptr<QTextEdit>{new QTextEdit()};
urlLabel = unique_ptr<QLabel>{new QLabel(tr("URL"))};
songPath = unique_ptr<QLabel>{new QLabel(tr("Song Path"))};
urlPortion = unique_ptr<QHBoxLayout>{new QHBoxLayout};
songPathPortion = unique_ptr<QHBoxLayout>{new QHBoxLayout};
urlPortion.get()->addWidget(urlLabel.get());
urlPortion.get()->addWidget(urlQt.get());
songPathPortion->addWidget(songPath.get());
songPathPortion->addWidget(sourceFilePathQt.get());
subLayoutOneQt = unique_ptr<QVBoxLayout>{new QVBoxLayout};
subLayoutOneQt.get()->addLayout(urlPortion.get());
subLayoutOneQt->addLayout(songPathPortion.get());
mainLayoutQt.get()->addLayout(subLayoutOneQt.get());
}
void MainWindow::configureWindowDimensions()
{
windowWidth = 450;
windowHeight = 450;
}
void MainWindow::configureWindowProperties()
{
setWindowTitle("IcarusDownloadManager");
setFixedHeight(windowHeight);
setFixedWidth(windowWidth);
}
void MainWindow::connections()
{
QObject::connect(uploadSongQt.get(), SIGNAL(clicked()), this, SLOT(uploadSong()));
QObject::connect(closeApplicationQt.get(), SIGNAL(triggered()), this,
SLOT(exitApplication()));
QObject::connect(aboutApplicationQt.get(), SIGNAL(triggered()), this,
SLOT(displaySoftwareInformation()));
QObject::connect(windowComboBox.get(), SIGNAL(activated(int)),
this, SLOT(setCurrentIndex(int)));
}
void MainWindow::createMenus()
{
fileMenuQt = unique_ptr<QMenu>{menuBar()->addMenu(tr("File"))};
editMenuQt = unique_ptr<QMenu>{menuBar()->addMenu(tr("Edit"))};
helpMenuQt = unique_ptr<QMenu>{menuBar()->addMenu(tr("Help"))};
closeApplicationQt = unique_ptr<QAction>{new QAction(new QObject(nullptr))};
closeApplicationQt->setText("Exit Application");
aboutApplicationQt = unique_ptr<QAction>{new QAction(new QObject(nullptr))};
aboutApplicationQt->setText("About");
fileMenuQt->addAction(closeApplicationQt.get());
helpMenuQt->addAction(aboutApplicationQt.get());
}
void MainWindow::setupMainWidget()
{
mainWidgetQt = unique_ptr<QWidget>{new QWidget};
windowComboBox = unique_ptr<QComboBox>{new QComboBox};
setupWindowLists();
stackLayout = unique_ptr<QVBoxLayout>{new QVBoxLayout};
stackLayout->addWidget(windowComboBox.get());
uploadSongWidgetQt = unique_ptr<QWidget>{new QWidget};
uploadSongWidgetQt->setLayout(mainLayoutQt.get());
stackLayout->addWidget(uploadSongWidgetQt.get());
mainWidgetQt->setLayout(stackLayout.get());
}
void MainWindow::setupMainWindow()
{
configureWindowDimensions();
mainLayoutQt = unique_ptr<QVBoxLayout>{new QVBoxLayout};
widgetStack = unique_ptr<QStackedWidget>{new QStackedWidget};
configureUploadSection();
setupMainWidget();
widgetStack->addWidget(mainWidgetQt.get());
MainDockWidgetQt = unique_ptr<QDockWidget>{new QDockWidget};
MainDockWidgetQt.get()->setWindowTitle(tr("Music Manager"));
MainDockWidgetQt->setWidget(widgetStack.get());
MainDockWidgetQt.get()->setFeatures(QDockWidget::NoDockWidgetFeatures);
setCentralWidget(MainDockWidgetQt.get());
createMenus();
configureWindowProperties();
connections();
}
void MainWindow::setupWindowLists()
{
windowComboBox->addItem(tr("Upload song"));
windowComboBox->addItem(tr("Download song"));
windowComboBox->addItem(tr("Display all songs"));
windowComboBox->addItem(tr("Display songs"));
}
void MainWindow::exitApplication()
{
exit(0);
}
void MainWindow::displaySoftwareInformation()
{
aboutWindow->show();
}
void MainWindow::setCurrentIndex(int index)
{
cout<<"index "<<index<<endl;
QString qText = windowComboBox->itemText(index);
auto cnvert = Utilities::Conversions(qText);
auto convertedStr = cnvert.convertQStringToString();
cout<<"item text"<<endl;
}
void MainWindow::uploadSong()
{
uploadSongQt->setEnabled(false);
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
}
-82
View File
@@ -1,82 +0,0 @@
#ifndef MAINWINDOW_H_
#define MAINWINDOW_H_
#include<iostream>
#include<memory>
#include<QAction>
#include<QComboBox>
#include<QDialog>
#include<QDockWidget>
#include<QLabel>
#include<QMenu>
#include<QMenuBar>
#include<QMainWindow>
#include<QPushButton>
#include<QStackedWidget>
#include<QTextEdit>
#include<QWidget>
#include"UI/CommonWindow.h"
#include"UI/AboutWindow.h"
namespace UI
{
class MainWindow: public QMainWindow, public CommonWindow
{
Q_OBJECT
public:
MainWindow();
~MainWindow() = default;
private:
void configureDownloadSection();
void configureUploadSection();
void configureWindowDimensions();
void configureWindowProperties();
void connections();
void createMenus();
void setupMainWidget();
void setupMainWindow();
void setupWindowLists();
std::unique_ptr<QStackedWidget> widgetStack;
std::unique_ptr<QVBoxLayout> stackLayout;
std::unique_ptr<QHBoxLayout> urlPortion;
std::unique_ptr<QHBoxLayout> songPathPortion;
std::unique_ptr<QWidget> mainWidgetQt;
std::unique_ptr<QWidget> uploadSongWidgetQt;
std::unique_ptr<QDockWidget> MainDockWidgetQt;
std::unique_ptr<QComboBox> windowComboBox;
std::unique_ptr<QPushButton> uploadSongQt;
std::unique_ptr<QTextEdit> urlQt;
std::unique_ptr<QTextEdit> sourceFilePathQt;
std::unique_ptr<QLabel> urlLabel;
std::unique_ptr<QLabel> songPath;
std::unique_ptr<QMenu> fileMenuQt;
std::unique_ptr<QMenu> editMenuQt;
std::unique_ptr<QMenu> helpMenuQt;
std::unique_ptr<QAction> closeApplicationQt;
std::unique_ptr<QAction> aboutApplicationQt;
std::unique_ptr<AboutWindow> aboutWindow;
signals:
private slots:
void uploadSong();
void exitApplication();
void displaySoftwareInformation();
void setCurrentIndex(int);
};
}
#endif
+17 -15
View File
@@ -1,24 +1,26 @@
#include"Conversions.h"
#include "Utilities/Conversions.h"
#include<iostream>
#include <iostream>
using std::string;
using std::unique_ptr;
namespace Utilities
{
Conversions::Conversions()
{
initializeValues();
}
void Conversions::initializeValues()
{
}
template <typename T>
void Conversions::printValue(T val)
{
std::cout<<"going to print value"<<std::endl;
std::cout<<val<<std::endl;
}
Conversions::Conversions()
{
initializeValues();
}
void Conversions::initializeValues()
{
}
template <typename T>
void Conversions::printValue(T val)
{
std::cout<<"going to print value\n";
std::cout<<val<< "\n";
}
}
-22
View File
@@ -1,22 +0,0 @@
#ifndef CONVERSIONS_H_
#define CONVERSIONS_H_
#include<memory>
#include<string>
namespace Utilities
{
class Conversions
{
public:
Conversions();
void initializeValues();
template <typename T>
void printValue(T);
private:
};
}
#endif