Compare commits
7 Commits
01fc3a0551
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| cf21d5cd74 | |||
| 7fd7492dc2 | |||
| 49eb64f589 | |||
| cb8939a3e3 | |||
| 7c213fe037 | |||
| 42ab8dbcb1 | |||
| 21058e5ac4 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
config.json
|
||||
cookies.txt
|
||||
mcat_dl*
|
||||
.vscode/*
|
||||
|
||||
43
README.md
43
README.md
@@ -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
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
# 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.
|
||||
|
||||
### 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 - Artist - Title.(mp3/flac) - Used when track artist **does not match** release artist
|
||||
@@ -38,7 +52,22 @@ https://github.com/nlohmann/json
|
||||
# eyeD3
|
||||
https://eyed3.readthedocs.io/en/latest/
|
||||
* 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
|
||||
https://xiph.org/flac/download.html
|
||||
@@ -49,17 +78,17 @@ metaflac
|
||||
--preserve-modtime
|
||||
--no-utf8-convert
|
||||
|
||||
// First Step - Remove Tags
|
||||
// First Step - Remove Pictures
|
||||
--remove --block-type=PICTURE
|
||||
|
||||
// Second Step - Remove Tags
|
||||
--remove-tag=TITLE
|
||||
--remove-tag=ARTIST
|
||||
--remove-tag=ALBUM
|
||||
--remove-tag=TRACKNUMBER
|
||||
|
||||
// Second Step - Remove Pictures
|
||||
--remove --block-type=PICTURE
|
||||
|
||||
// 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=ARTIST=..."
|
||||
"--set-tag=ALBUM=..."
|
||||
|
||||
6
TODO.md
6
TODO.md
@@ -1,5 +1 @@
|
||||
* Rate limit
|
||||
* Use external tools
|
||||
* Download and resize cover before tracks
|
||||
* Tag tracks
|
||||
* Update README with eyeD3
|
||||
* Add API Rate Limit
|
||||
|
||||
14
common.cpp
14
common.cpp
@@ -3,6 +3,7 @@
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
using std::endl;
|
||||
@@ -187,3 +188,16 @@ string clean_filename(const string& s)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool exec_cmd(const string& cmd)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = system(cmd.c_str());
|
||||
if (0 != error)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
1
common.h
1
common.h
@@ -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);
|
||||
std::string trim_whitespace(const std::string& s);
|
||||
std::string clean_filename(const std::string& s);
|
||||
bool exec_cmd(const std::string& cmd);
|
||||
|
||||
#endif // COMMON_H_
|
||||
|
||||
@@ -185,13 +185,13 @@ bool CURL_DL::download(const string& url, ostream* out,
|
||||
curl_easy_reset(m_handle);
|
||||
|
||||
// Enable cookie engine
|
||||
curl_easy_setopt(m_handle, CURLOPT_COOKIEFILE, "");
|
||||
curl_easy_setopt(m_handle, CURLOPT_COOKIEFILE, "cookies.txt");
|
||||
|
||||
// Enable error messages
|
||||
curl_easy_setopt(m_handle, CURLOPT_ERRORBUFFER, m_error);
|
||||
|
||||
// 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))
|
||||
{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"comment": "This file will attempt to download MCS1091, MCS1195, MCS1425, MCS1426",
|
||||
"releases":
|
||||
[
|
||||
"MCS1091",
|
||||
"MCS1195",
|
||||
"MCS1425",
|
||||
"MCS1426"
|
||||
]
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"Email": "USER",
|
||||
"Password": "PASS"
|
||||
}
|
||||
200
main.cpp
200
main.cpp
@@ -15,6 +15,111 @@ void usage(const char *name)
|
||||
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)
|
||||
{
|
||||
// Config stuff
|
||||
@@ -51,12 +156,19 @@ int main(int argc, char **argv)
|
||||
json_extract(config, "Pass", pass);
|
||||
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);
|
||||
if (!ok)
|
||||
{
|
||||
cout << "Could not login" << endl;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
@@ -96,6 +208,22 @@ int main(int argc, char **argv)
|
||||
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)
|
||||
for (Track& track : release.tracks)
|
||||
{
|
||||
@@ -103,6 +231,7 @@ int main(int argc, char **argv)
|
||||
|
||||
// Download MP3
|
||||
filepath = build_fname(mp3_folder, "", filename);
|
||||
filepath += ".mp3";
|
||||
ok = mcat.download_track(release.id, track.id, filepath, FORMAT_MP3);
|
||||
if (!ok)
|
||||
{
|
||||
@@ -111,8 +240,34 @@ int main(int argc, char **argv)
|
||||
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
|
||||
filepath = build_fname(flac_folder, "", filename);
|
||||
filepath += ".flac";
|
||||
ok = mcat.download_track(release.id, track.id, filepath, FORMAT_FLAC);
|
||||
if (!ok)
|
||||
{
|
||||
@@ -121,6 +276,40 @@ int main(int argc, char **argv)
|
||||
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
|
||||
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();
|
||||
if (!ok)
|
||||
{
|
||||
cout << "Could not log out" << endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -389,23 +389,24 @@ string Monstercat_DL::calc_track_filename(const Release& release, int track_num)
|
||||
return "";
|
||||
}
|
||||
|
||||
// Determine what we need
|
||||
// Determine whether number is needed
|
||||
if (1 == release.tracks.size())
|
||||
{
|
||||
use_number = false;
|
||||
use_artist = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
use_number = true;
|
||||
if (track->artist == release.artist)
|
||||
{
|
||||
use_artist = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
use_artist = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine whether artist is needed
|
||||
if (track->artist == release.artist)
|
||||
{
|
||||
use_artist = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
use_artist = true;
|
||||
}
|
||||
|
||||
// Build filename
|
||||
@@ -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,
|
||||
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();
|
||||
bool ok;
|
||||
string url;
|
||||
string filepath;
|
||||
stringstream out_data;
|
||||
ofstream out_file;
|
||||
|
||||
@@ -537,16 +537,6 @@ bool Monstercat_DL::download_track(const string& release_id,
|
||||
return false;
|
||||
}
|
||||
|
||||
filepath = path;
|
||||
if (is_mp3)
|
||||
{
|
||||
filepath += ".mp3";
|
||||
}
|
||||
else
|
||||
{
|
||||
filepath += ".flac";
|
||||
}
|
||||
|
||||
out_file.open(filepath, std::ios::binary);
|
||||
if (!out_file.is_open())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user