Skip to content

Commit ef777a1

Browse files
committed
[MIN] ALPHA 2.1
1 parent dfac8ab commit ef777a1

File tree

6 files changed

+200
-59
lines changed

6 files changed

+200
-59
lines changed

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,3 +673,26 @@ Small commit that adds a new dependency and a greatly needed feature of caching
673673
- Centering of the image_view
674674

675675
---
676+
677+
## [ALPHA 2.1] --- 17-01-2025
678+
679+
### Added
680+
- Added `src/arg-handler.hpp` and modified bash completions
681+
682+
### Changed
683+
- Command line arguments setup with subsequent changes to `src/cmg-line-args.hpp` and `main.cpp`
684+
685+
### Fixed
686+
- Issue with flac file thumbnail extraction
687+
688+
### Removed
689+
**NIL**
690+
691+
Small commit with some issues + cmd line args setup
692+
693+
### Known Issues to fix in immediate commits
694+
- Runtime errors with respect to `PlayCurrentSong()` that may be due to detaching the audio thread
695+
696+
- Centering of the image_view
697+
698+
---
Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,17 @@
1-
# A very primitive and basic completion system for inLimbo for bash
1+
#!/bin/bash
22

33
_inLimbo_completions() {
44
local cur prev opts
5-
6-
# Get the current word being typed
5+
COMPREPLY=()
76
cur="${COMP_WORDS[COMP_CWORD]}"
87
prev="${COMP_WORDS[COMP_CWORD-1]}"
8+
opts="--help --version --clear-cache --show-config-file --show-log-dir --show-dbus-name"
99

10-
# List of options for the music player
11-
opts="--play --pause --stop --next --prev --shuffle --repeat --volume --help"
12-
13-
# If the previous word is an option, suggest further options
14-
if [[ "$cur" == -* ]]; then
15-
COMPREPLY=($(compgen -W "$opts" -- "$cur"))
16-
return 0
17-
fi
18-
19-
# If the previous word is a command that expects a file path, suggest file paths
20-
if [[ "$prev" == "--play" || "$prev" == "--next" || "$prev" == "--prev" ]]; then
21-
COMPREPLY=($(compgen -f -- "$cur"))
10+
# Provide completion for options
11+
if [[ ${cur} == -* ]]; then
12+
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
2213
return 0
2314
fi
2415
}
2516

26-
# Attach the completion function to inLimbo
2717
complete -F _inLimbo_completions inLimbo

src/arg-handler.hpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#ifndef ARGUMENT_HANDLER_HPP
2+
#define ARGUMENT_HANDLER_HPP
3+
4+
#include "./cmd-line-args.hpp"
5+
#include <iostream>
6+
#include <stdexcept>
7+
#include <filesystem>
8+
9+
#define DBUS_SERVICE_NAME "org.mpris.MediaPlayer2.inLimbo"
10+
11+
// ANSI color codes for output
12+
#define COLOR_RESET "\033[0m"
13+
#define COLOR_GREEN "\033[32m"
14+
#define COLOR_BLUE "\033[34m"
15+
#define COLOR_YELLOW "\033[33m"
16+
#define COLOR_RED "\033[31m"
17+
#define COLOR_CYAN "\033[36m"
18+
#define COLOR_MAGENTA "\033[35m"
19+
20+
class ArgumentHandler
21+
{
22+
public:
23+
static void handleArguments(const CommandLineArgs& cmdArgs, const std::string& programName, const std::string& configPath, const std::string& libBinPath, const std::string& cacheDir)
24+
{
25+
if (cmdArgs.hasFlag("--help"))
26+
{
27+
printUsage(cmdArgs, programName);
28+
exit(0);
29+
}
30+
31+
if (cmdArgs.hasFlag("--version"))
32+
{
33+
std::cout << COLOR_CYAN << "inLimbo version: ALPHA 2.0" << COLOR_RESET << "\n";
34+
exit(0);
35+
}
36+
37+
if (cmdArgs.hasFlag("--clear-cache"))
38+
{
39+
clearCache(libBinPath);
40+
exit(0);
41+
}
42+
43+
if (cmdArgs.hasFlag("--show-config-file"))
44+
{
45+
std::cout << COLOR_GREEN << "Config file location: " << COLOR_RESET << configPath << "\n";
46+
exit(0);
47+
}
48+
49+
if (cmdArgs.hasFlag("--show-log-dir"))
50+
{
51+
std::cout << COLOR_BLUE << "Log directory: " << COLOR_RESET << cacheDir << "\n";
52+
exit(0);
53+
}
54+
55+
if (cmdArgs.hasFlag("--show-dbus-name"))
56+
{
57+
std::cout << COLOR_MAGENTA << "DBus name: " << COLOR_RESET << DBUS_SERVICE_NAME << "\n";
58+
exit(0);
59+
}
60+
}
61+
62+
private:
63+
static void printUsage(const CommandLineArgs& cmdArgs, const std::string& programName)
64+
{
65+
cmdArgs.printUsage(programName);
66+
}
67+
68+
static void clearCache(const std::string& libBinPath)
69+
{
70+
try
71+
{
72+
if (std::filesystem::exists(libBinPath))
73+
{
74+
std::filesystem::remove(libBinPath);
75+
std::cout << COLOR_GREEN << "Cache cleared successfully: " << COLOR_RESET << libBinPath << "\n";
76+
}
77+
else
78+
{
79+
std::cout << COLOR_YELLOW << "No cache file found to clear: " << COLOR_RESET << libBinPath << "\n";
80+
}
81+
}
82+
catch (const std::filesystem::filesystem_error& e)
83+
{
84+
std::cerr << COLOR_RED << "Error clearing cache: " << COLOR_RESET << e.what() << "\n";
85+
}
86+
}
87+
};
88+
89+
#endif // ARGUMENT_HANDLER_HPP

