Fully working album download
This commit is contained in:
+1
-4
@@ -1,9 +1,7 @@
|
|||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include <curl/easy.h>
|
#include <curl/easy.h>
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -20,6 +18,5 @@ auto main(int argc, char* argv[]) -> int {
|
|||||||
|
|
||||||
url = std::regex_replace(url, std::regex("music.youtube"), "www.youtube");
|
url = std::regex_replace(url, std::regex("music.youtube"), "www.youtube");
|
||||||
auto playlist = Playlist(url);
|
auto playlist = Playlist(url);
|
||||||
playlist.download();
|
playlist.rip(musicDir);
|
||||||
playlist.writeMetadata();
|
|
||||||
}
|
}
|
||||||
|
|||||||
+47
-57
@@ -19,6 +19,32 @@ using json = nlohmann::json;
|
|||||||
|
|
||||||
Playlist::Playlist(const std::string& playlistUrl) : playlistUrl(playlistUrl) {}
|
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 {
|
auto Playlist::download() -> bool {
|
||||||
std::vector<std::string> videoUrls = urlsFromPlaylist(playlistUrl);
|
std::vector<std::string> videoUrls = urlsFromPlaylist(playlistUrl);
|
||||||
|
|
||||||
@@ -57,27 +83,14 @@ auto Playlist::download() -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Playlist::writeMetadata() -> bool {
|
auto Playlist::writeMetadata(const json& data) -> bool {
|
||||||
std::string artist = channelNamePlaylist();
|
std::string artist;
|
||||||
std::string album = playlistTitle();
|
std::string album;
|
||||||
|
aristAndAlbumName(data, artist, album);
|
||||||
|
|
||||||
printf("Starting to write metadata for %s by %s.\n", album.c_str(), artist.c_str());
|
printf("Starting to write metadata for %s by %s.\n", album.c_str(), artist.c_str());
|
||||||
|
|
||||||
printf("Finding album cover.\n");
|
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"];
|
std::string coverUrl = data["thumbnails"][1]["url"];
|
||||||
downloadImageToTmpFolder(coverUrl);
|
downloadImageToTmpFolder(coverUrl);
|
||||||
|
|
||||||
@@ -98,19 +111,31 @@ auto Playlist::writeMetadata() -> bool {
|
|||||||
return true;
|
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::string> {
|
auto Playlist::urlsFromPlaylist(const std::string& url) -> std::vector<std::string> {
|
||||||
std::vector<std::string> urls;
|
std::vector<std::string> urls;
|
||||||
|
|
||||||
std::filesystem::remove("urls.txt");
|
std::string urlsFileLocation = "tmp/urls.txt";
|
||||||
|
|
||||||
|
std::filesystem::remove(urlsFileLocation);
|
||||||
ytdlp(
|
ytdlp(
|
||||||
std::format("--js-runtimes \"deno:bin/linux/deno\" "
|
std::format("--js-runtimes \"deno:bin/linux/deno\" "
|
||||||
"--quiet "
|
"--quiet "
|
||||||
"--flat-playlist "
|
"--flat-playlist "
|
||||||
"--print-to-file \"%(webpage_url)s\" "
|
"--print-to-file \"%(webpage_url)s\" "
|
||||||
"urls.txt \"{}\"",
|
"{} \"{}\"",
|
||||||
url));
|
urlsFileLocation, url));
|
||||||
|
|
||||||
std::ifstream f("urls.txt");
|
std::ifstream f(urlsFileLocation);
|
||||||
if (!f.is_open()) {
|
if (!f.is_open()) {
|
||||||
printf("ERROR: Couldn't open urls.txt\n");
|
printf("ERROR: Couldn't open urls.txt\n");
|
||||||
return urls;
|
return urls;
|
||||||
@@ -124,38 +149,3 @@ auto Playlist::urlsFromPlaylist(const std::string& url) -> std::vector<std::stri
|
|||||||
if (urls.empty()) printf("ERROR: Couldn't find any urls for playlist %s\n", url.c_str());
|
if (urls.empty()) printf("ERROR: Couldn't find any urls for playlist %s\n", url.c_str());
|
||||||
return urls;
|
return urls;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Playlist::dataFromYtdlpPlaylist(const std::string& data) -> 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;
|
|
||||||
}
|
|
||||||
|
|||||||
+5
-5
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <nlohmann/json_fwd.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -8,12 +9,11 @@ class Playlist {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Playlist(const std::string& playlistUrl);
|
Playlist(const std::string& playlistUrl);
|
||||||
auto download() -> bool;
|
auto rip(const std::string& musicFolder) -> bool;
|
||||||
auto writeMetadata() -> bool;
|
|
||||||
|
|
||||||
private:
|
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<std::string>;
|
auto urlsFromPlaylist(const std::string& url) -> std::vector<std::string>;
|
||||||
auto dataFromYtdlpPlaylist(const std::string& data) -> std::string;
|
|
||||||
auto playlistTitle() -> std::string;
|
|
||||||
auto channelNamePlaylist() -> std::string;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,12 +6,15 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
#include <format>
|
||||||
|
#include <fstream>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
// This runs in shell, if put through a website interface it would allow for injection
|
// This runs in shell, if put through a website interface it would allow for injection
|
||||||
auto ytdlp(const std::string& args) -> bool {
|
auto ytdlp(const std::string& args) -> bool {
|
||||||
system(std::format("bin/linux/yt-dlp {}", args).c_str());
|
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());
|
printf("Finished downloading video %s.\n", url.c_str());
|
||||||
return true;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <nlohmann/json_fwd.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
auto ytdlp(const std::string& args) -> bool;
|
auto ytdlp(const std::string& args) -> bool;
|
||||||
@@ -10,3 +11,8 @@ auto cleanTmpDownloadFolder() -> bool;
|
|||||||
auto downloadImageToTmpFolder(const std::string& url) -> bool;
|
auto downloadImageToTmpFolder(const std::string& url) -> bool;
|
||||||
|
|
||||||
auto downloadVideo(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;
|
||||||
|
|||||||
Reference in New Issue
Block a user