Youtube music and video downloader

links.js 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import { Meteor } from 'meteor/meteor';
  2. import { Mongo } from 'meteor/mongo';
  3. import { check, Match } from 'meteor/check';
  4. export const Converted = new Mongo.Collection('links');
  5. const YTExp = /http(?:s?):\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-_]*)/;
  6. if (Meteor.isServer) {
  7. Meteor.publish('links', function linksPublication() {
  8. return Converted.find();
  9. });
  10. }
  11. const convert = (url, filename, id) => {
  12. if (Meteor.isServer) {
  13. console.log('Converting ...');
  14. const fs = Meteor.npmRequire("fs");
  15. const ytdl = Meteor.npmRequire('ytdl-core');
  16. const path = Meteor.npmRequire('path');
  17. const ffmpeg = Meteor.npmRequire('fluent-ffmpeg');
  18. const filePath = path.resolve('/home/kod3/projects/SoundWave/uploaded/', filename)
  19. const videoPath = filePath + '.mp4';
  20. const audioPath = filePath + '.mp3';
  21. ytdl.getInfo(url, {}, Meteor.bindEnvironment((err, info) => {
  22. console.info(info ? 'ok' : 'ko');
  23. if (err) {
  24. console.log(url);
  25. console.error(err);
  26. Converted.update({ _id: id }, { $set: {
  27. error_video: 'Video is unreachable',
  28. error_audio: 'Video is unreachable',
  29. } });
  30. } else {
  31. const totalSeconds = info ? info.length_seconds : 0;
  32. const dl = ytdl(url);
  33. dl.pipe(fs.createWriteStream(videoPath));
  34. ffmpeg(dl)
  35. .noVideo()
  36. .on('end', Meteor.bindEnvironment(() => {
  37. Converted.update({ _id: id }, { $set: { audio: filename + '.mp3', audio_progress: 100 } });
  38. }))
  39. .on('progress', Meteor.bindEnvironment((params) => {
  40. const time = moment(new Date(...[0, 0, 0, ...params.timemark.split(':')]));
  41. const seconds = time.hours() * 3600 + time.minutes() * 60 + time.seconds();
  42. let percent = ((seconds / totalSeconds) * 100).toFixed(0);
  43. Converted.update({ _id: id }, { $set: { audio_progress: percent } });
  44. }))
  45. .on('error', Meteor.bindEnvironment((err) => {
  46. console.error('MP3 encoding error: ' + err.message);
  47. Converted.update({ _id: id }, { $set: { error_audio: 'Audio cannot be extracted' } });
  48. }))
  49. .format('mp3')
  50. .output(fs.createWriteStream(audioPath))
  51. .run();
  52. dl.on('info', (info, format) => console.log);
  53. dl.on('response', Meteor.bindEnvironment((res) => {
  54. const totalSize = res.headers['content-length'];
  55. let dataRead = 0;
  56. res.on('data', Meteor.bindEnvironment((data) => {
  57. dataRead += data.length;
  58. let percent = dataRead / totalSize;
  59. Converted.update({ _id: id }, { $set: { video_progress: (percent * 100).toFixed(0) } });
  60. }));
  61. res.on('end', Meteor.bindEnvironment(() => {
  62. Converted.update({ _id: id }, { $set: { video: filename + '.mp4', video_progress: 100 } });
  63. }));
  64. res.on('error', Meteor.bindEnvironment((err) => {
  65. console.error('Error: ' + err.message)
  66. Converted.update({ _id: id }, { $set: { error_video: 'Video cannot be saved' } });
  67. }));
  68. }));
  69. }
  70. }));
  71. } else return false;
  72. };
  73. Meteor.methods({
  74. 'links.add'({video, type}) {
  75. check(video.url, Match.Where(url => YTExp.test(url)));
  76. check(type, Match.Where(t => ['audio'].includes(t)));
  77. let converted = Converted.findOne({
  78. url: video.url,
  79. error_audio: { $ne: null },
  80. error_video: { $ne: null },
  81. });
  82. if (!converted) {
  83. const filename = video.title.replace(/ /g, '_');
  84. Converted.remove({url: video.url});
  85. var inserted_id = Converted.insert({
  86. id: video.id,
  87. url: video.url,
  88. title: video.title,
  89. video: '',
  90. video_progress: 0,
  91. error_video: '',
  92. audio: '',
  93. audio_progress: 0,
  94. error_audio: '',
  95. createdAt: new Date()
  96. });
  97. convert(video.url, filename, inserted_id);
  98. }
  99. },
  100. });