src/cmd-line-args.hpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@
66
#include <string>
77
#include <vector>
88
#include <stdexcept>
9+
#include <algorithm>
910

1011
class CommandLineArgs
1112
{
1213
private:
1314
std::map<std::string, std::string> args; // flag-value pairs
14-
std::vector<std::string> positionalArgs; // pos args
15-
std::vector<std::string> validFlags; // Valid flags for error checking
15+
std::vector<std::string> positionalArgs; // positional arguments
1616

1717
public:
18-
CommandLineArgs(int argc, char* argv[], const std::vector<std::string>& allowedFlags = {})
19-
: validFlags(allowedFlags)
18+
static const std::vector<std::string> validFlags; // Valid flags
19+
20+
CommandLineArgs(int argc, char* argv[])
2021
{
2122
parseArgs(argc, argv);
2223
}
@@ -43,7 +44,8 @@ class CommandLineArgs
4344

4445
void printUsage(const std::string& programName) const
4546
{
46-
std::cerr << "Usage: " << programName << " [options] [positional arguments]\n";
47+
std::cerr << "Music player that keeps you in Limbo.\n";
48+
std::cerr << "Usage: " << programName << " [options] [positional arguments]\n\n";
4749
if (!validFlags.empty())
4850
{
4951
std::cerr << "Valid options:\n";
@@ -72,8 +74,8 @@ class CommandLineArgs
7274
value = argv[++i]; // Consume the next argument as the value
7375
}
7476

75-
// Validate the flag if a list of valid flags is provided
76-
if (!validFlags.empty() && std::find(validFlags.begin(), validFlags.end(), flag) == validFlags.end())
77+
// Validate the flag
78+
if (std::find(validFlags.begin(), validFlags.end(), flag) == validFlags.end())
7779
{
7880
throw std::invalid_argument("Invalid flag: " + flag);
7981
}
@@ -88,4 +90,10 @@ class CommandLineArgs
8890
}
8991
};
9092

93+
// Define valid flags globally
94+
const std::vector<std::string> CommandLineArgs::validFlags = {
95+
"--help", "--show-dbus-name", "--version", "--clear-cache",
96+
"--show-config-file", "--show-log-dir"
97+
};
98+
9199
#endif // COMMAND_LINE_ARGS_HPP

src/dirsort/taglib_parser.h

Lines changed: 61 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
#ifndef __EMSCRIPTEN__
1919
#include <taglib/fileref.h>
2020
#include <taglib/tag.h>
21+
#include <taglib/tag_c.h>
2122
#include <taglib/id3v2tag.h>
2223
#include <taglib/mpegfile.h>
2324
#include <taglib/attachedpictureframe.h>
2425
#include <taglib/tpropertymap.h>
26+
#include <taglib/flacfile.h>
2527
#include <png.h>
2628
#endif
2729
#include <unordered_map>
@@ -259,54 +261,78 @@ void printMetadata(const Metadata& metadata) {
259261
}
260262

