lyrics_finder 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cc26dd72ab5b067f0b65825a0cf201814d78c435
4
+ data.tar.gz: 193e8cccb5a6017c1e6a064744bd24ab52763cda
5
+ SHA512:
6
+ metadata.gz: 979ecf3aa994a3091e79c9821d6fecc227f7286da1a728b6f314db0215971df116ec02bc3c63dc719989ca20f945b79c69953a181eb9b7483a9ff4aa98433071
7
+ data.tar.gz: 65747552f08a99b6e3935fdb7bffa1060fd1d99ff492cc7a0b8473d5a3ebba4f30e04f15c0f8ffbb9d852ad0844116a38f06307f31a9eb62fd6a5f65488d1c42
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.gitignore ADDED
@@ -0,0 +1,24 @@
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
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+
24
+ .idea
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format documentation
3
+ --format Nc
4
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ cache: bundler
3
+
4
+ rvm:
5
+ - ruby
6
+ - 2.1.0
7
+
8
+ notifications:
9
+ email:
10
+ recipients:
11
+ - dromveg@gmail.com
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in lyrics_finder.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,11 @@
1
+ guard 'rspec' do
2
+ # watch /lib/ files
3
+ watch(%r{^lib/(.+).rb$}) do |m|
4
+ "spec/#{m[1]}_spec.rb"
5
+ end
6
+
7
+ # watch /spec/ files
8
+ watch(%r{^spec/(.+).rb$}) do |m|
9
+ "spec/#{m[1]}.rb"
10
+ end
11
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Daniel Romero
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.
data/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # LyricsFinder [![Build Status](https://travis-ci.org/dnlR/lyrics_finder.svg?branch=master)](https://travis-ci.org/dnlR/lyrics_finder) [![Coverage Status](https://img.shields.io/coveralls/dnlR/lyrics_finder.svg)](https://coveralls.io/r/dnlR/lyrics_finder?branch=master) [![endorse](https://api.coderwall.com/dnlr/endorsecount.png)](https://coderwall.com/dnlr)
2
+
3
+ Simple library to search for song lyrics
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'lyrics_finder'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install lyrics_finder
18
+
19
+ ## Hello World!
20
+
21
+ Create an instance of `LyricsFinder::Fetcher`:
22
+
23
+ ```ruby
24
+ fetcher = LyricsFinder::Fetcher.new
25
+ ```
26
+
27
+ You can specify which websites are you going to get the lyrics from:
28
+
29
+ ```ruby
30
+ fetcher = LyricsFinder::Fetcher.new(:song_lyrics, :azlyrics)
31
+ ```
32
+
33
+ You can choose among the following:
34
+
35
+ - LyricsWikia
36
+ - SongLyrics
37
+ - AZLyrics
38
+
39
+ And search passing the author and the song title as parameters to `Fetcher#search`:
40
+
41
+ ```ruby
42
+ fetcher.search 'idina menzel', 'let it go'
43
+ ```
44
+ Which will return and array with all the verses of the song as strings, or `nil` if it cannot found the song in any of the websites.
45
+
46
+ ## Example
47
+
48
+ In your ruby apps:
49
+ ```ruby
50
+ require 'lyrics_finder'
51
+
52
+ fetcher = LyricsFinder::Fetcher.new
53
+ @song = fetcher.search 'idina menzel', 'let it go'
54
+ puts @song
55
+ ```
56
+
57
+ ## CLI
58
+
59
+ LyricsFinder is also available as a command-line tool.
60
+
61
+ $ lyricsfinder search -a 'idina menzel' -t 'let it go'
62
+
63
+ ## Changelog
64
+
65
+ v 0.0.1
66
+
67
+ - Initial release
68
+
69
+ ## Contributing
70
+
71
+ 1. Fork it ( https://github.com/[my-github-username]/lyrics_finder/fork )
72
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
73
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
74
+ 4. Push to the branch (`git push origin my-new-feature`)
75
+ 5. Create a new Pull Request
76
+
77
+ ## Credits
78
+
79
+ Inspired by [Lyricfy](https://github.com/javichito/Lyricfy).
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'rspec/core/rake_task'
2
+ require "bundler/gem_tasks"
3
+
4
+ # Run with 'rake spec'
5
+ RSpec::Core::RakeTask.new(:spec) do |task|
6
+ task.rspec_opts = ['--color', '--format documentation']
7
+ end
8
+
9
+ task :default => :spec
data/bin/lyricsfinder ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'lyrics_finder/cli'
3
+ LyricsFinder::CLI.start
@@ -0,0 +1,14 @@
1
+ require 'thor'
2
+ require 'lyrics_finder'
3
+
4
+ module LyricsFinder
5
+ class CLI < Thor
6
+ desc 'search -a Author -t Song Title', 'Search the lyrics for the specified author and title'
7
+ method_option 'author', :aliases => '-a', :type => :string
8
+ method_option 'title', :aliases => '-t', :type => :string
9
+ def search
10
+ fetcher = LyricsFinder::Fetcher.new
11
+ puts fetcher.search(options[:author], options[:title])
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ require 'open-uri'
2
+ require 'nokogiri'
3
+ require 'active_support/core_ext'
4
+ require 'i18n'
5
+ I18n.enforce_available_locales = false
6
+ require 'contracts'
7
+ include Contracts
8
+
9
+ require_relative 'version'
10
+ require_relative 'providers'
11
+ require_relative 'providers/lyrics_wikia'
12
+ require_relative 'providers/azlyrics'
13
+ require_relative 'providers/song_lyrics'
@@ -0,0 +1,19 @@
1
+ module LyricsFinder::Providers::Azlyrics
2
+ def format_url(author, title)
3
+ author = I18n.transliterate(author.strip.gsub(" ", ""))
4
+ title = I18n.transliterate(title.strip.gsub(" ", ""))
5
+ "http://www.azlyrics.com/lyrics/#{author}/#{title}.html"
6
+ end
7
+ module_function :format_url
8
+
9
+ def extract_lyric(data)
10
+ html = Nokogiri::HTML(data)
11
+ lyrics_container = html.css('div:nth-child(7)').first
12
+ unless lyrics_container.nil?
13
+ elements = lyrics_container.children.to_a
14
+ phrases = elements.select { |el| el.text? && el.text != "\n" && !el.blank? }
15
+ phrases.map! { |element| element.text.strip }
16
+ end
17
+ end
18
+ module_function :extract_lyric
19
+ end
@@ -0,0 +1,23 @@
1
+ module LyricsFinder::Providers::LyricsWikia
2
+ #Contract lambda { |a, s| !a.blank? && !s.blank? } => String
3
+ Contract String, String => String
4
+ def format_url(author, title)
5
+ author = I18n.transliterate(author.strip.gsub(" ", "_"))
6
+ title = I18n.transliterate(title.strip.gsub(" ", "_"))
7
+ "http://lyrics.wikia.com/#{author}:#{title}"
8
+ end
9
+ module_function :format_url
10
+
11
+ #Contract lambda { |x| x.is_a? Tempfile } => Module
12
+ Contract lambda { |x| x.is_a? Tempfile } => Array
13
+ def extract_lyric(data)
14
+ html = Nokogiri::HTML(data)
15
+ lyrics_container = html.css('.lyricbox').first
16
+ unless lyrics_container.nil?
17
+ elements = lyrics_container.children.to_a
18
+ phrases = elements.select { |el| el.text? && el.text != "\n" && !el.blank? }
19
+ phrases.map! { |element| element.text.strip }
20
+ end
21
+ end
22
+ module_function :extract_lyric
23
+ end
@@ -0,0 +1,19 @@
1
+ module LyricsFinder::Providers::SongLyrics
2
+ def format_url(author, title)
3
+ author = I18n.transliterate(author.strip.gsub(" ", "-"))
4
+ title = I18n.transliterate(title.strip.gsub(" ", "-"))
5
+ "http://www.songlyrics.com/#{author}/#{title}-lyrics/"
6
+ end
7
+ module_function :format_url
8
+
9
+ def extract_lyric(data)
10
+ html = Nokogiri::HTML(data)
11
+ lyrics_container = html.css('#songLyricsDiv').first
12
+ unless lyrics_container.nil?
13
+ elements = lyrics_container.children.to_a
14
+ phrases = elements.select { |el| el.text? && el.text != "\n" && !el.blank? }
15
+ phrases.map! { |element| element.text.strip }
16
+ end
17
+ end
18
+ module_function :extract_lyric
19
+ end
@@ -0,0 +1,8 @@
1
+ module LyricsFinder::Providers
2
+ Contract Symbol => Module
3
+ def build_klass(provider)
4
+ klass = "LyricsFinder::Providers::" + provider.to_s.camelize
5
+ klass.constantize
6
+ end
7
+ module_function :build_klass
8
+ end
@@ -0,0 +1,3 @@
1
+ module LyricsFinder
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,53 @@
1
+ require_relative 'lyrics_finder/dependencies'
2
+
3
+ module LyricsFinder
4
+ class Fetcher
5
+ PROVIDERS_LIST = [:lyrics_wikia, :song_lyrics, :azlyrics]
6
+ UsageError = Class.new(StandardError)
7
+ attr_reader :providers
8
+
9
+ def initialize(*args)
10
+ @providers = filter_providers(args)
11
+ end
12
+
13
+ def search(author, title)
14
+ validate_song_data(author, title)
15
+ song_lyric = catch(:song_lyric) {
16
+ @providers.each do |provider|
17
+ klass = Providers.build_klass(provider)
18
+ url = klass.format_url(author, title)
19
+
20
+ data = perform_request(url)
21
+ result = klass.extract_lyric(data) if data
22
+ throw :song_lyric, result unless result.nil?
23
+ end
24
+ }
25
+ # because if it doesn't find anything returns @providers by default
26
+ song_lyric != @providers ? song_lyric : nil
27
+ end
28
+
29
+ private
30
+
31
+ def filter_providers(providers)
32
+ valid_providers = []
33
+ providers.each do |provider|
34
+ valid_providers << provider if PROVIDERS_LIST.include?(provider)
35
+ end
36
+ valid_providers.any? ? valid_providers : PROVIDERS_LIST
37
+ end
38
+
39
+ def validate_song_data(author, title)
40
+ if author.blank? || title.blank?
41
+ fail UsageError, "You must supply a valid author and title"
42
+ end
43
+ end
44
+
45
+ def perform_request(url)
46
+ begin
47
+ open(url)
48
+ rescue Exception => ex
49
+ # puts "ERROR: " + ex.message
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'lyrics_finder/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'lyrics_finder'
8
+ spec.version = LyricsFinder::VERSION
9
+ spec.authors = ['Daniel Romero']
10
+ spec.email = ['dromveg@gmail.com']
11
+ spec.summary = %q{Solution for finding song lyrics}
12
+ spec.description = %q{Simple library for finding song lyrics}
13
+ spec.homepage = 'https://github.com/dnlR/lyrics_finder'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.6'
22
+ spec.add_development_dependency 'rake'
23
+
24
+ spec.add_development_dependency 'rspec', '~> 2.14.0'
25
+ spec.add_development_dependency 'rspec-nc', '0.0.6'
26
+ spec.add_development_dependency 'vcr', '2.9.2'
27
+ spec.add_development_dependency 'webmock', '1.18.0'
28
+ spec.add_development_dependency 'coveralls', '0.7.0'
29
+
30
+ spec.add_dependency 'nokogiri', '1.6.1'
31
+ spec.add_dependency 'activesupport', '4.1.1'
32
+ spec.add_dependency 'i18n', '0.6.9'
33
+ spec.add_dependency 'contracts', '0.4'
34
+ spec.add_dependency 'thor', '0.19.1'
35
+ end
@@ -0,0 +1,142 @@
1
+ describe LyricsFinder::Fetcher do
2
+ describe 'sets @providers properly on initialization' do
3
+ context 'without specifying providers' do
4
+ let(:fetcher) { LyricsFinder::Fetcher.new }
5
+
6
+ it 'sets @providers to default PROVIDERS_LIST' do
7
+ expect(fetcher.providers).to eq LyricsFinder::Fetcher::PROVIDERS_LIST
8
+ end
9
+ end
10
+
11
+ context 'specifying providers' do
12
+ context 'some providers are invalid' do
13
+ let(:fetcher) { LyricsFinder::Fetcher.new(:lyrics_wikia, :bad_songs) }
14
+
15
+ it 'filters invalid providers' do
16
+ expect(fetcher.providers).to match_array [:lyrics_wikia]
17
+ end
18
+ end
19
+
20
+ context 'all providers are invalid' do
21
+ let(:fetcher) { LyricsFinder::Fetcher.new(:bad_songs, :invalid_songs) }
22
+
23
+ it 'sets @providers to default PROVIDERS_LIST' do
24
+ expect(fetcher.providers).to eq LyricsFinder::Fetcher::PROVIDERS_LIST
25
+ end
26
+ end
27
+ end
28
+ end # 'initialization'
29
+
30
+ describe '#search' do
31
+ describe 'using LyricsWikia as the provider' do
32
+ context 'with a song that can be found' do
33
+ before :each do
34
+ @fetcher = LyricsFinder::Fetcher.new(:lyrics_wikia)
35
+ VCR.use_cassette 'LyricsWikia 200 search' do
36
+ @song = @fetcher.search("american authors", "best day of my life")
37
+ end
38
+ end
39
+
40
+ it 'returns an instance of Array' do
41
+ expect(@song.class).to eq Array
42
+ end
43
+
44
+ it 'returns the desired song' do
45
+ expect(@song).to eq LyricsWikiaSampleSongs::BEST_DAY_OF_MY_LIFE
46
+ end
47
+ end
48
+
49
+ # Searching for a song that exist but it's not yet on this website.
50
+ context 'with a song that cannot be found' do
51
+ before :each do
52
+ @fetcher = LyricsFinder::Fetcher.new(:lyrics_wikia)
53
+ VCR.use_cassette 'LyricsWikia Song does not exist search' do
54
+ @song = @fetcher.search("arctic monkeys", "do i wanna know")
55
+ end
56
+ end
57
+
58
+ it 'returns nil' do
59
+ expect(@song).to be nil
60
+ end
61
+ end
62
+ end
63
+
64
+ describe 'using Azlyrics as the provider' do
65
+ before :each do
66
+ @fetcher = LyricsFinder::Fetcher.new(:azlyrics)
67
+ VCR.use_cassette 'Azlyrics 200 search' do
68
+ @song = @fetcher.search("american authors", "best day of my life")
69
+ end
70
+ end
71
+
72
+ it 'returns an instance of Array' do
73
+ expect(@song.class).to eq Array
74
+ end
75
+
76
+ it 'returns the desired song' do
77
+ expect(@song).to eq AzlyricsSampleSongs::BEST_DAY_OF_MY_LIFE
78
+ end
79
+ end
80
+
81
+ describe 'using SongLyrics as the provider' do
82
+ before :each do
83
+ @fetcher = LyricsFinder::Fetcher.new(:song_lyrics)
84
+ VCR.use_cassette 'SongLyrics 200 search' do
85
+ @song = @fetcher.search("american authors", "best day of my life")
86
+ end
87
+ end
88
+
89
+ it 'returns an instance of Array' do
90
+ expect(@song.class).to eq Array
91
+ end
92
+
93
+ it 'returns the desired song' do
94
+ expect(@song).to eq SongLyricsSampleSongs::BEST_DAY_OF_MY_LIFE
95
+ end
96
+ end
97
+
98
+ # unfortunately lyrics mania doesn't return 404 if it does not find the song
99
+ # it just redirect to the root url www.lyricsmania.com
100
+ # describe 'using LyricsMania as the provider' do
101
+ # before :each do
102
+ # @fetcher = LyricsFinder::Fetcher.new(:lyrics_mania)
103
+ # VCR.use_cassette 'LyricsMania 200 search' do
104
+ # @song = @fetcher.search("american authors", "best day of my life")
105
+ # end
106
+ # end
107
+ #
108
+ # it 'returns an instance of Array' do
109
+ # expect(@song.class).to eq Array
110
+ # end
111
+ #
112
+ # it 'returns the desired song' do
113
+ # expect(@song).to eq LyricsManiaSampleSongs::BEST_DAY_OF_MY_LIFE
114
+ # end
115
+ # end
116
+
117
+ describe 'with a song that cannot be found' do
118
+ before :each do
119
+ @fetcher = LyricsFinder::Fetcher.new
120
+ VCR.use_cassette 'Nonexistent Song 404 search' do
121
+ @song = @fetcher.search("the foobar band", "rubynation")
122
+ end
123
+ end
124
+
125
+ it 'returns nil' do
126
+ expect(@song).to be nil
127
+ end
128
+ end
129
+
130
+ describe 'with invalid parameters' do
131
+ let(:fetcher) { LyricsFinder::Fetcher.new }
132
+
133
+ it 'fails with UsageError' do
134
+ expect{
135
+ fetcher.search("", "")
136
+ }.to raise_error( LyricsFinder::Fetcher::UsageError,
137
+ "You must supply a valid author and title")
138
+ end
139
+ end
140
+ end # '#search'
141
+
142
+ end