torrenting.hpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. #ifndef TORRENT_HTP
  2. #define TORRENT_HPP
  3. #include "libtorrent/session.hpp"
  4. #include "libtorrent/torrent_handle.hpp"
  5. #include "libtorrent/magnet_uri.hpp"
  6. #include <string>
  7. #include <vector>
  8. #include <iostream>
  9. #include <sstream>
  10. #include <vector>
  11. #include <thread>
  12. #include <chrono>
  13. #include <memory>
  14. void read_alerts(std::vector<lt::alert*> &alerts) {
  15. for (lt::alert const* a : alerts) {
  16. // alert examples on libtorrent do not work.
  17. // https://www.libtorrent.org/tutorial-ref.html
  18. // results in: compilation error - incomplete type
  19. // type code referenced from:
  20. // ./deps/libtorrent/include/libtorrent/alert_types.hpp
  21. switch (a -> type()) {
  22. default:
  23. std::cout << a -> message() << ", " << a -> type() << std::endl;
  24. // case 11: // tracker unreachable
  25. // case 67: // torrent added
  26. // case 23:
  27. // case 26: // torrent finished alert
  28. // case 64: // torrent error alert
  29. }
  30. }
  31. return;
  32. }
  33. std::vector<std::string> readfile(std::string manifest) {
  34. std::vector<std::string> out;
  35. std::fstream fin;
  36. fin.open(manifest);
  37. std::string line;
  38. if (!fin.is_open()) {
  39. fprintf(stderr, "Error: could not open file.\n");
  40. }
  41. while (fin) {
  42. std::getline(fin, line);
  43. out.push_back(line);
  44. }
  45. return out;
  46. }
  47. std::string scrolling_str(std::string s, const unsigned int LEN_MAX) {
  48. static int i = 0;
  49. std::string shorter;
  50. if (s.length() > LEN_MAX) {
  51. if ((i + LEN_MAX) < s.length()) {
  52. try {
  53. shorter = s.substr(i, LEN_MAX);
  54. } catch (std::out_of_range const &e) {
  55. ;
  56. }
  57. i = (i + 1) % s.length();
  58. } else {
  59. i = 0;
  60. }
  61. } else {
  62. shorter = s;
  63. }
  64. return shorter;
  65. }
  66. void display(lt::torrent_status &ts) {
  67. // <download_rate> downloading <name> from <num_peers> (<num seeds> seeds)
  68. // <upload rate> uploading <name> to <num_peers> (<num seeds> seeds)
  69. // fuck cout
  70. static char last_state = 0;
  71. // don't bother line breaking for checks and meta data'
  72. if (last_state != ts.state) {
  73. std::cout << std::endl;
  74. }
  75. // long names will spam console
  76. #define MAX_LENGTH 40
  77. std::string shortname = scrolling_str(ts.name, MAX_LENGTH);
  78. const char *tname = shortname.c_str();
  79. float perc = ts.progress * 100;
  80. float down = ts.download_rate/1000000;
  81. float up = ts.upload_rate/1000000;
  82. std::int64_t total_upload = ts.total_upload/1000000;
  83. switch(ts.state) {
  84. case 1: // checking files
  85. fprintf(stdout, "checking files\r");
  86. break;
  87. case 2: // downloading meta data
  88. fprintf(stdout, "downloading meta data\r");
  89. break;
  90. case 3: // downloading
  91. fprintf(stdout, "[%2.2f%] Downloading %s from %i peers (%i seeds) @ %2.2f MB/s\r",
  92. perc, tname, ts.num_peers, ts.num_seeds, down);
  93. break;
  94. case 4: // finished
  95. break;
  96. case 5: // seeding
  97. fprintf(stdout, "Uploading %s to %i/%i peers (%i seeds) @ %2.2f MB/s [%i MB]\r",
  98. tname, ts.num_peers, ts.list_peers, ts.list_seeds, up, total_upload);
  99. break;
  100. }
  101. last_state = ts.state;
  102. }
  103. // magnet link version
  104. // lt::add_torrent_params params = lt::parse_magnet_uri(magnet_link);
  105. // params.save_path = "."; // save in current dir
  106. // lt::torrent_handle h = s.add_torrent(params);
  107. // torrents = paths to .torrent files
  108. void init_torrents(lt::session &s, const std::vector<std::string>& torrents) {
  109. std::string torrent;
  110. for (unsigned int i = 0; i < torrents.size(); ++i) {
  111. torrent = torrents[i];
  112. if (torrent.length() < 2) { // less than 1 char and newline
  113. continue;
  114. }
  115. lt::add_torrent_params p;
  116. p.save_path = "./downloaded";
  117. try {
  118. p.ti = std::make_shared<lt::torrent_info>(torrent);
  119. } catch (std::exception const&e) {
  120. std::cerr << "Encountered error while reading torrent files ("
  121. << torrent
  122. << ").\n"
  123. << e.what() << std::endl;
  124. return;
  125. }
  126. s.add_torrent(p);
  127. }
  128. }
  129. // run torrents in the background
  130. void seedbox (std::string &torrentfiles) {
  131. #define MINUTE 60000
  132. lt::session s;
  133. std::vector<std::string> paths = readfile(torrentfiles.c_str());
  134. if (paths.empty()) {
  135. return;
  136. }
  137. init_torrents(s, paths);
  138. std::vector<lt::torrent_handle> handles = s.get_torrents();
  139. const int TORRENT_COUNT = handles.size();
  140. unsigned int not_dl_count = 0;
  141. unsigned int tid = 0;
  142. unsigned int elapsed = 0;
  143. while(true) {
  144. std::vector<lt::alert*> alerts;
  145. s.pop_alerts(&alerts);
  146. read_alerts(alerts);
  147. for (unsigned int i = 0; i < TORRENT_COUNT; ++i) {
  148. lt::torrent_status ts = handles[i].status();
  149. if (!ts.is_seeding && !ts.is_finished) {
  150. not_dl_count++;
  151. }
  152. }
  153. // if no torrents are downloading
  154. if (!(TORRENT_COUNT > not_dl_count)) {
  155. lt::torrent_status spotlight = handles[tid].status();
  156. display(spotlight);
  157. if (elapsed >= MINUTE) {
  158. std::cout << std::endl;
  159. tid = (tid + 1) % TORRENT_COUNT;
  160. }
  161. }
  162. elapsed = (elapsed + 1) % (MINUTE + 1);
  163. std::this_thread::sleep_for(std::chrono::milliseconds(50));
  164. // std::this_thread::sleep_for(std::chrono::seconds(1));
  165. }
  166. }
  167. #include <curlpp/cURLpp.hpp>
  168. #include <curlpp/Easy.hpp>
  169. #include <curlpp/Options.hpp>
  170. std::string request(const std::string& url) {
  171. curlpp::options::Url source (url);
  172. curlpp::Easy request;
  173. request.setOpt(source);
  174. std::ostringstream response;
  175. try {
  176. response << request;
  177. } catch (curlpp::LibcurlRuntimeError e) {
  178. std::cout << e.what() << std::endl;
  179. } catch (std::exception const& e) {
  180. std::cout << e.what() << std::endl;
  181. }
  182. return response.str();
  183. }
  184. // #include "libtorrent/create_torrent.hpp"
  185. // #include "libtorrent/entry.hpp"
  186. // #include "libtorrent/bencode.hpp"
  187. #include "peertube.hpp" // also includes rapidjson
  188. void torrent_basic_loop(std::string torrent_file) {
  189. lt::session s;
  190. lt::add_torrent_params p;
  191. p.save_path = "./downloaded";
  192. p.ti = std::make_shared<lt::torrent_info>(torrent_file);
  193. lt::torrent_handle h = s.add_torrent(p);
  194. h.set_flags(lt::torrent_flags::sequential_download);
  195. lt::torrent_status ts;
  196. do {
  197. std::vector<lt::alert*> alerts;
  198. s.pop_alerts(&alerts);
  199. read_alerts(alerts);
  200. ts = h.status();
  201. display(ts);
  202. std::this_thread::sleep_for(std::chrono::seconds(1));
  203. } while (!ts.is_seeding && !ts.is_finished);
  204. }
  205. // download torrent file from peertube server
  206. std::string dl_torrentfile(struct file_t *video_file, const char * title = NULL) {
  207. if (video_file == NULL) {
  208. return std::string();
  209. }
  210. if (video_file -> attribs == NULL) {
  211. return std::string();
  212. }
  213. std::string torrent_url (video_file -> attribs[TORRENTDOWNLOAD_URL]);
  214. std::string buffer = request(torrent_url);
  215. std::string filename;
  216. {
  217. std::stringstream ss;
  218. if (title == NULL) { // use the file name from the url
  219. unsigned int pos = torrent_url.rfind("/");
  220. pos++; // +1 to omit '/'
  221. ss << torrent_url.substr(pos, torrent_url.size());
  222. } else {
  223. // does not remove forbidden characters in file name yet
  224. ss << title <<"-"<< video_file -> resolution << "p.torrent";
  225. }
  226. filename = ss.str();
  227. std::cout << filename << std::endl;
  228. }
  229. std::fstream fout;
  230. fout.open (filename, std::fstream::out | std::fstream::binary);
  231. if (fout.good()) {
  232. fout << buffer;
  233. }
  234. fout.close();
  235. return filename;
  236. }
  237. // watch a video given a URL
  238. bool watch(std::string video_url) {
  239. //turn peertube video url into api request
  240. bool is_playlist = false;
  241. std::string api = get_endpoint(video_url, is_playlist);
  242. if (api.length() == 0) {
  243. std::cout << "Error: can't watch video." << std::endl;
  244. return false;
  245. }
  246. // figure something out with playlists.
  247. if (is_playlist) {
  248. std::cout << "playlist support not implemented" << std::endl;
  249. return false;
  250. }
  251. std::string got = request(api);
  252. std::cout << api << std::endl;
  253. rapidjson::Document root;
  254. root.Parse(got.c_str());
  255. // video downloads can either be in "files"
  256. // or under "streamingPlaylists" if HLS is enabled on the server
  257. struct video_t *video = init_from_json(root);
  258. video_print(video);
  259. // get torrent download url
  260. struct file_t *best_file = video_pick_file(video);
  261. // torrent file > magnet link if peertube instance's tracker is unreliable
  262. std::string saved = dl_torrentfile(best_file);
  263. if (!saved.empty()) {
  264. std::cout << "acquired .torrent file! " << saved << std::endl;
  265. torrent_basic_loop(saved);
  266. }
  267. std::cout << "\n\n\n" << std::endl;
  268. video_free(video);
  269. return true;
  270. }
  271. #endif