diff --git a/src/main.cpp b/src/main.cpp index 567542a..27be95f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,9 +1,7 @@ #include #include -#include #include -#include #include #include #include @@ -20,6 +18,5 @@ auto main(int argc, char* argv[]) -> int { url = std::regex_replace(url, std::regex("music.youtube"), "www.youtube"); auto playlist = Playlist(url); - playlist.download(); - playlist.writeMetadata(); + playlist.rip(musicDir); } diff --git a/src/playlist.cpp b/src/playlist.cpp index af0a665..ebc152f 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -19,6 +19,32 @@ using json = nlohmann::json; Playlist::Playlist(const std::string& playlistUrl) : playlistUrl(playlistUrl) {} +auto Playlist::rip(const std::string& musicFolder) -> bool { + printf("Writting to data.json\n"); + json data = writeAndReturnDataJson(playlistUrl); + + if (!download()) { + printf("ERROR: Failed to download playlsit\n"); + return false; + } + + if (!writeMetadata(data)) { + printf("ERROR: Failed to write metatdata for playlsit\n"); + return false; + } + + std::string artist; + std::string album; + aristAndAlbumName(data, artist, album); + + if (!moveAndSortTmpFilesToFolder(musicFolder, artist, album)) { + printf("ERROR: Failed to move files to music folder\n"); + return false; + } + + return true; +} + auto Playlist::download() -> bool { std::vector videoUrls = urlsFromPlaylist(playlistUrl); @@ -57,27 +83,14 @@ auto Playlist::download() -> bool { return true; } -auto Playlist::writeMetadata() -> bool { - std::string artist = channelNamePlaylist(); - std::string album = playlistTitle(); +auto Playlist::writeMetadata(const json& data) -> bool { + std::string artist; + std::string album; + aristAndAlbumName(data, artist, album); + printf("Starting to write metadata for %s by %s.\n", album.c_str(), artist.c_str()); printf("Finding album cover.\n"); - std::filesystem::remove("tmp/data.json"); - ytdlp( - std::format("--js-runtimes \"deno:bin/linux/deno\" " - "--dump-single-json " - "\"{}\" " - "> tmp/data.json", - playlistUrl)); - - std::ifstream f("tmp/data.json"); - if (!f) { - printf("ERROR: Couldn't open data.json\n"); - return false; - } - - json data = json::parse(f); std::string coverUrl = data["thumbnails"][1]["url"]; downloadImageToTmpFolder(coverUrl); @@ -98,19 +111,31 @@ auto Playlist::writeMetadata() -> bool { return true; } +auto Playlist::aristAndAlbumName(const nlohmann::json& data, std::string& artist, std::string& album) -> bool { + artist = data["entries"][0]["uploader"]; + artist = std::regex_replace(artist, std::regex(" - Topic"), ""); + + album = data["title"]; + album = std::regex_replace(album, std::regex("Album - "), ""); + + return true; +} + auto Playlist::urlsFromPlaylist(const std::string& url) -> std::vector { std::vector urls; - std::filesystem::remove("urls.txt"); + std::string urlsFileLocation = "tmp/urls.txt"; + + std::filesystem::remove(urlsFileLocation); ytdlp( std::format("--js-runtimes \"deno:bin/linux/deno\" " "--quiet " "--flat-playlist " "--print-to-file \"%(webpage_url)s\" " - "urls.txt \"{}\"", - url)); + "{} \"{}\"", + urlsFileLocation, url)); - std::ifstream f("urls.txt"); + std::ifstream f(urlsFileLocation); if (!f.is_open()) { printf("ERROR: Couldn't open urls.txt\n"); return urls; @@ -124,38 +149,3 @@ auto Playlist::urlsFromPlaylist(const std::string& url) -> std::vector std::string { - ytdlp( - std::format("--quiet " - "--no-warnings " - "--flat-playlist " - "--playlist-items 1 " - "--print-to-file \"%({})s\" data.txt \"{}\"", - data, playlistUrl)); - - std::ifstream f("data.txt"); - if (!f.is_open()) { - printf("ERROR: Couldn't open data.txt\n"); - } - - std::string s; - std::string line; - while (std::getline(f, line)) { - s = line; - } - - return s; -}; - -auto Playlist::playlistTitle() -> std::string { - std::string s = dataFromYtdlpPlaylist("playlist_title"); - s = std::regex_replace(s, std::regex("Album - "), ""); - return s; -} - -auto Playlist::channelNamePlaylist() -> std::string { - std::string s = dataFromYtdlpPlaylist("channel"); - s = std::regex_replace(s, std::regex(" - Topic"), ""); - return s; -} diff --git a/src/playlist.hpp b/src/playlist.hpp index 4167651..e4570fe 100644 --- a/src/playlist.hpp +++ b/src/playlist.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -8,12 +9,11 @@ class Playlist { public: Playlist(const std::string& playlistUrl); - auto download() -> bool; - auto writeMetadata() -> bool; + auto rip(const std::string& musicFolder) -> bool; private: + auto download() -> bool; + auto writeMetadata(const nlohmann::json& data) -> bool; + auto aristAndAlbumName(const nlohmann::json& data, std::string& artist, std::string& album) -> bool; auto urlsFromPlaylist(const std::string& url) -> std::vector; - auto dataFromYtdlpPlaylist(const std::string& data) -> std::string; - auto playlistTitle() -> std::string; - auto channelNamePlaylist() -> std::string; }; diff --git a/src/utils.cpp b/src/utils.cpp index a1348cd..aecddd7 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -6,12 +6,15 @@ #include #include #include +#include #include #include #include #include "config.hpp" +using json = nlohmann::json; + // This runs in shell, if put through a website interface it would allow for injection auto ytdlp(const std::string& args) -> bool { system(std::format("bin/linux/yt-dlp {}", args).c_str()); @@ -97,3 +100,38 @@ auto downloadVideo(const std::string& url) -> bool { printf("Finished downloading video %s.\n", url.c_str()); return true; } + +auto writeAndReturnDataJson(const std::string& url) -> json { + std::filesystem::remove("tmp/data.json"); + ytdlp( + std::format("--js-runtimes \"deno:bin/linux/deno\" " + "--dump-single-json " + "\"{}\" " + "> tmp/data.json", + url)); + + std::ifstream f("tmp/data.json"); + if (!f) { + printf("ERROR: Couldn't open data.json\n"); + return false; + } + + return json::parse(f); +} + +auto moveAndSortTmpFilesToFolder(const std::string& folder, const std::string& artist, const std::string& album) + -> bool { + std::filesystem::path folderPath(folder); + std::filesystem::path path = folderPath / artist / album; + std::filesystem::create_directories(path); + + for (const auto& entry : std::filesystem::directory_iterator(path)) { + std::filesystem::remove_all(entry.path()); + } + + for (const auto& entry : std::filesystem::directory_iterator(TMP_DOWNLOAD_FOLDER)) { + std::filesystem::rename(entry, path / entry.path().filename()); + } + + return true; +} diff --git a/src/utils.hpp b/src/utils.hpp index 32cac02..0c1394e 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include auto ytdlp(const std::string& args) -> bool; @@ -10,3 +11,8 @@ auto cleanTmpDownloadFolder() -> bool; auto downloadImageToTmpFolder(const std::string& url) -> bool; auto downloadVideo(const std::string& url) -> bool; + +auto writeAndReturnDataJson(const std::string& url) -> nlohmann::json; + +auto moveAndSortTmpFilesToFolder(const std::string& folder, const std::string& artist, const std::string& album) + -> bool;