first commit
This commit is contained in:
commit
0b15394d5d
27 changed files with 23984 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
build/
|
||||||
|
cmake-build-debug/
|
||||||
|
cmake/
|
2
.idea/Eliya.iml
Normal file
2
.idea/Eliya.iml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
7
.idea/misc.xml
Normal file
7
.idea/misc.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="ES6" />
|
||||||
|
</component>
|
||||||
|
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/Eliya.iml" filepath="$PROJECT_DIR$/.idea/Eliya.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
151
.idea/workspace.xml
Normal file
151
.idea/workspace.xml
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CMakeRunConfigurationManager" shouldGenerate="true" shouldDeleteObsolete="true">
|
||||||
|
<generated>
|
||||||
|
<config projectName="Eliya" targetName="Eliya" />
|
||||||
|
</generated>
|
||||||
|
</component>
|
||||||
|
<component name="CMakeSettings" AUTO_RELOAD="true">
|
||||||
|
<configurations>
|
||||||
|
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" />
|
||||||
|
</configurations>
|
||||||
|
</component>
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="87f1c914-4d46-4c1a-9e29-30eb4356db3e" name="Default Changelist" comment="" />
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="ClangdSettings">
|
||||||
|
<option name="formatViaClangd" value="false" />
|
||||||
|
</component>
|
||||||
|
<component name="ExecutionTargetManager" SELECTED_TARGET="CMakeBuildProfile:Debug" />
|
||||||
|
<component name="ProjectId" id="1YAFiGju36yXjkmzf3LxUY6eROH" />
|
||||||
|
<component name="ProjectViewState">
|
||||||
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
|
<option name="showExcludedFiles" value="true" />
|
||||||
|
<option name="showLibraryContents" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent">
|
||||||
|
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
|
||||||
|
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||||
|
<property name="settings.editor.selected.configurable" value="preferences.lookFeel" />
|
||||||
|
</component>
|
||||||
|
<component name="RecentsManager">
|
||||||
|
<key name="MoveFile.RECENT_KEYS">
|
||||||
|
<recent name="$PROJECT_DIR$/cmake" />
|
||||||
|
<recent name="$PROJECT_DIR$/src" />
|
||||||
|
</key>
|
||||||
|
</component>
|
||||||
|
<component name="RunManager">
|
||||||
|
<configuration name="Eliya" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="--files="/mnt/nas/Bootleg/"" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Eliya" TARGET_NAME="Eliya" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Eliya" RUN_TARGET_NAME="Eliya">
|
||||||
|
<method v="2">
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
|
<component name="SvnConfiguration">
|
||||||
|
<configuration />
|
||||||
|
</component>
|
||||||
|
<component name="TaskManager">
|
||||||
|
<task active="true" id="Default" summary="Default task">
|
||||||
|
<changelist id="87f1c914-4d46-4c1a-9e29-30eb4356db3e" name="Default Changelist" comment="" />
|
||||||
|
<created>1582377616132</created>
|
||||||
|
<option name="number" value="Default" />
|
||||||
|
<option name="presentableId" value="Default" />
|
||||||
|
<updated>1582377616132</updated>
|
||||||
|
<workItem from="1582377618031" duration="22316000" />
|
||||||
|
<workItem from="1582452152884" duration="8183000" />
|
||||||
|
<workItem from="1582551176378" duration="21273000" />
|
||||||
|
<workItem from="1582908123245" duration="33000" />
|
||||||
|
<workItem from="1583009998226" duration="6755000" />
|
||||||
|
<workItem from="1583055740209" duration="1581000" />
|
||||||
|
</task>
|
||||||
|
<servers />
|
||||||
|
</component>
|
||||||
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
<option name="version" value="1" />
|
||||||
|
</component>
|
||||||
|
<component name="WindowStateProjectService">
|
||||||
|
<state x="1251" y="400" key="#com.intellij.execution.impl.EditConfigurationsDialog" timestamp="1583011913205">
|
||||||
|
<screen x="0" y="0" width="2560" height="1408" />
|
||||||
|
</state>
|
||||||
|
<state x="738" y="354" key="#com.intellij.execution.impl.EditConfigurationsDialog/0.0.2560.1408/2560.0.2560.1440@0.0.2560.1408" timestamp="1582396273706" />
|
||||||
|
<state x="1251" y="400" key="#com.intellij.execution.impl.EditConfigurationsDialog/0.0.2560.1408/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583011913205" />
|
||||||
|
<state x="3648" y="423" width="374" height="568" key="#com.intellij.ide.util.MemberChooser" timestamp="1582459657179">
|
||||||
|
<screen x="2560" y="0" width="2560" height="1440" />
|
||||||
|
</state>
|
||||||
|
<state x="3648" y="423" width="374" height="568" key="#com.intellij.ide.util.MemberChooser/0.0.2560.1408/2560.0.2560.1440@2560.0.2560.1440" timestamp="1582459657179" />
|
||||||
|
<state width="2510" height="408" key="GridCell.Tab.0.bottom" timestamp="1583016802112">
|
||||||
|
<screen x="2560" y="0" width="2560" height="1440" />
|
||||||
|
</state>
|
||||||
|
<state width="2510" height="482" key="GridCell.Tab.0.bottom/0.0.2560.1408/2560.0.2560.1440@0.0.2560.1408" timestamp="1582398707113" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.0.bottom/0.0.2560.1408/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583013554049" />
|
||||||
|
<state width="2510" height="408" key="GridCell.Tab.0.bottom/0.0.2560.1440/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583016802112" />
|
||||||
|
<state width="2510" height="408" key="GridCell.Tab.0.center" timestamp="1583016802112">
|
||||||
|
<screen x="2560" y="0" width="2560" height="1440" />
|
||||||
|
</state>
|
||||||
|
<state width="2510" height="482" key="GridCell.Tab.0.center/0.0.2560.1408/2560.0.2560.1440@0.0.2560.1408" timestamp="1582398707113" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.0.center/0.0.2560.1408/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583013554049" />
|
||||||
|
<state width="2510" height="408" key="GridCell.Tab.0.center/0.0.2560.1440/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583016802112" />
|
||||||
|
<state width="2510" height="408" key="GridCell.Tab.0.left" timestamp="1583016802112">
|
||||||
|
<screen x="2560" y="0" width="2560" height="1440" />
|
||||||
|
</state>
|
||||||
|
<state width="2510" height="482" key="GridCell.Tab.0.left/0.0.2560.1408/2560.0.2560.1440@0.0.2560.1408" timestamp="1582398707113" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.0.left/0.0.2560.1408/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583013554049" />
|
||||||
|
<state width="2510" height="408" key="GridCell.Tab.0.left/0.0.2560.1440/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583016802112" />
|
||||||
|
<state width="2510" height="408" key="GridCell.Tab.0.right" timestamp="1583016802112">
|
||||||
|
<screen x="2560" y="0" width="2560" height="1440" />
|
||||||
|
</state>
|
||||||
|
<state width="2510" height="482" key="GridCell.Tab.0.right/0.0.2560.1408/2560.0.2560.1440@0.0.2560.1408" timestamp="1582398707113" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.0.right/0.0.2560.1408/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583013554049" />
|
||||||
|
<state width="2510" height="408" key="GridCell.Tab.0.right/0.0.2560.1440/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583016802112" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.1.bottom" timestamp="1583016802110">
|
||||||
|
<screen x="2560" y="0" width="2560" height="1440" />
|
||||||
|
</state>
|
||||||
|
<state width="2510" height="453" key="GridCell.Tab.1.bottom/0.0.2560.1408/2560.0.2560.1440@0.0.2560.1408" timestamp="1582398641044" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.1.bottom/0.0.2560.1408/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583013554049" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.1.bottom/0.0.2560.1440/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583016802110" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.1.center" timestamp="1583016802110">
|
||||||
|
<screen x="2560" y="0" width="2560" height="1440" />
|
||||||
|
</state>
|
||||||
|
<state width="2510" height="453" key="GridCell.Tab.1.center/0.0.2560.1408/2560.0.2560.1440@0.0.2560.1408" timestamp="1582398641043" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.1.center/0.0.2560.1408/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583013554049" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.1.center/0.0.2560.1440/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583016802110" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.1.left" timestamp="1583016802110">
|
||||||
|
<screen x="2560" y="0" width="2560" height="1440" />
|
||||||
|
</state>
|
||||||
|
<state width="2510" height="453" key="GridCell.Tab.1.left/0.0.2560.1408/2560.0.2560.1440@0.0.2560.1408" timestamp="1582398641043" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.1.left/0.0.2560.1408/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583013554049" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.1.left/0.0.2560.1440/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583016802110" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.1.right" timestamp="1583016802110">
|
||||||
|
<screen x="2560" y="0" width="2560" height="1440" />
|
||||||
|
</state>
|
||||||
|
<state width="2510" height="453" key="GridCell.Tab.1.right/0.0.2560.1408/2560.0.2560.1440@0.0.2560.1408" timestamp="1582398641044" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.1.right/0.0.2560.1408/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583013554049" />
|
||||||
|
<state width="2510" height="692" key="GridCell.Tab.1.right/0.0.2560.1440/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583016802110" />
|
||||||
|
<state x="3321" y="339" width="1037" height="736" key="SettingsEditor" timestamp="1582384592156">
|
||||||
|
<screen x="2560" y="0" width="2560" height="1440" />
|
||||||
|
</state>
|
||||||
|
<state x="3321" y="339" width="1037" height="736" key="SettingsEditor/0.0.2560.1408/2560.0.2560.1440@2560.0.2560.1440" timestamp="1582384592156" />
|
||||||
|
<state x="3493" y="308" width="683" height="812" key="com.intellij.openapi.editor.actions.MultiplePasteAction$ClipboardContentChooser" timestamp="1582562732167">
|
||||||
|
<screen x="2560" y="0" width="2560" height="1440" />
|
||||||
|
</state>
|
||||||
|
<state x="933" y="301" width="683" height="812" key="com.intellij.openapi.editor.actions.MultiplePasteAction$ClipboardContentChooser/0.0.2560.1408/2560.0.2560.1440@0.0.2560.1408" timestamp="1582391546963" />
|
||||||
|
<state x="3493" y="308" key="com.intellij.openapi.editor.actions.MultiplePasteAction$ClipboardContentChooser/0.0.2560.1408/2560.0.2560.1440@2560.0.2560.1440" timestamp="1582562732167" />
|
||||||
|
<state x="3487" y="384" width="705" height="640" key="find.popup" timestamp="1583013464055">
|
||||||
|
<screen x="2560" y="0" width="2560" height="1440" />
|
||||||
|
</state>
|
||||||
|
<state x="3487" y="384" width="705" height="640" key="find.popup/0.0.2560.1408/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583013464055" />
|
||||||
|
<state x="3556" y="339" width="558" height="735" key="refactoring.ChangeSignatureDialog" timestamp="1583011117198">
|
||||||
|
<screen x="2560" y="0" width="2560" height="1440" />
|
||||||
|
</state>
|
||||||
|
<state x="3556" y="339" width="558" height="735" key="refactoring.ChangeSignatureDialog/0.0.2560.1408/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583011117198" />
|
||||||
|
<state x="3503" y="321" width="672" height="678" key="search.everywhere.popup" timestamp="1583014420663">
|
||||||
|
<screen x="2560" y="0" width="2560" height="1440" />
|
||||||
|
</state>
|
||||||
|
<state x="943" y="314" width="672" height="663" key="search.everywhere.popup/0.0.2560.1408/2560.0.2560.1440@0.0.2560.1408" timestamp="1582398628799" />
|
||||||
|
<state x="3503" y="321" width="672" height="678" key="search.everywhere.popup/0.0.2560.1408/2560.0.2560.1440@2560.0.2560.1440" timestamp="1583014420663" />
|
||||||
|
</component>
|
||||||
|
</project>
|
12
CMakeLists.txt
Normal file
12
CMakeLists.txt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
project(Eliya VERSION 1.0)
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${ECM_MODULE_PATH})
|
||||||
|
|
||||||
|
FILE(GLOB_RECURSE SRC "src/**/*.cpp" "src/**/*.h")
|
||||||
|
add_executable(Eliya src/main.cpp lib/json.hpp ${SRC})
|
||||||
|
find_package(TagLib REQUIRED)
|
||||||
|
find_package (Threads)
|
||||||
|
target_include_directories(Eliya PRIVATE ${TAGLIB_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(Eliya ${TAGLIB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
37
backup.txt
Normal file
37
backup.txt
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
for (const auto &entry : fs::recursive_directory_iterator(inputDir, fs::directory_options::skip_permission_denied)) {
|
||||||
|
auto file = entry.path().string();
|
||||||
|
// doesnt need audio properties here
|
||||||
|
auto tagFile = TagLib::FileRef(file.c_str(), false);
|
||||||
|
if (!tagFile.isNull()) {
|
||||||
|
TagLib::MPEG::File f(file.c_str());
|
||||||
|
if (f.isValid()) {
|
||||||
|
TagLib::ID3v2::Tag *id3v2tag = f.ID3v2Tag();
|
||||||
|
if (id3v2tag) {
|
||||||
|
auto listOfFrames = id3v2tag->frameListMap()["APIC"];
|
||||||
|
if (!listOfFrames.isEmpty()) {
|
||||||
|
//hold here for debugger ;)
|
||||||
|
auto it = listOfFrames.begin();
|
||||||
|
for (; it != listOfFrames.end(); it++) {
|
||||||
|
auto *pictureFrame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame *> (*it);
|
||||||
|
/* {
|
||||||
|
FILE *jpegFile;
|
||||||
|
jpegFile = fopen("/home/versustune/FromId3.jpg", "wb");
|
||||||
|
unsigned long Size = pictureFrame->picture().size();
|
||||||
|
void *SrcImage = malloc(Size);
|
||||||
|
if (SrcImage) {
|
||||||
|
memcpy(SrcImage, pictureFrame->picture().data(), Size);
|
||||||
|
fwrite(SrcImage, Size, 1, jpegFile);
|
||||||
|
fclose(jpegFile);
|
||||||
|
free(SrcImage);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "no ID3v2 \n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "is not Mpeg!" << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22875
lib/json.hpp
Normal file
22875
lib/json.hpp
Normal file
File diff suppressed because it is too large
Load diff
60
src/Core/Arguments.cpp
Normal file
60
src/Core/Arguments.cpp
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 22.02.20.
|
||||||
|
//
|
||||||
|
#include "Arguments.h"
|
||||||
|
#include <cstring>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PUBLIC ONES
|
||||||
|
*/
|
||||||
|
Arguments::Arguments(int argc, std::vector<std::string> args) {
|
||||||
|
count = argc;
|
||||||
|
Arguments::args = std::move(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
Arguments::~Arguments() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Arguments::parseArgs() {
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
//always skip the first :)
|
||||||
|
if (i == 0)
|
||||||
|
continue;
|
||||||
|
std::string string = std::string(args[i]);
|
||||||
|
//if argument doesnt start with -- it's invalid!
|
||||||
|
if (string.find("--", 0) != 0)
|
||||||
|
continue;
|
||||||
|
string = string.replace(0, 2, "");
|
||||||
|
auto pos = string.find('=', 0);
|
||||||
|
if (pos != 0 && pos < string.size()) {
|
||||||
|
std::string token = string.substr(0, pos);
|
||||||
|
parsedArgs[token] = string.substr(pos + 1, string.back());
|
||||||
|
} else {
|
||||||
|
parsedArgs[string] = "true";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Arguments::getArg(const std::string &key) {
|
||||||
|
if (parsedArgs.find(key) == parsedArgs.end()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return parsedArgs[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Arguments::getArgOrDefault(const std::string &key, std::string fallback) {
|
||||||
|
if (parsedArgs.find(key) == parsedArgs.end()) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
return parsedArgs[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::unordered_map<std::string, std::string> &Arguments::getParsedArgs() {
|
||||||
|
return parsedArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PROTECTED ONES
|
||||||
|
*/
|
29
src/Core/Arguments.h
Normal file
29
src/Core/Arguments.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 22.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ELIYA_ARGUMENTS_H
|
||||||
|
#define ELIYA_ARGUMENTS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Arguments {
|
||||||
|
private:
|
||||||
|
std::unordered_map<std::string, std::string> parsedArgs;
|
||||||
|
int count = 0;
|
||||||
|
std::vector<std::string> args;
|
||||||
|
public:
|
||||||
|
Arguments(int argc, std::vector<std::string> args);
|
||||||
|
~Arguments();
|
||||||
|
//pureRead args with this format: --key=args or --debug if "--" not defined it's says failed and skip it.. so make sure it's provided
|
||||||
|
void parseArgs();
|
||||||
|
std::string getArg(const std::string &key);
|
||||||
|
std::string getArgOrDefault(const std::string &key, std::string fallback);
|
||||||
|
const std::unordered_map<std::string, std::string> &getParsedArgs();
|
||||||
|
protected:
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ELIYA_ARGUMENTS_H
|
29
src/Core/Logo.h
Normal file
29
src/Core/Logo.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 22.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ELIYA_LOGO_H
|
||||||
|
#define ELIYA_LOGO_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
class EliyaLogo {
|
||||||
|
private:
|
||||||
|
static std::string logo;
|
||||||
|
public:
|
||||||
|
EliyaLogo() {}
|
||||||
|
|
||||||
|
static void draw() {
|
||||||
|
std::cout << "\033[1;36m" << logo << "\033[0m\n\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string EliyaLogo::logo = "U _____ u _ __ __ _ \n"
|
||||||
|
"\\| ___\"|/ |\"| ___ \\ \\ / /U /\"\\ u \n"
|
||||||
|
" | _|\" U | | u |_\"_| \\ V / \\/ _ \\/ \n"
|
||||||
|
" | |___ \\| |/__ | | U_|\"|_u / ___ \\ \n"
|
||||||
|
" |_____| |_____| U/| |\\u |_| /_/ \\_\\ \n"
|
||||||
|
" << >> // \\\\.-,_|___|_,-.-,//|(_ \\\\ >> \n"
|
||||||
|
"(__) (__)(_\")(\"_)\\_)-' '-(_/ \\_) (__)(__) (__) ";
|
||||||
|
#endif //ELIYA_LOGO_H
|
5
src/Models/AudioFile.cpp
Normal file
5
src/Models/AudioFile.cpp
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 22.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AudioFile.h"
|
34
src/Models/AudioFile.h
Normal file
34
src/Models/AudioFile.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 22.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ELIYA_AUDIOFILE_H
|
||||||
|
#define ELIYA_AUDIOFILE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class AudioFile {
|
||||||
|
public:
|
||||||
|
AudioFile() = default;
|
||||||
|
~AudioFile() = default;
|
||||||
|
|
||||||
|
//properties
|
||||||
|
std::string path;
|
||||||
|
std::string title;
|
||||||
|
std::string artist;
|
||||||
|
std::string album;
|
||||||
|
std::string genre;
|
||||||
|
int year;
|
||||||
|
int track;
|
||||||
|
int length;
|
||||||
|
int bitrate;
|
||||||
|
int sampleRate;
|
||||||
|
int channels;
|
||||||
|
int bitsPerSample = -1; //not always available so -1 is empty
|
||||||
|
int samplesPerFrame = -1; // also not always available so set it to -1 that we know it's invalid ;)
|
||||||
|
bool isValid = false; //set to true if the audio file is valid
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ELIYA_AUDIOFILE_H
|
142
src/Reader/FileReader.cpp
Normal file
142
src/Reader/FileReader.cpp
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 22.02.20.
|
||||||
|
//
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <fstream>
|
||||||
|
#include <utility>
|
||||||
|
#include <zconf.h>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
#include "FileReader.h"
|
||||||
|
#include "../Utils/Logging.h"
|
||||||
|
#include "../Utils/Utils.h"
|
||||||
|
#include "../Utils/ProgressBar.h"
|
||||||
|
#include "ThreadPool.h"
|
||||||
|
|
||||||
|
#define FS_MODULE_NAME "FileReader"
|
||||||
|
|
||||||
|
FileReader::FileReader(std::string path, std::string outputPath) {
|
||||||
|
FileReader::path = std::move(path);
|
||||||
|
FileReader::outputPath = std::move(outputPath);
|
||||||
|
validateDirectories();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileReader::~FileReader() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<AudioFile *> &FileReader::getValidFiles() const {
|
||||||
|
return validFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
// here i want to iterate over all files recursive and save all valid files ;)
|
||||||
|
void FileReader::pureRead() {
|
||||||
|
auto *progressBar = getProgressBar("Read Files", -1);
|
||||||
|
progressBar->startThread();
|
||||||
|
for (const auto &entry : fs::recursive_directory_iterator(path, fs::directory_options::skip_permission_denied)) {
|
||||||
|
if (fs::is_directory(entry.path()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
//check if file is less then 2GB
|
||||||
|
if (entry.file_size() < 2147483648) {
|
||||||
|
files.push_back(entry.path());
|
||||||
|
}
|
||||||
|
} catch (fs::filesystem_error &error) {
|
||||||
|
//skip
|
||||||
|
}
|
||||||
|
progressBar->tick();
|
||||||
|
}
|
||||||
|
progressBar->setFinished(true);
|
||||||
|
while (!progressBar->isDone()) {
|
||||||
|
usleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileReader::validateDirectories() {
|
||||||
|
if (!fs::is_directory(path)) {
|
||||||
|
Logging::error("Input Path not Found", FS_MODULE_NAME);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!fs::is_directory(outputPath)) {
|
||||||
|
Logging::error("Output Path not Found. Creating? [Y/n]", FS_MODULE_NAME);
|
||||||
|
auto value = std::cin.get();
|
||||||
|
if (value == 110) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
fs::create_directory(outputPath);
|
||||||
|
if (!fs::is_directory(outputPath)) {
|
||||||
|
Logging::error("Cannot create Output Path", FS_MODULE_NAME);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cacheDir = outputPath + "/cache";
|
||||||
|
if (!fs::is_directory(cacheDir)) {
|
||||||
|
fs::create_directory(cacheDir);
|
||||||
|
if (!fs::is_directory(cacheDir)) {
|
||||||
|
Logging::error("Cannot create Cache Directory", FS_MODULE_NAME);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto finalDir = outputPath + "/final";
|
||||||
|
if (!fs::is_directory(finalDir)) {
|
||||||
|
fs::create_directory(outputPath + "/final");
|
||||||
|
if (!fs::is_directory(finalDir)) {
|
||||||
|
Logging::error("Cannot create final Directory", FS_MODULE_NAME);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this function write a json from all valid music files into the cache directory.
|
||||||
|
* here we go. we get all AudioFile and call the toJson function.
|
||||||
|
*/
|
||||||
|
void FileReader::writeToCache() {
|
||||||
|
auto cacheFile = outputPath + "/cache/" + cacheName;
|
||||||
|
std::ofstream outputFile;
|
||||||
|
outputFile.open(cacheFile);
|
||||||
|
if (!outputFile.is_open()) {
|
||||||
|
Logging::error("Cannot open cache File: \"" + cacheFile + "\"", FS_MODULE_NAME);
|
||||||
|
Logging::error("Writing Cache FAILED", FS_MODULE_NAME);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* filename: stringToHex(inputPath) + ".json"
|
||||||
|
*/
|
||||||
|
std::string FileReader::getCacheName() {
|
||||||
|
if (cacheName.empty()) {
|
||||||
|
std::string _cacheName = path;
|
||||||
|
_cacheName.erase(std::remove_if(_cacheName.begin(), _cacheName.end(), ::isspace), cacheName.end());
|
||||||
|
cacheName = Utils::stringToHex(_cacheName) + ".json";
|
||||||
|
}
|
||||||
|
return cacheName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileReader::readAudioFiles() {
|
||||||
|
auto *progressBar = getProgressBar("Validate Files", files.size());
|
||||||
|
auto threadPool = ThreadPool();
|
||||||
|
auto queue = new Tsqueue<std::shared_ptr<ThreadQueueItem>>();
|
||||||
|
for (int i = 0; i < files.size(); ++i) {
|
||||||
|
auto item = std::make_shared<ThreadQueueItem>();
|
||||||
|
item->fileIndex = i;
|
||||||
|
item->reader = this;
|
||||||
|
item->progressBar = progressBar;
|
||||||
|
queue->push(item);
|
||||||
|
}
|
||||||
|
progressBar->setMaxTicks(queue->getSize());
|
||||||
|
threadPool.setQueue(queue);
|
||||||
|
threadPool.start(progressBar);
|
||||||
|
progressBar->setFinished(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressBar *FileReader::getProgressBar(std::string name, int maxTicks) {
|
||||||
|
auto progressBar = new ProgressBar(std::move(name), maxTicks, 1);
|
||||||
|
std::thread progressBarThread(&ProgressBar::runInThread, progressBar);
|
||||||
|
progressBarThread.detach();
|
||||||
|
return progressBar;
|
||||||
|
}
|
49
src/Reader/FileReader.h
Normal file
49
src/Reader/FileReader.h
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 22.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ELIYA_FILEREADER_H
|
||||||
|
#define ELIYA_FILEREADER_H
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
#include "../Models/AudioFile.h"
|
||||||
|
#include "FileValidator.h"
|
||||||
|
#include "../Utils/ProgressBar.h"
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This class pureRead recursive from the disk and build and vector with all files.
|
||||||
|
*/
|
||||||
|
class FileReader {
|
||||||
|
private:
|
||||||
|
std::string path;
|
||||||
|
std::string outputPath;
|
||||||
|
std::string cacheName = "";
|
||||||
|
std::vector<AudioFile*> validFiles;
|
||||||
|
FileValidator validator;
|
||||||
|
public:
|
||||||
|
FileReader(std::string path, std::string outputPath);
|
||||||
|
|
||||||
|
~FileReader();
|
||||||
|
|
||||||
|
void pureRead();
|
||||||
|
|
||||||
|
void readAudioFiles();
|
||||||
|
|
||||||
|
const std::vector<AudioFile*> &getValidFiles() const;
|
||||||
|
std::vector<std::string> files; //clean after audioFile reading because can need alot of memory!
|
||||||
|
std::vector<std::string> processedFiles;
|
||||||
|
protected:
|
||||||
|
void validateDirectories();
|
||||||
|
void writeToCache();
|
||||||
|
std::string getCacheName();
|
||||||
|
static ProgressBar *getProgressBar(std::string name, int maxTicks);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ELIYA_FILEREADER_H
|
18
src/Reader/FileValidator.cpp
Normal file
18
src/Reader/FileValidator.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 24.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "FileValidator.h"
|
||||||
|
|
||||||
|
ValidateObject *FileValidator::validate(const std::string &path) {
|
||||||
|
auto validatedObject = new ValidateObject();
|
||||||
|
validatedObject->ref = TagLib::FileRef(path.c_str(), false);
|
||||||
|
validatedObject->isValid = !validatedObject->ref.isNull();
|
||||||
|
return validatedObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
// in this file we build a AudioFile from TagLib...
|
||||||
|
// we know that object is always a ptr never a nullptr so we can use that shit again ;)
|
||||||
|
AudioFile FileValidator::getAudioFile(ValidateObject *object) {
|
||||||
|
return AudioFile();
|
||||||
|
}
|
33
src/Reader/FileValidator.h
Normal file
33
src/Reader/FileValidator.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 24.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ELIYA_FILEVALIDATOR_H
|
||||||
|
#define ELIYA_FILEVALIDATOR_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "../Models/AudioFile.h"
|
||||||
|
#include <taglib/fileref.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this class validate if the file is a audio file
|
||||||
|
*/
|
||||||
|
struct ValidateObject {
|
||||||
|
TagLib::FileRef ref;
|
||||||
|
bool isValid = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileValidator {
|
||||||
|
private:
|
||||||
|
AudioFile defaultFile;
|
||||||
|
public:
|
||||||
|
FileValidator() = default;
|
||||||
|
~FileValidator() = default;
|
||||||
|
ValidateObject * validate(const std::string& path);
|
||||||
|
AudioFile getAudioFile(ValidateObject *object);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ELIYA_FILEVALIDATOR_H
|
59
src/Reader/ThreadPool.cpp
Normal file
59
src/Reader/ThreadPool.cpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 24.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "ThreadPool.h"
|
||||||
|
#include "../Utils/Logging.h"
|
||||||
|
#include "ThreadSafeDeque.h"
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <sstream>
|
||||||
|
#include <zconf.h>
|
||||||
|
|
||||||
|
void ThreadPool::setQueue(Tsqueue<std::shared_ptr<ThreadQueueItem>> *queue) {
|
||||||
|
ThreadPool::threadQueue = queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadPool::initThreads() {
|
||||||
|
threadCount = std::thread::hardware_concurrency();
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << "Create Threadpool with " << threadCount << " threads";
|
||||||
|
Logging::log(stream.str().c_str(), "ThreadPool");
|
||||||
|
threads.resize(threadCount);
|
||||||
|
threads.clear();
|
||||||
|
finishedThreads.clear();
|
||||||
|
for (int i = 0; i < threadCount; ++i) {
|
||||||
|
threads[i] = new std::thread(&ThreadPool::execute, this, i);
|
||||||
|
threads[i]->detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadPool::start(ProgressBar *progressBar) {
|
||||||
|
initThreads();
|
||||||
|
progressBar->startThread();
|
||||||
|
while (finishedThreads.size() < threadCount) {
|
||||||
|
//wait for threads to finish
|
||||||
|
std::this_thread::sleep_for(std::chrono::microseconds(1000));
|
||||||
|
}
|
||||||
|
progressBar->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadPool::execute(int threadNumber) {
|
||||||
|
//if queue empty terminate Thread... make no sense ;)
|
||||||
|
if (threadQueue->getSize() < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (auto queueItem = threadQueue->pop()) {
|
||||||
|
auto item = queueItem.value();
|
||||||
|
if (item == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto file = item->reader->files[item->fileIndex];
|
||||||
|
auto wait = 10000L+(long)((1e5-1e4)*random()/(RAND_MAX+1.0));
|
||||||
|
usleep(wait);
|
||||||
|
//do your job here!
|
||||||
|
item->progressBar->tick();
|
||||||
|
}
|
||||||
|
finishedThreads.push_back(threadNumber + 1);
|
||||||
|
}
|
40
src/Reader/ThreadPool.h
Normal file
40
src/Reader/ThreadPool.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 24.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ELIYA_THREADPOOL_H
|
||||||
|
#define ELIYA_THREADPOOL_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
#include <thread>
|
||||||
|
#include "../Utils/ProgressBar.h"
|
||||||
|
#include "FileReader.h"
|
||||||
|
#include "ThreadSafeDeque.h"
|
||||||
|
|
||||||
|
struct ThreadQueueItem {
|
||||||
|
ProgressBar *progressBar = nullptr;
|
||||||
|
int fileIndex{};
|
||||||
|
int status{};
|
||||||
|
FileReader *reader = nullptr;
|
||||||
|
ThreadQueueItem() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ThreadPool {
|
||||||
|
private:
|
||||||
|
int threadCount = 12;
|
||||||
|
std::vector<std::thread*> threads;
|
||||||
|
Tsqueue<std::shared_ptr<ThreadQueueItem>> *threadQueue = nullptr;
|
||||||
|
std::vector<int> finishedThreads;
|
||||||
|
public:
|
||||||
|
ThreadPool() = default;
|
||||||
|
~ThreadPool() = default;
|
||||||
|
void setQueue(Tsqueue<std::shared_ptr<ThreadQueueItem>> *queue);
|
||||||
|
void initThreads();
|
||||||
|
void start(ProgressBar * progressBar);
|
||||||
|
protected:
|
||||||
|
void execute(int threadNumber);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ELIYA_THREADPOOL_H
|
101
src/Reader/ThreadSafeDeque.h
Normal file
101
src/Reader/ThreadSafeDeque.h
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 29.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ELIYA_THREADSAFEDEQUE_H
|
||||||
|
#define ELIYA_THREADSAFEDEQUE_H
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <atomic>
|
||||||
|
#include <queue>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <optional>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Tsqueue {
|
||||||
|
/* Create Tsqueue object. Set maximum size of the queue to max_size. */
|
||||||
|
inline explicit Tsqueue(size_t max_size = -1UL) : maxsize(max_size), end(false) {};
|
||||||
|
|
||||||
|
/* Push T to the queue. Many threads can push at the same time.
|
||||||
|
* If the queue is full, calling thread will be suspended until
|
||||||
|
* some other thread pop() data. */
|
||||||
|
void push(const T &);
|
||||||
|
|
||||||
|
void push(T &&);
|
||||||
|
|
||||||
|
/* Close the queue.
|
||||||
|
* Be sure all writing threads done their writes before call this.
|
||||||
|
* Push data to closed queue is forbidden. */
|
||||||
|
void close();
|
||||||
|
|
||||||
|
/* Pop and return T from the queue. Many threads can pop at the same time.
|
||||||
|
* If the queue is empty, calling thread will be suspended.
|
||||||
|
* If the queue is empty and closed, nullopt returned. */
|
||||||
|
std::optional<T> pop();
|
||||||
|
std::optional<T> waitAndPop();
|
||||||
|
|
||||||
|
int getSize() {
|
||||||
|
return que.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::queue<T> que;
|
||||||
|
std::mutex mtx;
|
||||||
|
std::condition_variable cv_empty, cv_full;
|
||||||
|
const size_t maxsize;
|
||||||
|
std::atomic<bool> end;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Tsqueue<T>::push(T &&t) {
|
||||||
|
std::unique_lock<std::mutex> lck(mtx);
|
||||||
|
while (que.size() == maxsize && !end)
|
||||||
|
cv_full.wait(lck);
|
||||||
|
assert(!end);
|
||||||
|
que.push(std::move(t));
|
||||||
|
cv_empty.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Tsqueue<T>::push(const T &t) {
|
||||||
|
std::unique_lock<std::mutex> lck(mtx);
|
||||||
|
while (que.size() == maxsize && !end)
|
||||||
|
cv_full.wait(lck);
|
||||||
|
assert(!end);
|
||||||
|
que.push(std::move(t));
|
||||||
|
cv_empty.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::optional<T> Tsqueue<T>::pop() {
|
||||||
|
std::unique_lock<std::mutex> lck(mtx);
|
||||||
|
if (que.empty()) return {};
|
||||||
|
T t = std::move(que.front());
|
||||||
|
que.pop();
|
||||||
|
cv_full.notify_one();
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::optional<T> Tsqueue<T>::waitAndPop() {
|
||||||
|
std::unique_lock<std::mutex> lck(mtx);
|
||||||
|
while (que.empty() && !end)
|
||||||
|
cv_empty.wait(lck);
|
||||||
|
if (que.empty()) return {};
|
||||||
|
T t = std::move(que.front());
|
||||||
|
que.pop();
|
||||||
|
cv_full.notify_one();
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Tsqueue<T>::close() {
|
||||||
|
end = true;
|
||||||
|
std::lock_guard<std::mutex> lck(mtx);
|
||||||
|
cv_empty.notify_one();
|
||||||
|
cv_full.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ELIYA_THREADSAFEDEQUE_H
|
13
src/Utils/Logging.cpp
Normal file
13
src/Utils/Logging.cpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 22.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Logging.h"
|
||||||
|
|
||||||
|
void Logging::error(std::basic_string<char> error, std::basic_string<char> module) noexcept {
|
||||||
|
printf("\033[1;31m[Error][%s]\t %s\033[0m\n", module.c_str(), error.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logging::log(const char* log, const char* module) noexcept {
|
||||||
|
printf("\033[1;34m[Info]\033[0m[%s]\t %s\n", module, log);
|
||||||
|
}
|
21
src/Utils/Logging.h
Normal file
21
src/Utils/Logging.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 22.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef ELIYA_LOGGING_H
|
||||||
|
#define ELIYA_LOGGING_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Logging {
|
||||||
|
public:
|
||||||
|
static void error(std::basic_string<char> error, std::basic_string<char> module) noexcept;
|
||||||
|
|
||||||
|
static void log(const char* log, const char* module) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ELIYA_LOGGING_H
|
155
src/Utils/ProgressBar.cpp
Normal file
155
src/Utils/ProgressBar.cpp
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 23.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <cmath>
|
||||||
|
#include <zconf.h>
|
||||||
|
#include <thread>
|
||||||
|
#include "ProgressBar.h"
|
||||||
|
|
||||||
|
ProgressBar::ProgressBar(std::string name, int maxTicks, int showAfterTicks) {
|
||||||
|
ProgressBar::maxTicks = maxTicks + 0;
|
||||||
|
ProgressBar::ticks = 0 + 0;
|
||||||
|
ProgressBar::name = "\033[1;32m" + std::move(name) + "\033[0m";
|
||||||
|
ProgressBar::showAfterTicks = showAfterTicks;
|
||||||
|
if (maxTicks == -1) {
|
||||||
|
isUnlimited = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressBar::~ProgressBar() = default;
|
||||||
|
|
||||||
|
void ProgressBar::update() {
|
||||||
|
//only update if ticks reached
|
||||||
|
if (ticks % showAfterTicks == 0 || (isFinished && !finishedDraw)) {
|
||||||
|
if (isUnlimited) {
|
||||||
|
renderUnknown();
|
||||||
|
} else {
|
||||||
|
renderNormal();
|
||||||
|
}
|
||||||
|
if (isFinished) {
|
||||||
|
finishedDraw = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgressBar::tick() {
|
||||||
|
++ticks;
|
||||||
|
if (ticks > maxTicks && maxTicks != -1) {
|
||||||
|
ticks = maxTicks;
|
||||||
|
isFinished = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgressBar::setFinished(bool isThread) {
|
||||||
|
isFinished = true;
|
||||||
|
if (!isThread) {
|
||||||
|
this->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgressBar::start() {
|
||||||
|
start_time = std::chrono::steady_clock::now();
|
||||||
|
this->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgressBar::renderUnknown() {
|
||||||
|
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
|
||||||
|
auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time).count();
|
||||||
|
double seconds = static_cast<double>(time_elapsed) / 1000.0;
|
||||||
|
double ticks_per_second = static_cast<double>(ticks) / seconds;
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << "\033[2K" << "\r";
|
||||||
|
stream << "[" << name << "] \033[1;34m[" << unlimitedChars.at(++lastIcon % unlimitedChars.length());
|
||||||
|
stream << "]\033[1;36m [" << ticks << "]" << " (" << static_cast<std::size_t>(ticks ? ticks_per_second : 0.0)
|
||||||
|
<< " t/s)\033[0m";
|
||||||
|
std::cout << stream.str() << std::flush;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgressBar::renderNormal() {
|
||||||
|
int pos = 0;
|
||||||
|
double progress = 0;
|
||||||
|
if (ticks > 0) {
|
||||||
|
progress = double(ticks) / double(maxTicks);
|
||||||
|
pos = (50 * progress);
|
||||||
|
}
|
||||||
|
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
|
||||||
|
auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time).count();
|
||||||
|
double seconds = static_cast<double>(time_elapsed) / 1000.0;
|
||||||
|
double ticks_per_second = static_cast<double>(ticks) / seconds;
|
||||||
|
double remaining_ticks = maxTicks - ticks;
|
||||||
|
double total_seconds_rem = remaining_ticks / ticks_per_second;
|
||||||
|
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << "\033[2K" << "\r";
|
||||||
|
stream << "[" << name << "]\033[1;34m[";
|
||||||
|
for (int i = 0; i < 50; ++i) {
|
||||||
|
if (i < pos) stream << '=';
|
||||||
|
else if (i == pos) stream << ">";
|
||||||
|
else stream << ' ';
|
||||||
|
}
|
||||||
|
stream << "]\033[1;35m " << std::roundf(progress * 100.0f) << "% ";
|
||||||
|
stream << ticks << " / " << maxTicks << " [";
|
||||||
|
convertTime(stream, seconds);
|
||||||
|
stream << " / ";
|
||||||
|
if (ticks) {
|
||||||
|
convertTime(stream, total_seconds_rem);
|
||||||
|
} else {
|
||||||
|
stream << "??:??:??";
|
||||||
|
}
|
||||||
|
stream << "]";
|
||||||
|
stream << " (" << static_cast<std::size_t>(ticks ? ticks_per_second : 0.0) << " t/s)\033[0m";
|
||||||
|
std::cout << stream.str() << std::flush;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgressBar::convertTime(std::stringstream &stream, double seconds) {
|
||||||
|
std::size_t s_in_h(60 * 60), s_in_m(60)/*, m_in_h(60)*/;
|
||||||
|
int hours_rem = seconds / s_in_h;
|
||||||
|
int minutes_rem = (seconds - (hours_rem * s_in_h)) / s_in_m;
|
||||||
|
int seconds_rem = seconds - ((hours_rem * s_in_h) + (minutes_rem * s_in_m));
|
||||||
|
std::ios init(nullptr), time_fmt(nullptr);
|
||||||
|
init.copyfmt(stream);
|
||||||
|
stream << std::setfill('0') << std::setw(2);
|
||||||
|
time_fmt.copyfmt(stream);
|
||||||
|
//hours
|
||||||
|
stream.copyfmt(time_fmt);
|
||||||
|
stream << hours_rem;
|
||||||
|
stream.copyfmt(init);
|
||||||
|
//minutes
|
||||||
|
stream << ":";
|
||||||
|
stream.copyfmt(time_fmt);
|
||||||
|
stream << minutes_rem;
|
||||||
|
stream.copyfmt(init);
|
||||||
|
//seconds
|
||||||
|
stream << ":";
|
||||||
|
stream.copyfmt(time_fmt);
|
||||||
|
stream << seconds_rem;
|
||||||
|
//restore format
|
||||||
|
stream.copyfmt(init);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProgressBar::isDone() const {
|
||||||
|
return isFinished && finishedDraw;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgressBar::runInThread() {
|
||||||
|
while(!runThread) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
|
}
|
||||||
|
this->start();
|
||||||
|
while (!isDone()) {
|
||||||
|
this->update();
|
||||||
|
}
|
||||||
|
std::cout << "\n";
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgressBar::setMaxTicks(int newMaxTicks) {
|
||||||
|
maxTicks = newMaxTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgressBar::startThread() {
|
||||||
|
runThread = true;
|
||||||
|
}
|
38
src/Utils/ProgressBar.h
Normal file
38
src/Utils/ProgressBar.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 23.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ELIYA_PROGRESSBAR_H
|
||||||
|
#define ELIYA_PROGRESSBAR_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
class ProgressBar {
|
||||||
|
private:
|
||||||
|
long ticks, maxTicks, showAfterTicks, lastIcon = 0;
|
||||||
|
bool isUnlimited = false, isFinished = false, finishedDraw = false;
|
||||||
|
std::string name;
|
||||||
|
std::chrono::steady_clock::time_point start_time;
|
||||||
|
std::string unlimitedChars = "|/-\\";
|
||||||
|
bool runThread = false;
|
||||||
|
public:
|
||||||
|
ProgressBar(std::string name, int maxTicks, int showAfterTicks);
|
||||||
|
~ProgressBar();
|
||||||
|
void start();
|
||||||
|
void update();
|
||||||
|
void setFinished(bool isThread);
|
||||||
|
void tick();
|
||||||
|
bool isDone() const;
|
||||||
|
void setMaxTicks(int newMaxTicks);
|
||||||
|
void runInThread();
|
||||||
|
void startThread();
|
||||||
|
protected:
|
||||||
|
void renderNormal();
|
||||||
|
void renderUnknown();
|
||||||
|
void convertTime(std::stringstream & stream, double seconds);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ELIYA_PROGRESSBAR_H
|
17
src/Utils/Utils.cpp
Normal file
17
src/Utils/Utils.cpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 23.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
std::string Utils::stringToHex(const std::string &input) {
|
||||||
|
static const char hex_digits[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
std::string output;
|
||||||
|
output.reserve(input.length() * 2);
|
||||||
|
for (unsigned char c : input) {
|
||||||
|
output.push_back(hex_digits[c >> 4]);
|
||||||
|
output.push_back(hex_digits[c & 15]);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
17
src/Utils/Utils.h
Normal file
17
src/Utils/Utils.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
//
|
||||||
|
// Created by versustune on 23.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ELIYA_UTILS_H
|
||||||
|
#define ELIYA_UTILS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Utils {
|
||||||
|
public:
|
||||||
|
static std::string stringToHex(const std::string &input);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ELIYA_UTILS_H
|
29
src/main.cpp
Normal file
29
src/main.cpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include "Core/Arguments.h"
|
||||||
|
#include "Core/Logo.h"
|
||||||
|
#include "Reader/FileReader.h"
|
||||||
|
#include "Utils/Logging.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
std::cout << "\x1B[2J\x1B[H";
|
||||||
|
EliyaLogo::draw();
|
||||||
|
std::vector<std::string> args;
|
||||||
|
for (int i = 0; i < argc; i++)
|
||||||
|
args.emplace_back(argv[i]);
|
||||||
|
|
||||||
|
auto argParser = Arguments(argc, args);
|
||||||
|
argParser.parseArgs();
|
||||||
|
|
||||||
|
// test if the paths are provided
|
||||||
|
std::string inputDir = argParser.getArgOrDefault("files", "");
|
||||||
|
std::string opDir = argParser.getArgOrDefault("output", std::string(std::getenv("HOME")) + "/.eliya");
|
||||||
|
if (inputDir.empty() || opDir.empty()) {
|
||||||
|
Logging::error("No Input or Operation path specified", "ArgumentValidator");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
auto reader = FileReader(inputDir, opDir);
|
||||||
|
reader.pureRead();
|
||||||
|
reader.readAudioFiles();
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue