Compare commits

...

7 Commits

Author SHA1 Message Date
cf21d5cd74 Fixed donwloader to work with direct cookie. Cleaned some files. 2024-09-10 14:50:21 +03:00
7fd7492dc2 Changed file naming 2024-07-09 16:42:14 +03:00
49eb64f589 Addedd Prerequisites to README 2024-07-01 16:34:58 +03:00
cb8939a3e3 Added FLAC Tagging 2024-07-01 16:04:53 +03:00
7c213fe037 Added MP3 tagging 2024-07-01 15:39:42 +03:00
42ab8dbcb1 Added cover resizing 2024-07-01 15:17:40 +03:00
21058e5ac4 Prepare for tagging 2024-07-01 15:10:04 +03:00
11 changed files with 259 additions and 65 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
config.json config.json
cookies.txt
mcat_dl* mcat_dl*
.vscode/* .vscode/*

View File

@@ -1,9 +1,23 @@
# Prerequisites
### Ubuntu
`apt install build-essential libcurl4-gnutls-dev imagemagick eyeD3 flac`
### Other OS
* make
* g++
* libcurl
* imagemagick (convert executable)
* eyeD3 executable
* metaflac executable
# Usage # Usage
There must be a file named "config.json" in the working directory with your monstercat credentials and other configurations. There must be a file named "config.json" in the working directory with your monstercat credentials and other configurations.
See config_example.json for the template. See config_example.json for the template.
Invoke `make` to compile. Requires libcurl. Invoke `make` to compile. Requires libcurl.
Login via browser and export `cid` cookie to cookies.txt (Netscape format)
Invoke `mcat_dl` with catalog ID as extra arguments to download. Invoke `mcat_dl` with catalog ID as extra arguments to download.
# Download File Structure # Download File Structure
@@ -25,7 +39,7 @@ Separate folders if more than 1 track otherwise put in main folder.
This is where extended mixes are put into. They are in their original format. This is where extended mixes are put into. They are in their original format.
### File Naming ### File Naming
* Artist - Title.(mp3/flac) - Used when only 1 track * Title.(mp3/flac) - Used when only 1 track
* Number - Title.(mp3/flac) - Used when track artist **matches** release artist * Number - Title.(mp3/flac) - Used when track artist **matches** release artist
* Number - Artist - Title.(mp3/flac) - Used when track artist **does not match** release artist * Number - Artist - Title.(mp3/flac) - Used when track artist **does not match** release artist
@@ -38,7 +52,22 @@ https://github.com/nlohmann/json
# eyeD3 # eyeD3
https://eyed3.readthedocs.io/en/latest/ https://eyed3.readthedocs.io/en/latest/
* For MP3 tagging * For MP3 tagging
* TODO: Add info here ```
// Common
--encoding utf8
--preserve-file-times
// First Step - Remove Images
--remove-all-images
// Second Step - Change what is needed
--add-image "...":FRONT_COVER
--artist "..."
--album "..."
--title "..."
--track ...
```
# metaflac # metaflac
https://xiph.org/flac/download.html https://xiph.org/flac/download.html
@@ -49,17 +78,17 @@ metaflac
--preserve-modtime --preserve-modtime
--no-utf8-convert --no-utf8-convert
// First Step - Remove Tags // First Step - Remove Pictures
--remove --block-type=PICTURE
// Second Step - Remove Tags
--remove-tag=TITLE --remove-tag=TITLE
--remove-tag=ARTIST --remove-tag=ARTIST
--remove-tag=ALBUM --remove-tag=ALBUM
--remove-tag=TRACKNUMBER --remove-tag=TRACKNUMBER
// Second Step - Remove Pictures
--remove --block-type=PICTURE
// Third Step - Add // Third Step - Add
--import-picture-from=3|image/jpeg|||"/path/to/cover" "--import-picture-from=3|image/jpeg|||/path/to/cover"
"--set-tag=TITLE=..." "--set-tag=TITLE=..."
"--set-tag=ARTIST=..." "--set-tag=ARTIST=..."
"--set-tag=ALBUM=..." "--set-tag=ALBUM=..."

View File

@@ -1,5 +1 @@
* Rate limit * Add API Rate Limit
* Use external tools
* Download and resize cover before tracks
* Tag tracks
* Update README with eyeD3

View File

@@ -3,6 +3,7 @@
#include <fstream> #include <fstream>
#include <set> #include <set>
#include <stdlib.h>
#include <sys/stat.h> #include <sys/stat.h>
using std::endl; using std::endl;
@@ -187,3 +188,16 @@ string clean_filename(const string& s)
return result; return result;
} }
bool exec_cmd(const string& cmd)
{
int error;
error = system(cmd.c_str());
if (0 != error)
{
return false;
}
return true;
}

View File

@@ -19,5 +19,6 @@ void json_extract(const nlohmann::json& j, const std::string& key, bool& out);
bool ensure_folder(const std::string& main_path, const std::string& folder); bool ensure_folder(const std::string& main_path, const std::string& folder);
std::string trim_whitespace(const std::string& s); std::string trim_whitespace(const std::string& s);
std::string clean_filename(const std::string& s); std::string clean_filename(const std::string& s);
bool exec_cmd(const std::string& cmd);
#endif // COMMON_H_ #endif // COMMON_H_

View File

@@ -185,13 +185,13 @@ bool CURL_DL::download(const string& url, ostream* out,
curl_easy_reset(m_handle); curl_easy_reset(m_handle);
// Enable cookie engine // Enable cookie engine
curl_easy_setopt(m_handle, CURLOPT_COOKIEFILE, ""); curl_easy_setopt(m_handle, CURLOPT_COOKIEFILE, "cookies.txt");
// Enable error messages // Enable error messages
curl_easy_setopt(m_handle, CURLOPT_ERRORBUFFER, m_error); curl_easy_setopt(m_handle, CURLOPT_ERRORBUFFER, m_error);
// Set User-Agent // Set User-Agent
curl_easy_setopt(m_handle, CURLOPT_USERAGENT, "Internedko Archiver"); curl_easy_setopt(m_handle, CURLOPT_USERAGENT, "Internedko Downloader");
if ((nullptr == params) || (params->count("no-redir") == 0)) if ((nullptr == params) || (params->count("no-redir") == 0))
{ {

View File

@@ -1,7 +0,0 @@
{
"comment": "This file will attempt to download MCLP001, MCLP001-X, MCLP002, ... MCLP010-X",
"prefix": "MCLP",
"suffix_try": "-X",
"start": 1,
"end": 10
}

View File

@@ -1,10 +0,0 @@
{
"comment": "This file will attempt to download MCS1091, MCS1195, MCS1425, MCS1426",
"releases":
[
"MCS1091",
"MCS1195",
"MCS1425",
"MCS1426"
]
}

View File

@@ -1,4 +0,0 @@
{
"Email": "USER",
"Password": "PASS"
}

200
main.cpp
View File

@@ -15,6 +15,111 @@ void usage(const char *name)
cout << "Usage: " << name << " [catalog id] ..." << endl; cout << "Usage: " << name << " [catalog id] ..." << endl;
} }
string gen_resize_command(const string& release_folder, const string& convert_exec)
{
string cmd;
cmd = convert_exec;
cmd += " \"";
cmd += build_fname(release_folder, "", "Cover.*");
cmd += "\" -resize 750x750 \"";
cmd += build_fname(release_folder, "", "Cover_small.jpg");
cmd += "\"";
return cmd;
}
string gen_mp3_clear(const string& filepath, const string& eyed3_exec)
{
string cmd;
cmd = eyed3_exec;
cmd += " --preserve-file-times --remove-all-images \"";
cmd += filepath;
cmd += "\" > /dev/null 2>&1";
return cmd;
}
string gen_mp3_set_tags(const string& filepath, const string& artist,
const string& title, const string& album, int track_num,
const string& cover_filepath, string eyed3_exec)
{
string cmd;
cmd = eyed3_exec;
cmd += " --encoding utf8 --preserve-file-times --add-image \"";
cmd += cover_filepath;
cmd += "\":FRONT_COVER --artist \"";
cmd += artist;
// cmd += "\" --album \"";
// cmd += album;
cmd += "\" --title \"";
cmd += title;
cmd += "\" --track ";
cmd += to_string(track_num);
cmd += " \"";
cmd += filepath;
cmd += "\" > /dev/null 2>&1";
return cmd;
}
string gen_flac_clear_images(const string& filepath, const string& metaflac_exec)
{
string cmd;
cmd = metaflac_exec;
cmd += " --preserve-modtime --no-utf8-convert";
cmd += " --remove --block-type=PICTURE \"";
cmd += filepath;
cmd += "\"";
return cmd;
}
string gen_flac_clear_tags(const string& filepath, const string& metaflac_exec)
{
string cmd;
cmd = metaflac_exec;
cmd += " --preserve-modtime --no-utf8-convert";
cmd += " --remove-tag=TITLE";
cmd += " --remove-tag=ARTIST";
// cmd += " --remove-tag=ALBUM";
cmd += " --remove-tag=TRACKNUMBER";
cmd += " \"";
cmd += filepath;
cmd += "\"";
return cmd;
}
string gen_flac_set_tags(const string& filepath, const string& artist,
const string& title, const string& album, int track_num,
const string& cover_filepath, string metaflac_exec)
{
string cmd;
cmd = metaflac_exec;
cmd += " --preserve-modtime --no-utf8-convert";
cmd += " \"--import-picture-from=3|image/jpeg|||";
cmd += cover_filepath;
cmd += "\" \"--set-tag=TITLE=";
cmd += title;
cmd += "\" \"--set-tag=ARTIST=";
cmd += artist;
// cmd += "\" \"--set-tag=ALBUM=";
// cmd += album;
cmd += "\" \"--set-tag=TRACKNUMBER=";
cmd += to_string(track_num);
cmd += "\" --dont-use-padding \"";
cmd += filepath;
cmd += "\"";
return cmd;
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
// Config stuff // Config stuff
@@ -51,12 +156,19 @@ int main(int argc, char **argv)
json_extract(config, "Pass", pass); json_extract(config, "Pass", pass);
json_extract(config, "download_path", main_path); json_extract(config, "download_path", main_path);
json_extract(config, "convert_exec", convert_exec);
json_extract(config, "eyed3_exec", eyed3_exec);
json_extract(config, "metaflac_exec", metaflac_exec);
// Disable LOGIN
#if 0
ok = mcat.login(email, pass); ok = mcat.login(email, pass);
if (!ok) if (!ok)
{ {
cout << "Could not login" << endl; cout << "Could not login" << endl;
return -1; return -1;
} }
#endif
if (argc < 2) if (argc < 2)
{ {
@@ -96,6 +208,22 @@ int main(int argc, char **argv)
continue; continue;
} }
// Download Cover
ok = mcat.download_cover(release.catalog_id, release_folder);
if (!ok)
{
cout << "Could not download cover for release " << release.catalog_id << endl;
continue;
}
// Resize cover
ok = exec_cmd(gen_resize_command(release_folder, convert_exec));
if (!ok)
{
cout << "Could not resize cover for release - " << release.catalog_id << endl;
continue;
}
// Download tracks (1 -- N) // Download tracks (1 -- N)
for (Track& track : release.tracks) for (Track& track : release.tracks)
{ {
@@ -103,6 +231,7 @@ int main(int argc, char **argv)
// Download MP3 // Download MP3
filepath = build_fname(mp3_folder, "", filename); filepath = build_fname(mp3_folder, "", filename);
filepath += ".mp3";
ok = mcat.download_track(release.id, track.id, filepath, FORMAT_MP3); ok = mcat.download_track(release.id, track.id, filepath, FORMAT_MP3);
if (!ok) if (!ok)
{ {
@@ -111,8 +240,34 @@ int main(int argc, char **argv)
continue; continue;
} }
// Clear MP3 Images
ok = exec_cmd(gen_mp3_clear(filepath, eyed3_exec));
if (!ok)
{
cout << "Could not clear images for MP3 track " << track.number <<
" from release " << release.catalog_id << endl;
continue;
}
// Set MP3 Tags
ok = exec_cmd(
gen_mp3_set_tags(filepath,
track.artist,
track.title,
release.title,
track.number,
build_fname(release_folder, "", "Cover_small.jpg"),
eyed3_exec));
if (!ok)
{
cout << "Could not tag MP3 track " << track.number <<
" from release " << release.catalog_id << endl;
continue;
}
// Download FLAC // Download FLAC
filepath = build_fname(flac_folder, "", filename); filepath = build_fname(flac_folder, "", filename);
filepath += ".flac";
ok = mcat.download_track(release.id, track.id, filepath, FORMAT_FLAC); ok = mcat.download_track(release.id, track.id, filepath, FORMAT_FLAC);
if (!ok) if (!ok)
{ {
@@ -121,6 +276,40 @@ int main(int argc, char **argv)
continue; continue;
} }
// Clear FLAC Images
ok = exec_cmd(gen_flac_clear_images(filepath, metaflac_exec));
if (!ok)
{
cout << "Could not clear images for FLAC track " << track.number <<
" from release " << release.catalog_id << endl;
continue;
}
// Clear FLAC Tags
ok = exec_cmd(gen_flac_clear_tags(filepath, metaflac_exec));
if (!ok)
{
cout << "Could not clear tags for FLAC track " << track.number <<
" from release " << release.catalog_id << endl;
continue;
}
// Set FLAC Tags
ok = exec_cmd(
gen_flac_set_tags(filepath,
track.artist,
track.title,
release.title,
track.number,
build_fname(release_folder, "", "Cover_small.jpg"),
metaflac_exec));
if (!ok)
{
cout << "Could not tag FLAC track " << track.number <<
" from release " << release.catalog_id << endl;
continue;
}
// Download Extended Mix // Download Extended Mix
if (!track.extended_mix_file_id.empty()) if (!track.extended_mix_file_id.empty())
{ {
@@ -143,21 +332,16 @@ int main(int argc, char **argv)
} }
} }
} }
// Download Cover
ok = mcat.download_cover(release.catalog_id, release_folder);
if (!ok)
{
cout << "Could not download cover for release " << release.catalog_id << endl;
continue;
}
} }
// Disable LOGOUT
#if 0
ok = mcat.logout(); ok = mcat.logout();
if (!ok) if (!ok)
{ {
cout << "Could not log out" << endl; cout << "Could not log out" << endl;
} }
#endif
return 0; return 0;
} }

View File

@@ -389,15 +389,17 @@ string Monstercat_DL::calc_track_filename(const Release& release, int track_num)
return ""; return "";
} }
// Determine what we need // Determine whether number is needed
if (1 == release.tracks.size()) if (1 == release.tracks.size())
{ {
use_number = false; use_number = false;
use_artist = true;
} }
else else
{ {
use_number = true; use_number = true;
}
// Determine whether artist is needed
if (track->artist == release.artist) if (track->artist == release.artist)
{ {
use_artist = false; use_artist = false;
@@ -406,7 +408,6 @@ string Monstercat_DL::calc_track_filename(const Release& release, int track_num)
{ {
use_artist = true; use_artist = true;
} }
}
// Build filename // Build filename
result = ""; result = "";
@@ -502,12 +503,11 @@ bool Monstercat_DL::download_cover(const string& catalog_id, const string& path)
} }
bool Monstercat_DL::download_track(const string& release_id, bool Monstercat_DL::download_track(const string& release_id,
const string& track_id, const string& path, bool is_mp3) const string& track_id, const string& filepath, bool is_mp3)
{ {
CURL_DL& curl = CURL_DL::get_handle(); CURL_DL& curl = CURL_DL::get_handle();
bool ok; bool ok;
string url; string url;
string filepath;
stringstream out_data; stringstream out_data;
ofstream out_file; ofstream out_file;
@@ -537,16 +537,6 @@ bool Monstercat_DL::download_track(const string& release_id,
return false; return false;
} }
filepath = path;
if (is_mp3)
{
filepath += ".mp3";
}
else
{
filepath += ".flac";
}
out_file.open(filepath, std::ios::binary); out_file.open(filepath, std::ios::binary);
if (!out_file.is_open()) if (!out_file.is_open())
{ {