261263
/**
262-
* @brief Extracts the thumbnail (album art) from an audio file and saves it to an image file.
264+
* @brief Extracts the thumbnail (album art) from an audio file and saves it to an image file. (Works for mp3 and flac)
263265
* @param audioFilePath The path to the audio file containing embedded album art.
264266
* @param outputImagePath The path where the extracted album art image will be saved.
265267
* @return `true` if the thumbnail was successfully extracted, `false` otherwise.
266268
*/
267269
bool extractThumbnail(const std::string& audioFilePath, const std::string& outputImagePath) {
268-
// Open the file using TagLib
269-
TagLib::MPEG::File file(audioFilePath.c_str());
270-
if (!file.isValid()) {
271-
std::cerr << "Error: Could not open audio file." << std::endl;
272-
return false;
273-
}
270+
// Determine the file type based on the extension
271+
std::string extension = audioFilePath.substr(audioFilePath.find_last_of('.') + 1);
272+
273+
if (extension == "mp3") {
274+
// Handle MP3 files (ID3v2 tag)
275+
TagLib::MPEG::File mpegFile(audioFilePath.c_str());
276+
if (!mpegFile.isValid()) {
277+
std::cerr << "Error: Could not open MP3 file." << std::endl;
278+
return false;
279+
}
274280

275-
// Ensure the file has ID3v2 tags
276-
TagLib::ID3v2::Tag* id3v2Tag = file.ID3v2Tag();
277-
if (!id3v2Tag) {
278-
std::cerr << "Error: No ID3v2 tags found in the audio file." << std::endl;
279-
return false;
280-
}
281+
TagLib::ID3v2::Tag* id3v2Tag = mpegFile.ID3v2Tag();
282+
if (!id3v2Tag) {
283+
std::cerr << "Error: No ID3v2 tags found in the MP3 file." << std::endl;
284+
return false;
285+
}
281286

282-
// Search for the APIC (Attached Picture) frame
283-
const TagLib::ID3v2::FrameList& frameList = id3v2Tag->frameListMap()["APIC"];
284-
if (frameList.isEmpty()) {
285-
std::cerr << "Error: No embedded album art found in the audio file." << std::endl;
286-
return false;
287-
}
287+
const TagLib::ID3v2::FrameList& frameList = id3v2Tag->frameListMap()["APIC"];
288+
if (frameList.isEmpty()) {
289+
std::cerr << "Error: No embedded album art found in the MP3 file." << std::endl;
290+
return false;
291+
}
288292

289-
// Extract the first APIC frame (album art)
290-
auto* apicFrame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(frameList.front());
291-
if (!apicFrame) {
292-
std::cerr << "Error: Failed to retrieve album art." << std::endl;
293-
return false;
294-
}
293+
auto* apicFrame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(frameList.front());
294+
if (!apicFrame) {
295+
std::cerr << "Error: Failed to retrieve album art from MP3." << std::endl;
296+
return false;
297+
}
298+
299+
const auto& pictureData = apicFrame->picture();
300+
std::ofstream outputFile(outputImagePath, std::ios::binary);
301+
if (!outputFile) {
302+
std::cerr << "Error: Could not create output image file." << std::endl;
303+
return false;
304+
}
305+
306+
outputFile.write(reinterpret_cast<const char*>(pictureData.data()), pictureData.size());
307+
outputFile.close();
308+
} else if (extension == "flac") {
309+
// Handle FLAC files
310+
TagLib::FLAC::File flacFile(audioFilePath.c_str(), true);
311+
if (!flacFile.isValid()) {
312+
std::cerr << "Error: Could not open FLAC file." << std::endl;
313+
return false;
314+
}
295315

296-
// Get the picture data and MIME type
297-
const auto& pictureData = apicFrame->picture();
298-
const std::string mimeType = apicFrame->mimeType().toCString(true);
316+
const TagLib::List<TagLib::FLAC::Picture*>& pictureList = flacFile.pictureList();
317+
if (pictureList.isEmpty()) {
318+
std::cerr << "Error: No album art found in the FLAC file." << std::endl;
319+
return false;
320+
}
321+
322+
const auto& pictureData = pictureList.front()->data();
323+
std::ofstream outputFile(outputImagePath, std::ios::binary);
324+
if (!outputFile) {
325+
std::cerr << "Error: Could not create output image file." << std::endl;
326+
return false;
327+
}
299328

300-
// Save the picture data to a file
301-
std::ofstream outputFile(outputImagePath, std::ios::binary);
302-
if (!outputFile) {
303-
std::cerr << "Error: Could not create output image file." << std::endl;
329+
outputFile.write(reinterpret_cast<const char*>(pictureData.data()), pictureData.size());
330+
outputFile.close();
331+
} else {
332+
std::cerr << "Error: Unsupported file format. Only MP3 and FLAC are supported." << std::endl;
304333
return false;
305334
}
306335

307-
outputFile.write(reinterpret_cast<const char*>(pictureData.data()), pictureData.size());
308-
outputFile.close();
309-
310336
return true;
311337
}
312338

src/main.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "dirsort/inode_mapper.hpp"
22
#include "signal/signalHandler.hpp"
33
#include "ui/ui_handler.hpp"
4+
#include "./arg-handler.hpp"
45
#include <memory>
56
#include <random>
67

@@ -9,7 +10,11 @@ int main(int argc, char* argv[])
910
SignalHandler::getInstance().setup();
1011
auto directoryPath = string(parseTOMLField(PARENT_LIB, PARENT_LIB_FIELD_DIR));
1112
string libSyncPath = getConfigPath(LIB_SYNC_NAME);
13+
string configPath = getConfigPath("config.toml");
14+
string cacheDir = getCachePath();
1215
string libBinPath = getConfigPath(LIB_BIN_NAME);
16+
CommandLineArgs cmdArgs(argc, argv);
17+
ArgumentHandler::handleArguments(cmdArgs, argv[0], configPath, libBinPath, cacheDir);
1318
RedBlackTree rbt;
1419
InodeFileMapper mapper(libSyncPath, "false");
1520

@@ -22,7 +27,7 @@ int main(int argc, char* argv[])
2227
try
2328
{
2429
song_tree.loadFromFile(libBinPath);
25-
cout << "-- Successfully loaded song tree from file." << endl;
30+
cout << "-- Successfully loaded song tree from cache file." << endl;
2631
}
2732
catch (const std::exception& e)
2833
{

0 commit comments

Comments
 (0)