youtube-searcher 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8da9d76a91ca3d6ebc73b681e5909233ef2a8f49
4
+ data.tar.gz: a47c1ac70a86a62afc87f6475ce3255c9fd4d360
5
+ SHA512:
6
+ metadata.gz: 56f7e3f4500cee625864fe7cb1842596aa943ad09731dc95ebdc5c35e7beae341cff6084a127e0b0020cc491b259bd1701503a7cbc85554772283ac782a82201
7
+ data.tar.gz: 07eabde63daac26a804692eb63e9d128a9d060a4a6de6b70189763843618bebca0829b557c877fdb01b4c0679cc6d1f23fbebc5d29743507ba15e02c4a45db7e
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .gem/*
19
+ api_key
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in youtube-searcher.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Aziz Light
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,23 @@
1
+ # Youtube::Searcher
2
+
3
+ Search Youtube from the command line and download videos using `youtube-dl`.
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ > gem install youtube-searcher
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```
14
+ > yts --help
15
+ ```
16
+
17
+ ## Contributing
18
+
19
+ 1. Fork it ( http://github.com/<my-github-username>/youtube-searcher/fork )
20
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
21
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
22
+ 4. Push to the branch (`git push origin my-new-feature`)
23
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/yts ADDED
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "optparse"
4
+ require 'open3'
5
+ require "rainbow/ext/string"
6
+ require "ruby-progressbar"
7
+
8
+ require_relative "../lib/youtube-searcher"
9
+
10
+ config = YoutubeSearcher::Config.instance.config
11
+ audio_only = false
12
+
13
+ parser = OptionParser.new do |opts|
14
+ opts.banner = "Usage: yts [options] <query>"
15
+
16
+ opts.separator ""
17
+ opts.separator "Options:"
18
+
19
+ opts.on("-m", "--max-results=[NUM]", "Maximum number of search results") do |num|
20
+ config[:max_results] = num.to_i.to_s if num.to_i > 0
21
+ end
22
+
23
+ opts.on("-d", "--dir=[DIR]", "Download directory") do |dir|
24
+ config[:download_directory] = dir
25
+ end
26
+
27
+ opts.on("-a", "--audio-only", "Download the audio only") do
28
+ audio_only = true
29
+ end
30
+
31
+ opts.on("--audio-quality=[QUALITY]", "Audio quality (0-9, 0 being the best)") do |quality|
32
+ config[:audio_quality] = quality
33
+ end
34
+
35
+ opts.on("--audio-format=[FORMAT]", "Audio format (best/aac/vorbis/mp3/m4a/opus/wav)") do |format|
36
+ config[:audio_format] = format
37
+ end
38
+
39
+ opts.on("--no-download", "Just search") do
40
+ config[:always_download] = false
41
+ end
42
+
43
+ opts.on_tail("-h", "--help", "Show this help message") do
44
+ puts opts
45
+
46
+ puts
47
+ puts "Config file:"
48
+ puts "\tOptions can be made persistent using a config file (#{File.join(ENV["HOME"], ".ytsrc")})"
49
+ puts
50
+ puts "\tYou can generate a default config file by running:"
51
+ puts
52
+ puts "\t\t yts --config-gen"
53
+
54
+ exit
55
+ end
56
+
57
+ opts.on_tail("-v", "--version", "Show version") do
58
+ puts "yts #{YoutubeSearcher::VERSION}"
59
+ exit
60
+ end
61
+
62
+ opts.on_tail("--config-gen", "Generate a config file in the home directory") do
63
+ config_file = File.join(ENV["HOME"], ".ytsrc")
64
+ if File.file?(config_file)
65
+ puts "You already have a config file!".color(:red)
66
+ status_code = 1
67
+ else
68
+ YoutubeSearcher::Config.instance.generate
69
+ puts "Generated a config file: #{config_file}".color(:green)
70
+ status_code = 0
71
+ end
72
+
73
+ exit status_code
74
+ end
75
+ end
76
+
77
+ parser.parse! ARGV
78
+
79
+ client = YoutubeSearcher::Client.instance
80
+ videos = client.search(ARGV.join(" "), max_results: config[:max_results])
81
+
82
+ videos.each_with_index do |video, index|
83
+ index = config[:always_download] ? "#{(index + 1).to_s.background(:yellow).foreground(:black)} " : ""
84
+ puts index + video[:title]
85
+ puts "\t#{video[:url]}"
86
+ end
87
+
88
+ if config[:always_download]
89
+ def which(cmd)
90
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
91
+
92
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
93
+ exts.each { |ext|
94
+ exe = File.join(path, "#{cmd}#{ext}")
95
+ return exe if File.executable? exe
96
+ }
97
+ end
98
+
99
+ return nil
100
+ end
101
+
102
+ unless which("youtube-dl")
103
+ puts "`youtube-dl` not found!".color(:red)
104
+ exit 1
105
+ end
106
+
107
+ unless which("ffmpeg") && audio_only
108
+ puts "`ffmpeg` not found!".color(:red)
109
+ exit 1
110
+ end
111
+
112
+ def prompt(message)
113
+ m = "\n==> ".color(:yellow)
114
+ m << "#{message}"
115
+ m << "\n==> ".color(:yellow)
116
+ m << ("=" * message.length)
117
+ m << "\n==> ".color(:yellow)
118
+ m
119
+ end
120
+
121
+ print prompt "Enter n° of videos to download (space separated. ex: 1 2 3)"
122
+ indices = $stdin.gets.chomp.split(" ").map { |i| i.to_i - 1 }
123
+
124
+ unless indices.empty?
125
+ output_dir = "#{config[:download_directory]}/%(title)s.%(ext)s"
126
+
127
+ urls = Array.new
128
+
129
+ indices.each do |index|
130
+ unless videos[index].nil?
131
+ urls << videos[index][:url]
132
+ end
133
+ end
134
+
135
+ if urls.empty?
136
+ puts "Invalid video numbers...".color(:red)
137
+ exit 1
138
+ end
139
+
140
+ puts "Downloading videos...\n".color(:green)
141
+ progressbar = ProgressBar.create(:starting_at => 20, :total => nil)
142
+
143
+ urls.map! { |url| "\"#{url}\"" }
144
+ cmd = "youtube-dl -o '#{output_dir}' "
145
+ cmd << "-x " if audio_only
146
+ cmd << "--audio-quality #{config[:audio_quality]} "
147
+ cmd << "--audio-format '#{config[:audio_format]}' "
148
+ cmd << urls.join(" ")
149
+
150
+ status_code = 0
151
+ Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
152
+ stop = false
153
+ Signal.trap('SIGCHLD') do
154
+ stop = true
155
+ progressbar.stop
156
+ end
157
+
158
+ counter = 0
159
+ until stop
160
+ progressbar.increment if counter % 2000000 == 0
161
+ counter += 1
162
+ end
163
+
164
+ status_code = wait_thr.value.exitstatus
165
+ end
166
+
167
+ if status_code == 0
168
+ puts "\nVideos downloaded!".color(:green)
169
+ else
170
+ puts "\nAn error occured...".color(:red)
171
+ end
172
+
173
+ exit status_code
174
+ end
175
+ end
@@ -0,0 +1,6 @@
1
+ require_relative "./youtube-searcher/version"
2
+ require_relative "./youtube-searcher/config"
3
+ require_relative "./youtube-searcher/client"
4
+
5
+ module YoutubeSearcher
6
+ end
@@ -0,0 +1,51 @@
1
+ require "singleton"
2
+ require "google/api_client"
3
+
4
+ module YoutubeSearcher
5
+ class Client
6
+ include Singleton
7
+
8
+ APPLICATION_NAME = "Youtube Searcher"
9
+ YOUTUBE_API_SERVICE_NAME = "youtube"
10
+ YOUTUBE_API_VERSION = "v3"
11
+
12
+ def search(query, max_results: 20)
13
+ parameters = Hash.new
14
+ parameters[:part] = "id,snippet"
15
+ parameters[:type] = "video"
16
+ parameters[:maxResults] = max_results
17
+ parameters[:q] = query
18
+
19
+ response = client.execute!(
20
+ api_method: youtube.search.list,
21
+ parameters: parameters
22
+ )
23
+
24
+ videos = Array.new
25
+
26
+ response.data.items.each do |result|
27
+ video = Hash.new
28
+ video[:title] = result.snippet.title
29
+ video[:url] = "http://www.youtube.com/watch?v=#{result.id.videoId}"
30
+
31
+ videos << video
32
+ end
33
+
34
+ videos
35
+ end
36
+
37
+ def client
38
+ @client ||= Google::APIClient.new(key: api_key, authorization: nil, application_name: APPLICATION_NAME, application_version: YoutubeSearcher::VERSION)
39
+ end
40
+
41
+ def youtube
42
+ @youtube ||= @client.discovered_api(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION)
43
+ end
44
+
45
+ private
46
+
47
+ def api_key
48
+ @api_key ||= File.read(File.join(File.expand_path(__dir__), "..", "..", "api_key"))
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,39 @@
1
+ require "psych"
2
+ require "singleton"
3
+ require "erb"
4
+
5
+ class YoutubeSearcher::Config
6
+ include Singleton
7
+
8
+ CONFIG_FILE = ".ytsrc"
9
+
10
+ def config
11
+ @config ||= Psych.load(raw).inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo }
12
+ end
13
+ alias_method :get, :config
14
+
15
+ def generate
16
+ default_config = raw.gsub(/download_directory.*\n/, "download_directory: \"#{ENV["HOME"]}\"\n")
17
+ File.open(File.join(ENV["HOME"], ".ytsrc"), "w") do |f|
18
+ f.puts default_config
19
+ end
20
+ end
21
+
22
+ def raw
23
+ @raw ||= ERB.new(File.read(config_file)).result
24
+ end
25
+
26
+ private
27
+
28
+ def config_file
29
+ unless @config_file
30
+ if File.file?(File.join(ENV["HOME"], CONFIG_FILE))
31
+ @config_file = File.join(ENV["HOME"], CONFIG_FILE)
32
+ else
33
+ @config_file = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "ytsrc"))
34
+ end
35
+ end
36
+
37
+ @config_file
38
+ end
39
+ end
@@ -0,0 +1,3 @@
1
+ module YoutubeSearcher
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'youtube-searcher/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "youtube-searcher"
8
+ spec.version = YoutubeSearcher::VERSION
9
+ spec.authors = ["Aziz Light"]
10
+ spec.email = ["aziz@azizlight.me"]
11
+ spec.summary = %q{Search Youtube from the command line and download videos using `youtube-dl`.}
12
+ spec.homepage = "https://github.com/AzizLight/youtube-searcher"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.5"
20
+ spec.add_development_dependency "rake"
21
+ spec.add_runtime_dependency "google-api-client"
22
+ spec.add_runtime_dependency "rainbow"
23
+ spec.add_runtime_dependency "ruby-progressbar"
24
+ end
data/ytsrc ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ max_results: 20
3
+ download_directory: "<%= Dir.getwd %>"
4
+ audio_quality: 7
5
+ audio_format: "mp3"
6
+ always_download: true
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: youtube-searcher
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Aziz Light
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: google-api-client
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rainbow
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: ruby-progressbar
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description:
84
+ email:
85
+ - aziz@azizlight.me
86
+ executables:
87
+ - yts
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - Gemfile
93
+ - LICENSE
94
+ - README.md
95
+ - Rakefile
96
+ - bin/yts
97
+ - lib/youtube-searcher.rb
98
+ - lib/youtube-searcher/client.rb
99
+ - lib/youtube-searcher/config.rb
100
+ - lib/youtube-searcher/version.rb
101
+ - youtube-searcher.gemspec
102
+ - ytsrc
103
+ homepage: https://github.com/AzizLight/youtube-searcher
104
+ licenses:
105
+ - MIT
106
+ metadata: {}
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 2.2.0
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: Search Youtube from the command line and download videos using `youtube-dl`.
127
+ test_files: []