├── lyricaly ├── __init__.py └── __main__.py ├── MANIFEST.in ├── setup.py ├── LICENSE ├── README.rst ├── .gitignore ├── README.md └── lyricaly.py /lyricaly/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.rst 3 | setup.py 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | from setuptools import setup 3 | setup( 4 | name='lyricaly', 5 | packages=["lyricaly"], 6 | version='1.0.5', 7 | author='Vignesh M', 8 | author_email='vigzmv@outlook.com', 9 | url='https://github.com/vigzmv/Lyricaly', 10 | download_url='https://github.com/vigzmv/Lyricaly', 11 | license='MIT License', 12 | description='Lyricaly Gets Lyrics directly to your Terminal.', 13 | long_description=open('README.rst').read(), 14 | zip_safe=False, 15 | keywords='lyrics vigzmv music songs lyricaly vignesh m', 16 | install_requires = ['beautifulsoup','beautifulsoup4','requests','bs4'], 17 | entry_points={ 18 | 'console_scripts': [ 19 | 'lyricaly=lyricaly.__main__:main', 20 | ], 21 | }, 22 | ) 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 M Vignesh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Lyricaly 2 | 3 | Get Lyrics on your Terminal 4 | 5 | Just because finding lyrics on a web browser is too mainstream, I made this to get them delivered to your Terminal. 6 | 7 | Lyricaly gets Lyrics delivered to your Terminal for any Song. Uses beautifulsoup4 to scrap lyrics. 8 | 9 | Published at pypi: Lyricaly 10 | 11 | 12 | Installation 13 | 14 | Using pip 15 | 16 | # Install package from pypi 17 | $ pip install lyricaly 18 | 19 | # Run it 20 | $ lyricaly 21 | 22 | # Done!! 23 | Without using pip 24 | 25 | # Clone the repository 26 | $ git clone https://github.com/vigzmv/Lyricaly.git 27 | $ cd lyricaly 28 | 29 | # Install Lyricaly 30 | $ sudo python setup.py install 31 | 32 | # Run it 33 | $ lyricaly 34 | 35 | # or simply execute the Python Script (lyrical.py) 36 | # Done!! 37 | 38 | Lyricaly scraps the lyrics of the given song from Musixmatch 39 | 40 | I am in no way associated with musixmatch and the correctness of lyrics corresponds with the data present in the database. 41 | 42 | Lyricaly only scraps the present data from there and delivers it. 43 | 44 | Note: English Language lyrics work fine. Spanish and french support is not good. Other Languages might work. 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lyricaly 2 | 3 | [![PyPI version](https://badge.fury.io/py/lyricaly.svg)](https://badge.fury.io/py/lyricaly)    [![license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/vigzmv/Lyricaly/blob/master/LICENSE)    4 | [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat-square)](https://github.com/vigzmv/Lyricaly)    5 | 6 | ###:musical_note: Get Lyrics on your Terminal 7 | 8 | #### Just because finding lyrics on a web browser is too mainstream, I made this to get them delivered to your Terminal. 9 | 10 | #### Lyricaly gets Lyrics delivered to your Terminal for any Song. Uses beautifulsoup4 to scrap lyrics. 11 | #### Published at pypi: [Lyricaly](https://pypi.python.org/pypi/lyricaly) 12 | 13 | 14 | ## Installation 15 | --- 16 | 17 | ### Using pip 18 | 19 | # Install package from pypi 20 | $ pip install lyricaly 21 | 22 | # Run it 23 | $ lyricaly 24 | 25 | # Done!! 26 | 27 | 28 | ### Without using pip 29 | 30 | # Clone the repository 31 | $ git clone https://github.com/vigzmv/Lyricaly.git 32 | $ cd lyricaly 33 | 34 | # Install Lyricaly 35 | $ sudo python setup.py install 36 | 37 | # Run it 38 | $ lyricaly 39 | 40 | # or simply execute the Python Script (lyrical.py) 41 | # Done!! 42 | 43 | ### install_requires 44 | beautifulsoup 45 | requests 46 | --- 47 | 48 | ##### Lyricaly scraps the lyrics of the given song from [Musixmatch](http://musixmatch.com/) 49 | ##### I am in no way associated with musixmatch and the correctness of lyrics corresponds with the data present in the database. 50 | ##### Lyricaly only scraps the present data from there and delivers it. 51 | 52 | ###### Note: English Language lyrics work fine. Spanish and french support is not good. Other Languages might work. 53 | -------------------------------------------------------------------------------- /lyricaly.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Lyricaly - Get lyrics directly to your terminal 4 | # By: vigzmv 5 | # www.vigneshm.com 6 | # https://github.com/vigzmv 7 | 8 | # Start 9 | 10 | # -*- coding: utf-8 -*- 11 | 12 | from __future__ import print_function 13 | 14 | from bs4 import BeautifulSoup 15 | 16 | import requests 17 | import re 18 | import time 19 | import urllib2 20 | 21 | def main(): 22 | 23 | count = 0 24 | while True: 25 | 26 | print() 27 | 28 | if count == 0: 29 | print("What are you listening to ?\n") 30 | else: 31 | print("What are you listening to ? (enter 'exit' to exit)\n") 32 | 33 | songName = raw_input("") 34 | 35 | if songName == 'exit' or songName == 'Exit' or songName == 'EXIT': 36 | exit() 37 | 38 | songName = songName.replace(" ","%20") 39 | 40 | print("") 41 | print("Fetching the song...") 42 | 43 | # Lyrics Database: MusixMatch 44 | # MusixMatch claims itself to be the largerst database of lyrics. 45 | # Their search is very effective as they automaticaly choose the best match by 46 | # parameters like recent trends and popularity. Hence the lyrics can be found with 47 | # least keywords. 48 | 49 | # Earlier Python requests did the job, but some changes in MusixMatch blocked requests from it. 50 | # Now using urllib2 to fet this done 51 | 52 | # Searching for the song 53 | 54 | url1 = "https://www.musixmatch.com/search/" + songName 55 | 56 | # print(url1) 57 | try: 58 | response = urllib2.urlopen(url1) 59 | # respons1 = requests.get(url1) 60 | # print(response) 61 | soup1 = BeautifulSoup(response,'html.parser') 62 | 63 | except: 64 | 65 | print(" \n\nPlease Check Your Internet Connection and try again.\n") 66 | continue 67 | 68 | # Get the Best Search result. 69 | try: 70 | # bestresult appears first at top in a box 71 | BestResult = soup1.find_all("div",{"class":"box-style-plain"}) 72 | 73 | # get the song lyrics page link 74 | Link = BestResult[0].find_all("a")[0].get("href") 75 | 76 | except: 77 | 78 | print(" \n\nSearch Failed! Please check the song name and Retry.\n") 79 | continue 80 | 81 | # got the song link 82 | LyricUrl = "https://www.musixmatch.com" + Link 83 | 84 | 85 | # print(LyricUrl) 86 | 87 | # open the lyrics page 88 | 89 | try: 90 | 91 | respons2 = urllib2.urlopen(LyricUrl) 92 | # respons2 = requests.get(LyricUrl) 93 | soup2 = BeautifulSoup(respons2,'html.parser') 94 | 95 | except: 96 | 97 | print(" \n\nPlease Check Your Internet Connection and try again.\n") 98 | continue 99 | 100 | # get the song name form the title 101 | 102 | FoundSongName = soup2.title.string 103 | FoundSongName = FoundSongName.replace(" lyrics | Musixmatch","") 104 | 105 | # print the Found song name 106 | 107 | found = " Song: " + FoundSongName 108 | foundlen = len(found) 109 | 110 | print('\n\n') 111 | 112 | print() 113 | for _ in range(0,70): 114 | print("-",end="") 115 | print('\n') 116 | for _ in range(0,35-(foundlen/2)): 117 | print(" ",end="") 118 | print(found.encode("utf-8")) 119 | print() 120 | print("",end="") 121 | for _ in range(0,70): 122 | print("-",end="") 123 | 124 | 125 | print('\n\n') 126 | time.sleep(1) 127 | 128 | # get the lyrics 129 | 130 | # I found that the complete lyrics are stored in a list in scripts section of the page. 131 | # a easy way to access the lyrics is by to find the substring "body" which marks 132 | # the begining of the string. 133 | 134 | try: 135 | 136 | verylongtext = soup2.body.findAll(text=re.compile('"body"')) 137 | # print(len(verylongtext)) 138 | solongtext = verylongtext[0] 139 | 140 | # Lyrics are suceeded by "body" 141 | start = '"body":"' 142 | 143 | # lyics are followed by its language details 144 | end_en = '","language":"en","languageDescription":"English"' 145 | end_es = '","language":"es","languageDescription":"Spanish"' 146 | end_fr = '","language":"fr","languageDescription":"French"' 147 | end_un = '","language":"","languageDescription":""' 148 | 149 | # stripping the lyrics from the long string 150 | 151 | # checking for the lyrics languwage 152 | if end_en in solongtext: 153 | # english 154 | longtext = solongtext[solongtext.index(start) + len(start) : solongtext.index(end_en)] 155 | 156 | elif end_es in solongtext: 157 | # spanish 158 | longtext = solongtext[solongtext.index(start) + len(start) : solongtext.index(end_es)] 159 | 160 | elif end_fr in solongtext: 161 | # french 162 | longtext = solongtext[solongtext.index(start) + len(start) : solongtext.index(end_fr)] 163 | 164 | elif end_un in solongtext: 165 | # unknown (hindi) 166 | longtext = solongtext[solongtext.index(start) + len(start) : solongtext.index(end_un)] 167 | 168 | else: 169 | print(" Sorry, Lyrics are not available.\n") 170 | continue 171 | 172 | # Finally the lyrics are in. 173 | 174 | ThemLovelyLyrics = (" " + longtext) 175 | 176 | # Formating the lyrics to show with newlines and ignoring special chahracters 177 | 178 | for i in range(0,len(ThemLovelyLyrics)): 179 | if ThemLovelyLyrics[i] == '\\' and ThemLovelyLyrics[i+1] == 'n': 180 | print("\n ",end="") 181 | elif ThemLovelyLyrics[i] == '\\' and ThemLovelyLyrics[i+1] == '"': 182 | pass 183 | elif ThemLovelyLyrics[i-1] == '\\' and ThemLovelyLyrics[i] == 'n': 184 | pass 185 | else: 186 | print(ThemLovelyLyrics[i].encode("utf-8"),end='') 187 | 188 | 189 | print('\n') 190 | print('',end="") 191 | for _ in range(0,70): 192 | print("_",end="") 193 | print('\n\n') 194 | count = count + 1 195 | 196 | except: 197 | 198 | print(" Sorry, Lyrics are not available.\n") 199 | continue 200 | 201 | if __name__ == "__main__": 202 | main() 203 | # End 204 | -------------------------------------------------------------------------------- /lyricaly/__main__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Lyricaly - Get lyrics directly to your terminal 4 | # By: vigzmv 5 | # www.vigneshm.com 6 | # https://github.com/vigzmv 7 | 8 | # Start 9 | 10 | # -*- coding: utf-8 -*- 11 | 12 | from __future__ import print_function 13 | 14 | from bs4 import BeautifulSoup 15 | 16 | import requests 17 | import re 18 | import time 19 | import urllib2 20 | 21 | def main(): 22 | 23 | count = 0 24 | while True: 25 | 26 | print() 27 | 28 | if count == 0: 29 | print("What are you listening to ?\n") 30 | else: 31 | print("What are you listening to ? (enter 'exit' to exit)\n") 32 | 33 | songName = raw_input("") 34 | 35 | if songName == 'exit' or songName == 'Exit' or songName == 'EXIT': 36 | exit() 37 | 38 | songName = songName.replace(" ","%20") 39 | 40 | print("") 41 | print("Fetching the song...") 42 | 43 | # Lyrics Database: MusixMatch 44 | # MusixMatch claims itself to be the largerst database of lyrics. 45 | # Their search is very effective as they automaticaly choose the best match by 46 | # parameters like recent trends and popularity. Hence the lyrics can be found with 47 | # least keywords. 48 | 49 | # Earlier Python requests did the job, but some changes in MusixMatch blocked requests from it. 50 | # Now using urllib2 to fet this done 51 | 52 | # Searching for the song 53 | 54 | url1 = "https://www.musixmatch.com/search/" + songName 55 | 56 | # print(url1) 57 | try: 58 | response = urllib2.urlopen(url1) 59 | # respons1 = requests.get(url1) 60 | # print(response) 61 | soup1 = BeautifulSoup(response,'html.parser') 62 | 63 | except: 64 | 65 | print(" \n\nPlease Check Your Internet Connection and try again.\n") 66 | continue 67 | 68 | # Get the Best Search result. 69 | try: 70 | # bestresult appears first at top in a box 71 | BestResult = soup1.find_all("div",{"class":"box-style-plain"}) 72 | 73 | # get the song lyrics page link 74 | Link = BestResult[0].find_all("a")[0].get("href") 75 | 76 | except: 77 | 78 | print(" \n\nSearch Failed! Please check the song name and Retry.\n") 79 | continue 80 | 81 | # got the song link 82 | LyricUrl = "https://www.musixmatch.com" + Link 83 | 84 | 85 | # print(LyricUrl) 86 | 87 | # open the lyrics page 88 | 89 | try: 90 | 91 | respons2 = urllib2.urlopen(LyricUrl) 92 | # respons2 = requests.get(LyricUrl) 93 | soup2 = BeautifulSoup(respons2,'html.parser') 94 | 95 | except: 96 | 97 | print(" \n\nPlease Check Your Internet Connection and try again.\n") 98 | continue 99 | 100 | # get the song name form the title 101 | 102 | FoundSongName = soup2.title.string 103 | FoundSongName = FoundSongName.replace(" lyrics | Musixmatch","") 104 | 105 | # print the Found song name 106 | 107 | found = " Song: " + FoundSongName 108 | foundlen = len(found) 109 | 110 | print('\n\n') 111 | 112 | print() 113 | for _ in range(0,70): 114 | print("-",end="") 115 | print('\n') 116 | for _ in range(0,35-(foundlen/2)): 117 | print(" ",end="") 118 | print(found.encode("utf-8")) 119 | print() 120 | print("",end="") 121 | for _ in range(0,70): 122 | print("-",end="") 123 | 124 | 125 | print('\n\n') 126 | time.sleep(1) 127 | 128 | # get the lyrics 129 | 130 | # I found that the complete lyrics are stored in a list in scripts section of the page. 131 | # a easy way to access the lyrics is by to find the substring "body" which marks 132 | # the begining of the string. 133 | 134 | try: 135 | 136 | verylongtext = soup2.body.findAll(text=re.compile('"body"')) 137 | # print(len(verylongtext)) 138 | solongtext = verylongtext[0] 139 | 140 | # Lyrics are suceeded by "body" 141 | start = '"body":"' 142 | 143 | # lyics are followed by its language details 144 | end_en = '","language":"en","languageDescription":"English"' 145 | end_es = '","language":"es","languageDescription":"Spanish"' 146 | end_fr = '","language":"fr","languageDescription":"French"' 147 | end_un = '","language":"","languageDescription":""' 148 | 149 | # stripping the lyrics from the long string 150 | 151 | # checking for the lyrics languwage 152 | if end_en in solongtext: 153 | # english 154 | longtext = solongtext[solongtext.index(start) + len(start) : solongtext.index(end_en)] 155 | 156 | elif end_es in solongtext: 157 | # spanish 158 | longtext = solongtext[solongtext.index(start) + len(start) : solongtext.index(end_es)] 159 | 160 | elif end_fr in solongtext: 161 | # french 162 | longtext = solongtext[solongtext.index(start) + len(start) : solongtext.index(end_fr)] 163 | 164 | elif end_un in solongtext: 165 | # unknown (hindi) 166 | longtext = solongtext[solongtext.index(start) + len(start) : solongtext.index(end_un)] 167 | 168 | else: 169 | print(" Sorry, Lyrics are not available.\n") 170 | continue 171 | 172 | # Finally the lyrics are in. 173 | 174 | ThemLovelyLyrics = (" " + longtext) 175 | 176 | # Formating the lyrics to show with newlines and ignoring special chahracters 177 | 178 | for i in range(0,len(ThemLovelyLyrics)): 179 | if ThemLovelyLyrics[i] == '\\' and ThemLovelyLyrics[i+1] == 'n': 180 | print("\n ",end="") 181 | elif ThemLovelyLyrics[i] == '\\' and ThemLovelyLyrics[i+1] == '"': 182 | pass 183 | elif ThemLovelyLyrics[i-1] == '\\' and ThemLovelyLyrics[i] == 'n': 184 | pass 185 | else: 186 | print(ThemLovelyLyrics[i].encode("utf-8"),end='') 187 | 188 | 189 | print('\n') 190 | print('',end="") 191 | for _ in range(0,70): 192 | print("_",end="") 193 | print('\n\n') 194 | count = count + 1 195 | 196 | except: 197 | 198 | print(" Sorry, Lyrics are not available.\n") 199 | continue 200 | 201 | if __name__ == "__main__": 202 | main() 203 | # End 204 | --------------------------------------------------------------------------------