yt_mp3 0.0.1 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ notifications:
6
+ email: false
7
+ bundler_args: --without development
data/Gemfile CHANGED
@@ -3,3 +3,4 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in yt_mp3.gemspec
4
4
  gemspec
5
5
  gem 'rspec'
6
+ gem 'rake'
data/README.md CHANGED
@@ -1,29 +1,37 @@
1
- # YtMp3
1
+ # YTMp3 [![Build Status](https://secure.travis-ci.org/Kofel/yt_mp3.png)](http://travis-ci.org/Kofel/yt_mp3)
2
2
 
3
- Easily download YouTube videos as Mp3 with commandline tool!
3
+ Quickly download video from YouTube to mp3. Sync the folder with playlists or favorites!
4
4
 
5
5
  ## Installation
6
6
  $ gem install yt_mp3
7
7
 
8
8
  ## Usage
9
9
 
10
+ ###Just download
11
+
10
12
  $ yt_mp3 http://www.youtube.com/watch?v=DYyWVlh8NLM
13
+
14
+ ###Syncing
15
+ **syncing user favorites**
16
+
17
+ $ yt_mp3 init favorites kofels
18
+ $ yt_mp3 sync
19
+
20
+ **syncing playlist**
11
21
 
12
- ## YouTube MP3 API:
13
- This gem was build on top of [YouTube-Mp3.org](http://youtube-mp3.org). Every MP3 file convertion are made by them. There I've described an API:
22
+ $ yt_mp3 init playlist 39D3FA44E3F75572
23
+ $ yt_mp3 sync
24
+
25
+ **and when something has been pushed to playlist type**
14
26
 
15
- ### Request a video to mp3 convert:
16
- GET: http://www.youtube-mp3.org/api/pushItem/?item=#{video_url}&xy=yx&bf=false&r=#{Time.now.to_i}
17
- RESPONSE: video_id
27
+ $ yt_mp3 sync
18
28
 
19
- HTTParty.get("http://www.youtube-mp3.org/api/pushItem/?item=http%3A//www.youtube.com/watch%3Fv%3D41L3a0QUzwY%26feature%3Dg-all-u&xy=yx&bf=false&r=#{Time.now.to_i}").body
20
- => "41L3a0QUzwY"
29
+ ## YouTube MP3 API
30
+ This gem was build on top of [YouTube-Mp3.org](http://youtube-mp3.org).
21
31
 
22
- ### Get video info (we need it to get a hash). Repeat until status is "serving".
23
- GET: http://www.youtube-mp3.org/api/itemInfo/?video_id=#{video_id}&ac=www&r=#{Time.now.to_i}
24
- RESPONSE: info JSON fetched by response.body.match(/\Ainfo = (.*?);\z/)[1]
32
+ [There I've described an API](https://github.com/Kofel/yt_mp3/wiki/YouTube-MP3-API)
25
33
 
26
- HTTParty.get()
34
+ Please note that *yt_mp3* is not responsible for failed conversions. There are limitations ex. 15 convertions for 30 minutes.
27
35
 
28
36
  ## Contributing
29
37
 
data/bin/yt_mp3 CHANGED
@@ -1,28 +1,83 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'trollop'
4
-
5
3
  $:.unshift(File.join(File.dirname(__FILE__), "/../lib"))
6
4
  require "yt_mp3"
5
+ require "json"
7
6
 
8
- opts = Trollop::options do
9
- version "yt_mp3 #{YTMp3::VERSION} (c) 2012 #{YTMp3::AUTHORS.join(', ')}"
10
- banner <<-EOS
11
- USAGE: #{$0} [url]
7
+ banner = <<-EOS
8
+ yt_mp3 #{YTMp3::VERSION} (c) 2012 #{YTMp3::AUTHORS.join(', ')}
9
+ USAGE:
10
+ #{$0} [url]
11
+ OR:
12
+ initalize playlist sync:
13
+ #{$0} init playlist PLAYLIST_ID
14
+ initalize user favourite sync:
15
+ #{$0} init favorites USERNAME
16
+ and then:
17
+ #{$0} sync
12
18
  EOS
13
- end
14
19
 
15
20
  if ARGV.empty?
16
- STDERR.puts "You need to provide a URL"
17
- STDERR.puts "USAGE: #{$0} [url]"
21
+ STDERR.puts banner
18
22
  else
19
- mp3 = YTMp3::YouTubeMP3.new ARGV.first
20
- puts "Converting #{mp3.url}..."
21
- begin
22
- mp3.convert
23
- rescue Exception => e
24
- STDERR.puts e
25
- end
23
+ opts = ARGV.first
24
+
25
+ if opts == "--help" || opts == "-h"
26
+ puts banner
27
+ elsif opts == "init"
28
+ if ARGV[1] and ARGV[2]
29
+ options = {:synced => Array.new}
30
+
31
+ if ARGV[1] == "playlist"
32
+ options["playlist"] = ARGV[2]
33
+ puts "Playlist #{ARGV[2]} syncing initalized..."
34
+ elsif ARGV[1] == "favorites"
35
+ options["favorites"] = ARGV[2]
36
+ puts "User favorites \"#{ARGV[2]}\" syncing initalized..."
37
+ else
38
+ STDERR.puts banner
39
+ Kernel.exit
40
+ end
41
+
42
+ File.open(".yt_mp3.json","w") {|f| f.puts options.to_json}
43
+ else
44
+ STDERR.puts banner
45
+ end
46
+ elsif opts == "sync"
47
+ #begin
48
+ if File.exists?(".yt_mp3.json") && (options = JSON.parse(File.read(".yt_mp3.json")))
49
+ sync = nil
26
50
 
27
- system "curl --progress-bar -L \"#{mp3.downloadable}\" > \"#{mp3.title}\".mp3"
51
+ if options["playlist"]
52
+ sync = YTMp3::Sync.new :playlist => options["playlist"]
53
+ else
54
+ sync = YTMp3::Sync.new :favorites => options["favorites"]
55
+ end
56
+
57
+ sync.synced = options["synced"] || Array.new
58
+
59
+ if (n_count = sync.new_videos.count ) > 0
60
+ puts "Found #{n_count} new videos. Syncing..."
61
+ else
62
+ puts "Nothing to sync. Exiting."
63
+ Kernel.exit
64
+ end
65
+
66
+ options["synced"] = sync.sync do |mp3|
67
+ YTMp3::download_progress mp3
68
+ end
69
+
70
+ File.open(".yt_mp3.json","w") {|f| f.puts options.to_json}
71
+
72
+ puts "Syncing done."
73
+ else
74
+ STDERR.puts "Syncing not initialized yet. Please type:\n#{$1} init (...)"
75
+ end
76
+ #rescue Exception => e
77
+ # e.inspect
78
+ # STDERR.puts "Error found: #{e}\nPlease initalize syncing by:\n#{$1} init (...)"
79
+ #end
80
+ else
81
+ YTMp3::download_progress YTMp3::YouTubeMP3.new(opts)
82
+ end
28
83
  end
@@ -1,5 +1,8 @@
1
1
  require "yt_mp3/version"
2
2
  require "yt_mp3/youtube_mp3"
3
+ require "yt_mp3/sync"
4
+
5
+ require "yt_mp3/badge_progress_bar"
3
6
 
4
7
  module YTMp3
5
8
  def self.uri?(string)
@@ -11,7 +14,30 @@ module YTMp3
11
14
  false
12
15
  end
13
16
 
14
- class RequestFailed < StandardError; end
17
+ def self.download_progress(mp3)
18
+ puts ":: #{mp3.url}\n"
19
+
20
+ bar = BadgeProgressBar.new
21
+ bar.badge = "Converting"
15
22
 
16
- YOUTUBE_MP3_TIMEOUT = 90
23
+ begin
24
+ mp3.convert do |info|
25
+ bar.count = (info["progress"].to_f * 100).abs
26
+ bar.write
27
+ end
28
+
29
+ begin
30
+ mp3.download
31
+ rescue DownloadError => e
32
+ STDERR.puts "Failed to download. Video cannot be converted. Could not exists. (#{e})"
33
+ end
34
+ rescue RequestFailed => e
35
+ STDERR.puts e
36
+ end
37
+ end
38
+
39
+ class RequestFailed < StandardError; end
40
+ class DownloadError < StandardError; end
41
+ class SyncError < StandardError; end
17
42
  end
43
+
@@ -0,0 +1,21 @@
1
+ require "progress_bar"
2
+
3
+ module YTMp3
4
+ class BadgeProgressBar < ProgressBar
5
+ attr_accessor :badge
6
+
7
+ def initialize(*args)
8
+ super 100, :badge, :bar, :percentage, :elapsed
9
+ end
10
+
11
+ protected
12
+
13
+ def render_badge
14
+ @badge
15
+ end
16
+
17
+ def badge_width
18
+ @badge.length
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,37 @@
1
+ require 'youtube_it'
2
+
3
+ module YTMp3
4
+ class Sync
5
+ attr_reader :videos_playlist
6
+ attr_accessor :synced
7
+
8
+ def initialize(options)
9
+ client = YouTubeIt::Client.new
10
+ videos = {}
11
+
12
+ if options[:favorites]
13
+ videos = client.videos_by(:favorites, :user => options[:favorites]).videos
14
+ elsif options[:playlist]
15
+ videos = client.playlist(options[:playlist].gsub(/\APL/, "")).videos
16
+ else
17
+ raise SyncError, "Sync by what?"
18
+ end
19
+
20
+ @videos_playlist = videos.collect { |v| v.unique_id }
21
+ @synced = Array.new
22
+
23
+ raise SyncError, "Empty playlist to synchronize" if @videos_playlist.empty?
24
+ end
25
+
26
+ def new_videos
27
+ (@videos_playlist - @synced)
28
+ end
29
+
30
+ def sync
31
+ new_videos.each do |video|
32
+ @synced << video
33
+ yield YTMp3::YouTubeMP3.new(video)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,4 +1,4 @@
1
1
  module YTMp3
2
- VERSION = "0.0.1"
2
+ VERSION = "1.0"
3
3
  AUTHORS = ["Jakub Kaflik"]
4
4
  end
@@ -1,4 +1,3 @@
1
- require 'timeout'
2
1
  require 'httparty'
3
2
  require 'uri'
4
3
  require 'json'
@@ -13,27 +12,42 @@ module YTMp3
13
12
  end
14
13
 
15
14
  def convert
16
- r = HTTParty.get "http://www.youtube-mp3.org/api/pushItem/?item=#{URI.escape(@url)}&xy=yx&bf=false&r#{Time.now.to_i}"
15
+ r = HTTParty.get "http://www.youtube-mp3.org/api/pushItem/?item=#{CGI.escape(@url)}&xy=yx&bf=false&r=#{Time.now.to_i}", :headers => {"Accept-Location" => "*"}
17
16
 
18
- raise RequestFailed, "YouTubeMP3 service responsed: #{r.body}" unless r.response.class == Net::HTTPOK
17
+ raise RequestFailed, "Something went wrong (not HTTP OK)" unless r.response.class == Net::HTTPOK
18
+ handle_error(r.body)
19
19
 
20
20
  video_id = r.body
21
21
 
22
- Timeout::timeout(YOUTUBE_MP3_TIMEOUT) do
23
- while true
24
- r = HTTParty.get "http://www.youtube-mp3.org/api/itemInfo/?video_id=#{video_id}&ac=www&r=#{Time.now.to_i}"
22
+ while true
23
+ r = HTTParty.get "http://www.youtube-mp3.org/api/itemInfo/?video_id=#{video_id}&ac=www&r=#{Time.now.to_i}", :headers => {"Accept-Location" => "*"}
25
24
 
26
- raise RequestFailed, "YouTubeMP3 service responsed: #{r.body}" unless r.response.class == Net::HTTPOK
25
+ raise RequestFailed, "Something went wrong (not HTTP OK)" unless r.response.class == Net::HTTPOK
27
26
 
28
- info = JSON.parse(r.body.match(/\Ainfo = (.*?);\z/)[1])
27
+ info = JSON.parse(r.body.match(/\Ainfo = (.*?);\z/)[1])
29
28
 
30
- if info["status"] == "serving"
31
- @downloadable = "http://www.youtube-mp3.org/get?video_id=#{video_id}&h=#{info['h']}&r=#{Time.now.to_i}"
32
- @title = info["title"]
33
- break
34
- end
29
+ if info["status"] == "serving"
30
+ @downloadable = "http://www.youtube-mp3.org/get?video_id=#{video_id}&h=#{info['h']}&r=#{Time.now.to_i}"
31
+ @title = info["title"]
32
+ break
35
33
  end
36
- end
34
+
35
+ yield info if block_given?
36
+ end
37
+ end
38
+
39
+ def download
40
+ raise DownloadError, "File not converted yet" unless @downloadable
41
+ system "curl --progress-bar -L \"#{@downloadable}\" > \"#{@title.gsub(/\//,"-")}.mp3\""
42
+ end
43
+
44
+ protected
45
+
46
+ def handle_error( body )
47
+ case body
48
+ when "$$$LIMIT$$$" then raise RequestFailed, "YouTubeMP3 limit reached! Only 15 convertions per 30 minutes."
49
+ when "$$$ERROR$$$" then raise RequestFailed, "There was an Error caused by YouTube, we cannot deliver this Video! This error is mostly caused by copyright issues or the length of the video. YouTubeMP3 only support videos with maximum of 20 minutes."
50
+ end
37
51
  end
38
52
  end
39
53
  end
@@ -3,6 +3,13 @@ require 'bundler/setup'
3
3
 
4
4
  require 'yt_mp3' # and any other gems you need
5
5
 
6
- RSpec.configure do |config|
6
+ module Helpers
7
+ def temp
8
+ system("mkdir -p tmp")
9
+ Dir.chdir "tmp/"
10
+ end
11
+ end
7
12
 
13
+ RSpec.configure do |config|
14
+ config.include Helpers
8
15
  end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe YTMp3::Sync do
4
+ before do
5
+ temp
6
+ end
7
+
8
+ it "loads playlist" do
9
+ sync = YTMp3::Sync.new :playlist => "39D3FA44E3F75572"
10
+ sync.new_videos.count.should be > 0
11
+ end
12
+
13
+ it "loads playlist with prefix" do
14
+ sync = YTMp3::Sync.new :playlist => "PL39D3FA44E3F75572"
15
+ sync.new_videos.count.should be > 0
16
+ end
17
+
18
+ it "loads user favorites" do
19
+ sync = YTMp3::Sync.new :favorites => "SuchyKanal"
20
+ sync.new_videos.count.should be > 0
21
+ end
22
+
23
+ it "does sync" do
24
+ sync = YTMp3::Sync.new :playlist => "PL912D4D7B38309EAA"
25
+ sync.synced.count.should eq 0
26
+
27
+ new_videos = sync.new_videos
28
+
29
+ sync.sync do |mp3|
30
+ mp3.should be_an_instance_of YTMp3::YouTubeMP3
31
+ end
32
+
33
+ sync.synced.should eq new_videos
34
+ end
35
+ end
@@ -1,6 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe YTMp3::YouTubeMP3 do
4
+ before do
5
+ temp
6
+ end
7
+
4
8
  it "initialize by URL" do
5
9
  YTMp3::YouTubeMP3.new("http://www.youtube.com/watch?v=KlJy_Cb21Lw").url.should eq "http://www.youtube.com/watch?v=KlJy_Cb21Lw"
6
10
  end
@@ -20,4 +24,15 @@ describe YTMp3::YouTubeMP3 do
20
24
  mp3.convert
21
25
  mp3.title.should eq "Lady Antebellum - Need You Now (HQ) [Lyrics]"
22
26
  end
27
+
28
+ it "downloads" do
29
+ mp3 = YTMp3::YouTubeMP3.new("KlJy_Cb21Lw")
30
+ mp3.convert
31
+ mp3.download
32
+ end
33
+
34
+ it "cannot download while not converted" do
35
+ mp3 = YTMp3::YouTubeMP3.new("KlJy_Cb21Lw")
36
+ expect { mp3.download }.to raise_error(YTMp3::DownloadError)
37
+ end
23
38
  end
@@ -4,13 +4,14 @@ require File.expand_path('../lib/yt_mp3/version', __FILE__)
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = YTMp3::AUTHORS
6
6
  gem.email = ["kofels@gmail.com"]
7
- gem.description = %q{Simply download YT videos as mp3!}
8
- gem.summary = gem.description
7
+ gem.description = %q{Quickly download video from YouTube to mp3. Sync the folder with playlists or favorites!}
8
+ gem.summary = %q{Downloading YouTube videos as mp3}
9
9
  gem.homepage = "http://kofel.github.com/yt_mp3/"
10
10
 
11
11
  gem.rubyforge_project = "yt_mp3"
12
12
  gem.add_dependency "httparty"
13
- gem.add_dependency "trollop"
13
+ gem.add_dependency "youtube_it"
14
+ gem.add_dependency "progress_bar"
14
15
 
15
16
  gem.files = `git ls-files`.split($\)
16
17
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yt_mp3
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: '1.0'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-29 00:00:00.000000000 Z
12
+ date: 2012-06-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: httparty
@@ -28,7 +28,7 @@ dependencies:
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0'
30
30
  - !ruby/object:Gem::Dependency
31
- name: trollop
31
+ name: youtube_it
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  none: false
34
34
  requirements:
@@ -43,7 +43,24 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
- description: Simply download YT videos as mp3!
46
+ - !ruby/object:Gem::Dependency
47
+ name: progress_bar
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Quickly download video from YouTube to mp3. Sync the folder with playlists
63
+ or favorites!
47
64
  email:
48
65
  - kofels@gmail.com
49
66
  executables:
@@ -53,15 +70,19 @@ extra_rdoc_files: []
53
70
  files:
54
71
  - .gitignore
55
72
  - .rspec
73
+ - .travis.yml
56
74
  - Gemfile
57
75
  - LICENSE
58
76
  - README.md
59
77
  - Rakefile
60
78
  - bin/yt_mp3
61
79
  - lib/yt_mp3.rb
80
+ - lib/yt_mp3/badge_progress_bar.rb
81
+ - lib/yt_mp3/sync.rb
62
82
  - lib/yt_mp3/version.rb
63
83
  - lib/yt_mp3/youtube_mp3.rb
64
84
  - spec/spec_helper.rb
85
+ - spec/sync_spec.rb
65
86
  - spec/youtube_mp3_spec.rb
66
87
  - yt_mp3.gemspec
67
88
  homepage: http://kofel.github.com/yt_mp3/
@@ -87,7 +108,8 @@ rubyforge_project: yt_mp3
87
108
  rubygems_version: 1.8.22
88
109
  signing_key:
89
110
  specification_version: 3
90
- summary: Simply download YT videos as mp3!
111
+ summary: Downloading YouTube videos as mp3
91
112
  test_files:
92
113
  - spec/spec_helper.rb
114
+ - spec/sync_spec.rb
93
115
  - spec/youtube_mp3_spec.rb