Youtube music and video downloader

App.jsx 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import React, { Component, PropTypes } from 'react';
  2. import { Meteor } from 'meteor/meteor';
  3. import { createContainer } from 'meteor/react-meteor-data';
  4. import { Converted } from '../api/links';
  5. import Links from './Links';
  6. import { YouTubeSearch, YouTubeVideoInfo } from './YouTubeAPI';
  7. import Video from './Video';
  8. import Input from "./Input";
  9. import Results from "./Results";
  10. import OptionsAll from "./OptionsAll";
  11. class App extends Component {
  12. constructor(props) {
  13. super(props);
  14. this.state = { result: [], links: [], value: '' };
  15. this.options = [
  16. { type: 'MP3', handler: (video) => window.open('/mp3/'+ video.id) },
  17. { type: 'MP4', handler: (video) => window.open('/mp4/'+ video.id) },
  18. ];
  19. this.optionsAll = [
  20. { type: 'MP3', handler: () => window.open(`/mp3/batch/${this.batchLinks()}`) },
  21. { type: 'MP4', handler: () => window.open(`/mp4/batch/${this.batchLinks()}`) },
  22. ];
  23. }
  24. render() {
  25. return (
  26. <div className="container">
  27. <h1 className="logo">SoundWave</h1>
  28. <div className="box-container">
  29. <header>
  30. <Input value={this.state.value} change={this.inputChange.bind(this)} />
  31. <Results results={this.state.result} select={this.selectResult.bind(this)} />
  32. </header>
  33. <Links links={this.state.links} remove={this.removeLink.bind(this)} handlers={this.options}/>
  34. <OptionsAll count={this.state.links.length} handlers={this.optionsAll}
  35. links={this.state.links} converted={this.props.converted} />
  36. </div>
  37. </div>
  38. );
  39. }
  40. batchLinks() {
  41. return this.state.links.map(e => e.id).join(',');
  42. }
  43. inputChange(text) {
  44. this.setState({ value: text }, this.search);
  45. }
  46. removeLink(link) {
  47. if (_.some(this.state.links, e => e.id === link.id))
  48. this.setState({ links: _.reject(this.state.links, e => e.id === link.id) });
  49. }
  50. selectResult(video) {
  51. if (_.every(this.state.links, e => e.id !== video.id)) {
  52. if (_.some(this.props.converted, e => e.id === video.id)) {
  53. video.converted = _.find(this.props.converted, e => e.id === video.id)._id;
  54. } else
  55. Meteor.call('links.add', {video, type: 'audio'}, (err, res) => {
  56. if (err)
  57. console.error(err);
  58. else
  59. video.converted = _.find(this.props.converted, e => e.id === video.id)._id;
  60. });
  61. this.setState({links: [...this.state.links, video]});
  62. }
  63. this.setState({ value: '', result: [] });
  64. }
  65. search() {
  66. if (!this.state.value) {
  67. this.setState({ result: [] });
  68. } else {
  69. YouTubeSearch(this.state.value)
  70. .then(e => e.items.map(e => new Video(e)))
  71. .then(e => { this.setState({ result: e }); return e; })
  72. .then(e => e.forEach(i => YouTubeVideoInfo(i.id)
  73. .then(r => i.update(r.items[0].statistics, r.items[0].contentDetails.duration))
  74. .then(() => this.setState({ result: e }))
  75. ));
  76. }
  77. }
  78. }
  79. App.propTypes = {
  80. converted: PropTypes.array.isRequired,
  81. };
  82. export default createContainer(() => {
  83. Meteor.subscribe('links');
  84. return {
  85. converted: Converted.find({}).fetch(),
  86. };
  87. }, App)