You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
343 lines
10 KiB
343 lines
10 KiB
|
|
#include "libtorrent/session.hpp" |
|
#include "libtorrent/torrent_handle.hpp" |
|
#include "libtorrent/magnet_uri.hpp" |
|
|
|
#include <iostream> |
|
#include <fstream> |
|
#include <string> |
|
#include <sstream> |
|
|
|
#include <vector> |
|
#include <thread> |
|
#include <chrono> |
|
#include <memory> |
|
|
|
#include <ncurses.h> |
|
void canvas() { |
|
initscr(); |
|
raw(); |
|
keypad(stdscr, TRUE); |
|
noecho(); |
|
|
|
int ch; |
|
while (ch != 27 && ch != 'q') { // 27 = ESC |
|
printw("Type any character to see it in bold\n"); |
|
ch = getch(); |
|
if(ch == 22) { // ctrl+v |
|
printw("copy pasta pressed\n"); |
|
} else { |
|
printw("The pressed key is "); |
|
attron(A_BOLD); |
|
printw("%i\n", ch); |
|
attroff(A_BOLD); |
|
} |
|
refresh(); |
|
} |
|
endwin(); |
|
} |
|
|
|
void read_alerts(std::vector<lt::alert*> &alerts) { |
|
for (lt::alert const* a : alerts) { |
|
// alert examples on libtorrent do not work. |
|
// https://www.libtorrent.org/tutorial-ref.html |
|
// results in: compilation error - incomplete type |
|
// type code referenced from: |
|
// ./deps/libtorrent/include/libtorrent/alert_types.hpp |
|
switch (a -> type()) { |
|
default: |
|
std::cout << a -> message() << ", " << a -> type() << std::endl; |
|
// case 11: // tracker unreachable |
|
// case 67: // torrent added |
|
// case 23: |
|
// case 26: // torrent finished alert |
|
// case 64: // torrent error alert |
|
} |
|
} |
|
return; |
|
} |
|
|
|
std::vector<std::string> readfile(std::string manifest) { |
|
std::vector<std::string> out; |
|
std::fstream fin; |
|
fin.open(manifest); |
|
std::string line; |
|
if (!fin.is_open()) { |
|
fprintf(stderr, "Error: could not open file.\n"); |
|
} |
|
while (fin) { |
|
std::getline(fin, line); |
|
out.push_back(line); |
|
} |
|
return out; |
|
} |
|
|
|
void display(lt::torrent_status &ts) { |
|
// <download_rate> downloading <name> from <num_peers> (<num seeds> seeds) |
|
// <upload rate> uploading <name> to <num_peers> (<num seeds> seeds) |
|
// fuck cout |
|
static char last_state = 0; |
|
// don't bother line breaking for checks and meta data' |
|
if (last_state != ts.state && last_state > 3) { |
|
std::cout << std::endl; |
|
} |
|
// long names will spam console |
|
#define MAX_LENGTH 40 |
|
std::string shortname; |
|
if (ts.name.length() > MAX_LENGTH) { |
|
shortname = ts.name.substr(0, MAX_LENGTH); |
|
} else { |
|
shortname = ts.name; |
|
} |
|
const char *tname = shortname.c_str(); |
|
float perc = ts.progress * 100; |
|
float down = ts.download_rate/1000000; |
|
float up = ts.upload_rate/1000000; |
|
std::int64_t total_upload = ts.total_upload/1000000; |
|
switch(ts.state) { |
|
case 1: // checking files |
|
break; |
|
case 2: // downloading meta data |
|
break; |
|
case 3: // downloading |
|
fprintf(stdout, "[%2.2f%] Downloading %s from %i peers (%i seeds) @ %2.2f MB/s\r", |
|
perc, tname, ts.num_peers, ts.num_seeds, down); |
|
break; |
|
case 4: // finished |
|
break; |
|
case 5: // seeding |
|
fprintf(stdout, "Uploading %s to %i/%i peers (%i seeds) @ %2.2f MB/s [%i MB]\r", |
|
tname, ts.num_peers, ts.list_peers, ts.list_seeds, up, total_upload); |
|
break; |
|
} |
|
last_state = ts.state; |
|
} |
|
|
|
// run torrents in the background |
|
void seedbox (std::string &torrentfiles) { |
|
#define MINUTE 60 |
|
lt::session s; |
|
// magnet link version |
|
// lt::add_torrent_params params = lt::parse_magnet_uri(magnet_link); |
|
// params.save_path = "."; // save in current dir |
|
// lt::torrent_handle h = s.add_torrent(params); |
|
std::vector<lt::torrent_handle> handles; |
|
std::vector<std::string> torrents = readfile(torrentfiles.c_str()); |
|
if (torrents.empty()) { |
|
return; |
|
} |
|
std::string torrent; |
|
for (unsigned int i = 0; i < torrents.size(); ++i) { |
|
torrent = torrents[i]; |
|
if (torrent.length() < 2) { // less than 1 char and newline |
|
continue; |
|
} |
|
lt::add_torrent_params p; |
|
p.save_path = "./downloaded"; |
|
try { |
|
p.ti = std::make_shared<lt::torrent_info>(torrent); |
|
} catch (std::exception const&e) { |
|
std::cerr << "Encountered error while reading torrent files (" |
|
<< torrent |
|
<< ").\n" |
|
<< e.what() << std::endl; |
|
return; |
|
} |
|
handles.push_back(s.add_torrent(p)); |
|
} |
|
// std::vector<std::string> maglinks = readfile(magnetlinks.c_str()); |
|
char c; |
|
const int TORRENT_COUNT = handles.size(); |
|
unsigned int not_dl_count = 0; |
|
unsigned int tid = 0; |
|
unsigned int elapsed = 0; |
|
while(c != 'q') { |
|
std::vector<lt::alert*> alerts; |
|
s.pop_alerts(&alerts); |
|
read_alerts(alerts); |
|
for (unsigned int i = 0; i < TORRENT_COUNT; ++i) { |
|
lt::torrent_status ts = handles[i].status(); |
|
if (!ts.is_seeding && !ts.is_finished) { |
|
not_dl_count++; |
|
} |
|
} |
|
// if no torrents are downloading |
|
if (!(TORRENT_COUNT > not_dl_count)) { |
|
lt::torrent_status spotlight = handles[tid].status(); |
|
display(spotlight); |
|
if (elapsed >= MINUTE) { |
|
std::cout << std::endl; |
|
tid = (tid + 1) % TORRENT_COUNT; |
|
} |
|
} |
|
elapsed = (elapsed + 1) % (MINUTE + 1); |
|
std::this_thread::sleep_for(std::chrono::seconds(1)); |
|
} |
|
} |
|
|
|
#include <curlpp/cURLpp.hpp> |
|
#include <curlpp/Easy.hpp> |
|
#include <curlpp/Options.hpp> |
|
std::string request(const std::string& url) { |
|
curlpp::options::Url source (url); |
|
curlpp::Easy request; |
|
request.setOpt(source); |
|
std::ostringstream response; |
|
try { |
|
response << request; |
|
} catch (curlpp::LibcurlRuntimeError e) { |
|
std::cout << e.what() << std::endl; |
|
} catch (std::exception const& e) { |
|
std::cout << e.what() << std::endl; |
|
} |
|
return response.str(); |
|
} |
|
|
|
#include "libtorrent/create_torrent.hpp" |
|
#include "libtorrent/entry.hpp" |
|
#include "libtorrent/bencode.hpp" |
|
#include "peertube.hpp" // also includes rapidjson |
|
|
|
// watch a video given a URL |
|
void watch(std::string video_url) { |
|
//turn peertube video url into api request |
|
bool is_playlist = false; |
|
std::string api = get_endpoint(video_url, is_playlist); |
|
std::string got = request(api); |
|
std::cout << api << std::endl; |
|
rapidjson::Document root; |
|
root.Parse(got.c_str()); |
|
|
|
// figure something out with playlists. |
|
if (is_playlist) { |
|
std::cout << "playlist support not implemented" << std::endl; |
|
return; |
|
} |
|
|
|
// video downloads can either be in "files" |
|
// or under "streamingPlaylists" if HLS is enabled on the server |
|
const rapidjson::Value& vf = get_video_files(root); |
|
std::string magnet_link = get_magnet_link(vf); |
|
lt::session s; |
|
lt::add_torrent_params params = lt::parse_magnet_uri(magnet_link); |
|
params.save_path = "./downloaded"; |
|
lt::torrent_handle h = s.add_torrent(params); |
|
lt::torrent_status ts; |
|
do { |
|
std::vector<lt::alert*> alerts; |
|
s.pop_alerts(&alerts); |
|
read_alerts(alerts); |
|
ts = h.status(); |
|
display(ts); |
|
std::this_thread::sleep_for(std::chrono::seconds(1)); |
|
} while (!ts.is_seeding && !ts.is_finished); |
|
std::cout << std::endl; |
|
// prompt user to save torrent file? |
|
// reference: |
|
// https://github.com/steeve/libtorrent/blob/master/examples/client_test.cpp#L880 |
|
// char response; |
|
// std::cout << "Save file? [Y/n]" << std::endl; |
|
// std::cin >> response; |
|
// if (response == 'y' || response == 'Y') { |
|
// save_torrent(h); |
|
// } |
|
return; |
|
} |
|
|
|
void test (std::string video_url) { |
|
bool is_playlist; |
|
std::string api = get_endpoint(video_url, is_playlist); |
|
std::string got = request(api); |
|
std::cout << got.length() << std::endl; |
|
rapidjson::Document root; |
|
root.Parse(got.c_str()); |
|
const rapidjson::Value& vf = get_video_files(root); |
|
for (rapidjson::SizeType i = 0; i < vf.Size(); ++i) { |
|
struct file_t *test = init_from_json(vf[i]); |
|
if (test != NULL) { |
|
file_print(test); |
|
file_free(test); |
|
} |
|
} |
|
} |
|
|
|
// download torrent file from peertube server |
|
std::string dl_torrentfile(struct file_t *video_file, const char * title = NULL) { |
|
if (video_file == NULL) { |
|
return std::string(); |
|
} |
|
if (video_file -> attribs == NULL) { |
|
return std::string(); |
|
} |
|
std::string torrent_url (video_file -> attribs[TORRENTDOWNLOAD_URL]); |
|
std::string buffer = request(torrent_url); |
|
std::string filename; |
|
{ |
|
std::stringstream ss; |
|
if (title != NULL) { |
|
ss << title <<"-"<< video_file -> resolution << "p.torrent"; |
|
} else { // use the file name from the url |
|
unsigned int pos = torrent_url.rfind("/"); |
|
pos++; // +1 to omit '/' |
|
ss << torrent_url.substr(pos, torrent_url.size()); |
|
} |
|
filename = ss.str(); |
|
std::cout << filename << std::endl; |
|
} |
|
std::fstream fout; |
|
fout.open (filename, std::fstream::out | std::fstream::binary); |
|
if (fout.good()) { |
|
fout << buffer; |
|
} |
|
fout.close(); |
|
return filename; |
|
} |
|
|
|
void test2 (std::string video_url) { |
|
bool is_playlist; |
|
std::string api = get_endpoint(video_url, is_playlist); |
|
std::string got = request(api); |
|
// std::cout << api << std::endl; |
|
rapidjson::Document root; |
|
root.Parse(got.c_str()); |
|
struct video_t *video = init_from_json(root); |
|
// get torrent download rul |
|
int highest_res = 0; |
|
struct file_t *best_file = video_pick_file(video); |
|
std::string saved = dl_torrentfile(best_file, video -> name); |
|
if (!saved.empty()) { |
|
std::cout << "acquired .torrent file! " << std::endl; |
|
} |
|
std::cout << "\n\n\n" << std::endl; |
|
video_print(video); |
|
video_free(video); |
|
} |
|
|
|
|
|
int main(int argc, char const* argv[]) { |
|
std::cout << "This is cppia (unreleased)." << std::endl; |
|
if (argc != 3) { |
|
fprintf(stderr, "usage: %s <.txt list of torrents>\n", argv[0]); |
|
return 1; |
|
} |
|
// std::cout << "Press 'q' to quit and 'h' for more options." << std::endl; |
|
std::string s(argv[2]); |
|
// add real argument parsing later. |
|
int option = atoi(argv[1]); |
|
switch (option) { |
|
case 0: |
|
seedbox(s); |
|
break; |
|
case 1: |
|
watch(s); |
|
break; |
|
case 2: |
|
test2(s); |
|
break; |
|
} |
|
|
|
// API generated by openapi doesn't compile.' |
|
// apiClient_t* peertube = apiClient_create(); |
|
// apiClient_free(peertube); |
|
return 0; |
|
}
|
|
|