Skip to content

Instantly share code, notes, and snippets.

@su8
Last active December 7, 2025 02:23
Show Gist options
  • Select an option

  • Save su8/91f6a0753fa9f68f2d5e1220fd99bc5b to your computer and use it in GitHub Desktop.

Select an option

Save su8/91f6a0753fa9f68f2d5e1220fd99bc5b to your computer and use it in GitHub Desktop.
yt-dl.cpp
//g++ youtube_downloader.cpp -o youtube_downloader -lcurl
#include <iostream>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <array>
#include <memory>
#include <stdexcept>
#include <sys/stat.h>
#include <curl/curl.h>
// Function to execute a shell command and capture its output
std::string execCommand(const std::string &cmd) {
std::array<char, 256> buffer{};
std::string result;
FILE *pipe = popen(cmd.c_str(), "r");
if (!pipe) throw std::runtime_error("Failed to run command");
while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
result += buffer.data();
}
pclose(pipe);
return result;
}
// Callback for libcurl to write data to file
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
return fwrite(ptr, size, nmemb, stream);
}
// Progress callback for libcurl
int progress_callback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t, curl_off_t) {
if (dltotal > 0) {
double progress = (double)dlnow / (double)dltotal * 100.0;
std::cout << "\rDownloading: " << (int)progress << "% (" << dlnow / 1024 << " KB / " << dltotal / 1024 << " KB)" << std::flush;
}
return 0; // return non-zero to abort
}
// Get file size if exists (for resume)
long getFileSize(const std::string &filename) {
struct stat st;
if (stat(filename.c_str(), &st) == 0) {
return st.st_size;
}
return 0;
}
int main(int argc, char *argv[]) {
if (argc < 2) { std::cout << argv[0] << " requires argument with the yt video link." << std::endl; return EXIT_FAILURE; }
std::string youtubeURL = argv[1];
if (youtubeURL.empty()) {
std::cerr << "Error: No URL provided.\n";
return EXIT_FAILURE;
}
try {
// Step 1: Get direct video URL using yt-dlp
std::string cmd = "yt-dlp -g \"" + youtubeURL + "\" 2>/dev/null";
std::string directURL = execCommand(cmd);
// Remove trailing newline
if (!directURL.empty() && directURL.back() == '\n') {
directURL.pop_back();
}
if (directURL.empty()) {
std::cerr << "Error: Could not retrieve direct video URL.\n";
return EXIT_FAILURE;
}
std::cout << "Direct video URL retrieved:\n" << directURL << "\n";
// Step 2: Download the file using libcurl
CURL *curl = curl_easy_init();
if (!curl) {
std::cerr << "Error: Could not initialize libcurl.\n";
return EXIT_FAILURE;
}
const char *outputFile = "video.mp4";
// Step 3: Resume support
long existingSize = getFileSize(outputFile);
FILE *fp = fopen(outputFile, existingSize > 0 ? "ab" : "wb");
if (!fp) {
std::cerr << "Error: Could not open file for writing.\n";
return EXIT_FAILURE;
}
curl_easy_setopt(curl, CURLOPT_URL, directURL.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0");
// Resume from existing size
if (existingSize > 0) {
std::cout << "Resuming from " << existingSize / 1024 << " KB...\n";
curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, (curl_off_t)existingSize);
}
// Progress bar
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
std::cerr << "Download failed: " << curl_easy_strerror(res) << "\n";
} else {
std::cout << "Download completed successfully: " << outputFile << "\n";
}
fclose(fp);
curl_easy_cleanup(curl);
} catch (const std::exception &e) {
std::cerr << "Exception: " << e.what() << "\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment