/* mcopy * * Rename music by specifying a format * Licensed under the GNU General Public License version 3. * See included LICENSE file for copyright and license details. */ #include #include #include #include #include #include #include #include #ifndef VERSION #define VERSION "0.1" #endif bool ask = true; bool quiet = false; void help() { std::cout << "mcopy " << VERSION << "\n\n" << "mcopy -f, --format Specify a format to output files using\n" << "mcopy -a, --ask Ask the user if metadata cannot be retrieved from file\n" << "mcopy -na, --no-ask Don't ask if metadata cannot be retrieved from file\n" << "mcopy -q, --quiet Don't print status messages. Warnings will still be printed\n" << "mcopy -nq, --no-quiet Print status messages\n" << "mcopy -h, --help Display help\n" << "mcopy -v, --version Display version\n" << "\n" << "Example: mcopy --format \"/home/anon/Music/Albums/@A/@a/@n. @A - @t.flac\" \"~/Downloads/myflac1.flac\" \"~/Downloads/myflac2.flac\n" << "\n" << "Formats:\n" << "\n" << "@A Artist\n" << "@a Album name\n" << "@t Title\n" << "@n Track number\n"; } TagLib::FileRef getFile(std::string str) { const char *cstr = str.c_str(); TagLib::FileName fn(cstr); TagLib::FileRef file(fn); return file; } void getMetadataFromFile(std::string format, std::string str) { TagLib::FileRef file = getFile(str); TagLib::Tag *tag = file.tag(); if (file.isNull() || !file.audioProperties()) { std::cerr << "File '" << str << "' is not valid. Skipping.\n"; return; } std::string title = tag->title().to8Bit(true); std::string album = tag->album().to8Bit(true); std::string artist = tag->artist().to8Bit(true); std::string track = std::to_string(tag->track()); // If information is missing, ask for the missing details if (title.empty()) { title = "Unknown"; if (ask) { std::cerr << "mcopy: Could not retrieve title; please specify\n> "; std::getline(std::cin, title); } } if (album.empty()) { album = "Unknown"; if (ask) { std::cerr << "mcopy: Could not retrieve album; please specify\n> "; std::getline(std::cin, album); } } if (artist.empty()) { artist = "Unknown"; if (ask) { std::cerr << "mcopy: Could not retrieve artist; please specify\n> "; std::getline(std::cin, artist); } } if (track.empty()) { track = "Unknown"; if (ask) { std::cerr << "mcopy: Could not retrieve track; please specify\n> "; std::getline(std::cin, track); } } if (!std::cin) // Failed to get details, skipping return; std::string filename = format; // TODO: Replace this junk filename = std::regex_replace(filename, std::regex("@t"), title); filename = std::regex_replace(filename, std::regex("@a"), album); filename = std::regex_replace(filename, std::regex("@A"), artist); filename = std::regex_replace(filename, std::regex("@n"), track); std::ifstream ef(filename); if (static_cast(ef.good())) { std::cerr << "mcopy: File already exists, skipping.\n"; return; } std::filesystem::path fs; std::string dir = (fs = filename).remove_filename(); if (dir.empty()) { std::cerr << "mcopy: Was not able to get a directory.\n"; return; } if (!std::filesystem::exists(fs.remove_filename())) { if (!std::filesystem::create_directories(dir)) { std::cerr << "mcopy: Failed to create directory '" << dir << "'\n"; } } if (!std::filesystem::copy_file(str, filename)) { std::cerr << "mcopy: Failed to copy file " << str << " to " << filename << "\n"; std::exit(1); } else if (!quiet) { std::cout << "mcopy: Copied file " << str << " to " << filename << "\n"; } } int main(int argc, char **argv) { bool set{false}; std::string format; for (int i{1}; i < argc; i++) { std::string arg = argv[i]; if (!arg.compare("-h") || !arg.compare("--help")) { help(); } else if (!arg.compare("-v") || !arg.compare("--version")) { std::cout << "mcopy " << VERSION << '\n'; return 0; } else if (!arg.compare("-a") || !arg.compare("--ask")) { ask = true; } else if (!arg.compare("-na") || !arg.compare("--no-ask")) { ask = false; } else if (!arg.compare("-q") || !arg.compare("--quiet")) { quiet = true; } else if (!arg.compare("-nq") || !arg.compare("--no-quiet")) { quiet = false; } else if (!arg.compare("-f") || !arg.compare("--format")) { if (argc > i+1) { format = argv[++i]; } continue; } } if (!format.compare("")) { std::cerr << "mcopy: You must specify a format.\n"; return 1; } if (argc < 4) { std::cerr << "mcopy: You must specify a file to copy.\n"; return 1; } for (int i{1}; i < argc; i++) { std::ifstream f(argv[i]); if (static_cast(f.good())) { set = true; getMetadataFromFile(format, argv[i]); } } if (!set) { std::cerr << "mcopy: File not found.\n"; return 1; } }