Added CMakeLists.txt to File-Downloader
This commit is contained in:
7
CMakeLists.txt
Normal file
7
CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
add_library(FileDownloader SHARED downloader.cpp console.cpp)
|
||||
|
||||
target_include_directories(FileDownloader
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_SOURCE_DIR})
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 ezBinary
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
23
Makefile
Normal file
23
Makefile
Normal file
@@ -0,0 +1,23 @@
|
||||
# Makefile for FileDownloader project
|
||||
# Works on macOS & linux
|
||||
|
||||
CC = g++
|
||||
FLAGS = -Wall -std=c++11
|
||||
LIBS = -lcurl
|
||||
|
||||
all: FileDownloader
|
||||
|
||||
FileDownloader: main.o downloader.o console.o
|
||||
$(CC) $(FLAGS) $^ -o $@ $(LIBS)
|
||||
|
||||
main.o: main.cpp
|
||||
$(CC) $(FLAGS) -c $<
|
||||
|
||||
downloader.o: downloader.cpp
|
||||
$(CC) $(FLAGS) -c $<
|
||||
|
||||
console.o: console.cpp
|
||||
$(CC) $(FLAGS) -c $<
|
||||
|
||||
clean:
|
||||
rm -f *.o FileDownloader
|
||||
79
README.md
Normal file
79
README.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# File Downloader
|
||||
A simple File Downloader using C++ and libcURL.
|
||||
|
||||
## Table of Contents
|
||||
- [Introduction](#introduction)
|
||||
- [Features](#features)
|
||||
- [Compilation](#compilation)
|
||||
- [Contributions](#contributions)
|
||||
- [License](#license)
|
||||
- [Feedback](#feedback)
|
||||
|
||||
## Introduction
|
||||
The File Downloader is a C++ project developed using the libcURL library. It facilitates downloading files from provided URLs using the cURL library and provides real-time download progress information, including download speed, percentage completion, and total download size.
|
||||
|
||||
<img width="1061" alt="screenshot_filedownloader" src="https://github.com/ezBinary/File-Downloader/assets/164413461/3a934709-5c81-4125-ba4a-a9a2396e7f6c">
|
||||
|
||||
## Features
|
||||
- Downloads files from provided URLs using cURL.
|
||||
- Displays real-time download progress, including percentage completion and download speed.
|
||||
- Provides a simple and easy to use command line interface for downloading files.
|
||||
|
||||
## How to Use
|
||||
1. **Input URL**: Provide the download link of the file you want to download.
|
||||
2. **Start Download**: Press enter to initiate the download process.
|
||||
3. **Monitor Progress**: Monitor the download progress, including the percentage completed and the download speed.
|
||||
4. **Completion**: Once the download is complete, the file will be available for use.
|
||||
|
||||
## Why File Downloader?
|
||||
File Downloader was developed as a training project to learn more about the capabilities of the cURL and enhance understanding of network programming in C++. It aims to provide a practical example for those interested in integrating file downloading functionality into their projects.
|
||||
|
||||
## Compilation
|
||||
|
||||
To use File Downloader, simply clone the repository and compile the source code using your preferred C++ compiler. Ensure that you have the libcURL library installed on your system.
|
||||
|
||||
### Compiling with Different Compilers
|
||||
|
||||
File Downloader can be compiled using various compilers on different platforms. Below are instructions for compiling the project with commonly used compilers:
|
||||
|
||||
#### 1. g++
|
||||
|
||||
```bash
|
||||
g++ main.cpp downloader.cpp console.cpp -o FileDownloader -lcurl
|
||||
```
|
||||
|
||||
#### 2. clang++
|
||||
|
||||
```bash
|
||||
clang++ main.cpp downloader.cpp console.cpp -o FileDownloader -lcurl
|
||||
```
|
||||
|
||||
#### 3. Microsoft Visual C++ (MSVC)
|
||||
|
||||
```bash
|
||||
cl /EHsc main.cpp downloader.cpp console.cpp /link /out:FileDownloader.exe
|
||||
```
|
||||
|
||||
### Platform Compatibility
|
||||
|
||||
This project's Makefile is designed to work seamlessly on both macOS and Linux systems. Below are instructions on how to use it :
|
||||
|
||||
To compile the project on macOS and Linux systems, simply navigate to the project directory in the terminal and run the `make` command. This will compile the source files and generate the executable `FileDownloader`.
|
||||
|
||||
---
|
||||
|
||||
Feel free to let me know if you need any further modifications!
|
||||
|
||||
## Contributions
|
||||
Contributions to File Downloader are welcome! Feel free to fork the repository, make improvements, and submit pull requests.
|
||||
|
||||
## License
|
||||
This project is licensed under the [MIT License](LICENSE). Feel free to use and modify it according to your needs.
|
||||
|
||||
## Disclaimer
|
||||
File Downloader is provided as-is, without any warranties or guarantees. I am not liable for any damages or issues arising from the use of this software.
|
||||
|
||||
## Feedback
|
||||
If you have any feedback, suggestions, or issues, please feel free to [open an issue](https://github.com/ezBinary/File-Downloader/issues) or [contact me](mailto:ez.like.binary@proton.me). I appreciate your input!
|
||||
|
||||
Enjoy using File Downloader for your file downloading needs!
|
||||
8
common.h
Normal file
8
common.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <curl/curl.h>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <iomanip>
|
||||
54
console.cpp
Normal file
54
console.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "console.h"
|
||||
#include <string>
|
||||
#include <regex>
|
||||
// Check the validate URL format
|
||||
bool isValidURL(const std::string& url)
|
||||
{
|
||||
// Regular expression to validate URL format
|
||||
std::regex urlRegex("(https?|ftp)://[^\\s/$.?#].[^\\s]*");
|
||||
return std::regex_match(url, urlRegex);
|
||||
}
|
||||
|
||||
// Get a valid URL from the user
|
||||
std::string console::getValidURL() {
|
||||
std::string url;
|
||||
|
||||
while (true)
|
||||
{
|
||||
std::cout << "Enter the URL or 'q' to quit: ";
|
||||
std::getline(std::cin, url);
|
||||
|
||||
if (url == "q" || url == "Q") {
|
||||
std::cout << "Input cancelled." << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (isValidURL(url)) {
|
||||
return url;
|
||||
}
|
||||
|
||||
std::cout << "Invalid URL format. Please enter a valid URL or 'q' to cancel." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Print Stylish Progress Bar
|
||||
void console::drawStylishProgressBar(double progress, int width) {
|
||||
int completedBlocks = static_cast<int>(progress * width);
|
||||
int remainingBlocks = width - completedBlocks;
|
||||
int i;
|
||||
// Clear previous output
|
||||
std::cout << "\r" << std::flush;
|
||||
|
||||
// Print new progress bar
|
||||
std::cout << "[";
|
||||
|
||||
for (i = 0; i < completedBlocks; ++i) {
|
||||
std::cout << "\u2588"; // Full block Unicode character
|
||||
}
|
||||
|
||||
for (i = 0; i < remainingBlocks; ++i) {
|
||||
std::cout << "\u2591"; // Light shade Unicode character
|
||||
}
|
||||
|
||||
std::cout << "] " << std::fixed << std::setprecision(0) << (progress * 100) << "%" << std::flush;
|
||||
}
|
||||
10
console.h
Normal file
10
console.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
|
||||
bool isValidURL(const std::string& url) ;
|
||||
|
||||
namespace console
|
||||
{
|
||||
std::string getValidURL();
|
||||
void drawStylishProgressBar(double progress, int width);
|
||||
}
|
||||
149
downloader.cpp
Normal file
149
downloader.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
#include "downloader.h"
|
||||
|
||||
// Convert bytes to human readable format
|
||||
std::string formatBytes(curl_off_t bytes)
|
||||
{
|
||||
|
||||
static const char *suffixes[] = {"B", "KB", "MB", "GB", "TB"};
|
||||
int suffixIndex = 0;
|
||||
double adjustedBytes = static_cast<double>(bytes);
|
||||
|
||||
while (adjustedBytes >= 1024 && suffixIndex < sizeof(suffixes) / sizeof(suffixes[0]) ) {
|
||||
adjustedBytes /= 1024.0;
|
||||
suffixIndex++;
|
||||
}
|
||||
|
||||
return std::to_string(adjustedBytes) + " " + suffixes[suffixIndex];
|
||||
}
|
||||
|
||||
// Progress callback function
|
||||
int FileDownloader::progressCallback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
|
||||
{
|
||||
std::string SpeedStr;
|
||||
DownloadProgress *progress = static_cast<DownloadProgress*>(clientp);
|
||||
double percent;
|
||||
double speed;
|
||||
|
||||
// Update progress data
|
||||
progress->bytesDownloaded = dlnow;
|
||||
progress->totalSize = dltotal;
|
||||
|
||||
// Calculate download completion percentage
|
||||
percent = (dltotal > 0) ? (dlnow * 100.0 / dltotal) : 0.0;
|
||||
|
||||
// Calculate download speed
|
||||
auto elapsedTime = std::chrono::steady_clock::now() - progress->startTime;
|
||||
speed = progress->bytesDownloaded / (std::chrono::duration_cast<std::chrono::milliseconds>(elapsedTime).count() / 1000.0); // bytes per second
|
||||
|
||||
// Clear previous progress bar
|
||||
std::cout << "\r";
|
||||
|
||||
// Display progress bar
|
||||
console::drawStylishProgressBar(percent / 100.0,50);
|
||||
|
||||
// Display download size information
|
||||
std::cout << " (" << formatBytes(progress->bytesDownloaded) << " of " << formatBytes(progress->totalSize) << ")";
|
||||
|
||||
// Display download speed
|
||||
SpeedStr = " | Speed: " + formatBytes(speed) + "/s ";
|
||||
std::cout << SpeedStr.c_str();
|
||||
|
||||
std::cout.flush(); // Ensure immediate output
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool FileDownloader::Downloader()
|
||||
{
|
||||
CURL *curl = curl_easy_init();
|
||||
DownloadProgress progress;
|
||||
CURLcode res;
|
||||
FILE *file;
|
||||
|
||||
if (!curl) {
|
||||
std::cerr << "Error initializing curl." << std::endl;
|
||||
return false;
|
||||
}
|
||||
// Set the URL
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
|
||||
// Set progress callback function
|
||||
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &progress);
|
||||
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progressCallback);
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); // Enable progress data
|
||||
|
||||
// Open file hanndle for writing
|
||||
file = fopen(filename.c_str(), "wb");
|
||||
if (!file) {
|
||||
std::cerr << "Error opening file for writing" << std::endl;
|
||||
curl_easy_cleanup(curl);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set file as the target for the download
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
|
||||
|
||||
// Record start time
|
||||
progress.startTime = std::chrono::steady_clock::now();
|
||||
|
||||
// Perform the request
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
// Check for errors
|
||||
if (res != CURLE_OK)
|
||||
{
|
||||
std::cerr << "\ncurl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
|
||||
return false;
|
||||
} else
|
||||
{
|
||||
std::cout << "\nDownload completed successfully!" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FileDownloader::FileDownloader(const std::string& i_url) : url(i_url), curl(nullptr), file(nullptr)
|
||||
{
|
||||
// Initialize libcurl
|
||||
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
|
||||
{
|
||||
std::cerr << "Error initializing libcurl." << std::endl;
|
||||
}
|
||||
|
||||
std::size_t found = url.find_last_of("/");
|
||||
if (found != std::string::npos)
|
||||
{
|
||||
filename = url.substr(found + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// invalid URL without filename
|
||||
std::cerr << "Error: Invalid URL format." << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FileDownloader::~FileDownloader()
|
||||
{
|
||||
// close curl handle
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
// close file handle
|
||||
|
||||
fclose(file);
|
||||
|
||||
// If the download process was unsuccessful, simply delete the corrupted downloaded file.
|
||||
if(!check)
|
||||
{
|
||||
std::remove(filename.c_str());
|
||||
}
|
||||
|
||||
// close global init
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
void FileDownloader::download()
|
||||
{
|
||||
check = FileDownloader::Downloader();
|
||||
}
|
||||
35
downloader.h
Normal file
35
downloader.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "console.h"
|
||||
|
||||
|
||||
class FileDownloader {
|
||||
private:
|
||||
// Struct to encapsulate download progress data
|
||||
struct DownloadProgress {
|
||||
curl_off_t bytesDownloaded;
|
||||
curl_off_t totalSize;
|
||||
std::chrono::steady_clock::time_point startTime;
|
||||
|
||||
DownloadProgress() : bytesDownloaded(0), totalSize(0), startTime(std::chrono::steady_clock::now()) {}
|
||||
};
|
||||
|
||||
|
||||
std::string url;
|
||||
std::string filename;
|
||||
CURL* curl;
|
||||
FILE* file;
|
||||
|
||||
bool check;
|
||||
bool Downloader();
|
||||
static int progressCallback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);
|
||||
|
||||
public:
|
||||
|
||||
|
||||
|
||||
FileDownloader(const std::string& xurl);
|
||||
~FileDownloader();
|
||||
|
||||
void download();
|
||||
};
|
||||
Reference in New Issue
Block a user