lyrics_finder 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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