diff --git a/addons/__init__.py b/addons/__init__.py index 38504d5..6ffc10a 100644 --- a/addons/__init__.py +++ b/addons/__init__.py @@ -1,2 +1,2 @@ -from .lyrics import getLyrics from .lyrics import lyricsPlatform +from .settings import Settings, TOKENS \ No newline at end of file diff --git a/addons/lyrics.py b/addons/lyrics.py index 206443c..c24d702 100644 --- a/addons/lyrics.py +++ b/addons/lyrics.py @@ -1,6 +1,9 @@ import aiohttp, random, bs4, re +import function as func + from urllib.parse import quote from math import floor +from importlib import import_module userAgents = '''Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36 @@ -43,119 +46,139 @@ Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-US) AppleWebKit/530.9 (KHTM Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-US) AppleWebKit/530.6 (KHTML, like Gecko) Chrome/ Safari/530.6 Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/ Safari/530.5''' -async def get(url): - try: - async with aiohttp.ClientSession() as session: - resp = await session.get(url=url, headers={'User-Agent': random.choice(userAgents)}) - if resp.status != 200: - return None - return await resp.text() - except: - return "" +class A_ZLyrics(): + async def get(self, url): + try: + async with aiohttp.ClientSession() as session: + resp = await session.get(url=url, headers={'User-Agent': random.choice(userAgents)}) + if resp.status != 200: + return None + return await resp.text() + except: + return "" -async def getLyrics(title: str): - link = await googleGet(title=title) - if not link: - return 0 + async def getLyrics(self, title: str): + link = await self.googleGet(title=title) + if not link: + return 0 - page = await get(link) + page = await self.get(link) - metadata = [elm.text for elm in htmlFindAll(page)('b')] - - if not metadata: - return None - - # v3.0.4: Update title and artist attributes with exact names - title = ''.join(i for i in metadata[1][1:-1] if i not in r'<>:"/\|?*') - - divs = [i.text for i in htmlFindAll(page)('div', {'class': None})] - - lyrics = max(divs, key=len).strip() - - if not lyrics: - return print("Lyrics not found") - - rr = re.split(r"(\[[\w\S_ ]+\:])", lyrics) - for item in rr: - if item == "": - rr.remove(item) - - count = len(rr) - if count > 1: - if (count % 2) != 0: - del rr[count-1] - return {rr[i].replace("[", "").replace(":]", ""): clearText(rr[i + 1]) for i in range(0, len(rr), 2)} - return {"default": clearText(rr[0])} - -async def googleGet(acc = 0.6, artist='', title=''): - data = artist + ' ' * (title != '' and artist != '') + title - encoded_data = quote(data.replace(' ', '+')) - - - google_page = await get('{}{}+site%3Aazlyrics.com'.format( - 'https://duckduckgo.com/html/?q=', encoded_data)) - - try: - results = re.findall(r'(azlyrics\.com\/lyrics\/[a-z0-9]+\/(\w+).html)', google_page) - except: - return None + metadata = [elm.text for elm in self.htmlFindAll(page)('b')] - if len(results): - jaro_artist = 1.0 - jaro_title = 1.0 - - if artist: - jaro_artist = jaro_distance(artist.replace(' ', ''), results[0][0]) - if title: - jaro_title = jaro_distance(title.replace(' ', ''), results[0][1]) - - if jaro_artist >= acc and jaro_title >= acc: - return 'https://www.' + results[0][0] - else: + if not metadata: return None - return None - -def jaro_distance(s1, s2): - if (s1 == s2): - return 1.0 - - len1, len2 = len(s1), len(s2) - max_dist = floor(max(len1, len2) / 2) - 1 - match = 0 - hash_s1, hash_s2 = [0] * len(s1), [0] * len(s2) - - for i in range(len1): - for j in range(max(0, i - max_dist), - min(len2, i + max_dist + 1)): - if (s1[i] == s2[j] and hash_s2[j] == 0): - hash_s1[i], hash_s2[j] = 1, 1 - match += 1 - break - - if (match == 0): - return 0.0 - - t = 0 - point = 0 - - for i in range(len1): - if (hash_s1[i]): - while (hash_s2[point] == 0): - point += 1 - - if (s1[i] != s2[point]): - point += 1 - t += 1 - t = t//2 - - return (match/ len1 + match / len2 + (match - t + 1) / match)/ 3.0 - -def htmlFindAll(page): - soup = bs4.BeautifulSoup(page, "html.parser") - return soup.findAll - -def clearText(text: str): - if text.startswith("\n\n"): - text = text.replace("\n\n", "", 1) - return text \ No newline at end of file + try: + title = ''.join(i for i in metadata[1][1:-1] if i not in r'<>:"/\|?*') + + divs = [i.text for i in self.htmlFindAll(page)('div', {'class': None})] + + lyrics = max(divs, key=len).strip() + + if not lyrics: + return print("Lyrics not found") + + rr = re.split(r"(\[[\w\S_ ]+\:])", lyrics) + for item in rr: + if item == "": + rr.remove(item) + + count = len(rr) + if count > 1: + if (count % 2) != 0: + del rr[count-1] + return {rr[i].replace("[", "").replace(":]", ""): self.clearText(rr[i + 1]) for i in range(0, len(rr), 2)} + return {"default": self.clearText(rr[0])} + except: + return None + + async def googleGet(self, acc = 0.6, artist='', title=''): + data = artist + ' ' * (title != '' and artist != '') + title + encoded_data = quote(data.replace(' ', '+')) + + + google_page = await self.get('{}{}+site%3Aazlyrics.com'.format( + 'https://duckduckgo.com/html/?q=', encoded_data)) + + try: + results = re.findall(r'(azlyrics\.com\/lyrics\/[a-z0-9]+\/(\w+).html)', google_page) + except: + return None + + if len(results): + jaro_artist = 1.0 + jaro_title = 1.0 + + if artist: + jaro_artist = self.jaro_distance(artist.replace(' ', ''), results[0][0]) + if title: + jaro_title = self.jaro_distance(title.replace(' ', ''), results[0][1]) + + if jaro_artist >= acc and jaro_title >= acc: + return 'https://www.' + results[0][0] + else: + return None + return None + + def jaro_distance(self, s1, s2): + if (s1 == s2): + return 1.0 + + len1, len2 = len(s1), len(s2) + max_dist = floor(max(len1, len2) / 2) - 1 + match = 0 + hash_s1, hash_s2 = [0] * len(s1), [0] * len(s2) + + for i in range(len1): + for j in range(max(0, i - max_dist), + min(len2, i + max_dist + 1)): + if (s1[i] == s2[j] and hash_s2[j] == 0): + hash_s1[i], hash_s2[j] = 1, 1 + match += 1 + break + + if (match == 0): + return 0.0 + + t = 0 + point = 0 + + for i in range(len1): + if (hash_s1[i]): + while (hash_s2[point] == 0): + point += 1 + + if (s1[i] != s2[point]): + point += 1 + t += 1 + t = t//2 + + return (match/ len1 + match / len2 + (match - t + 1) / match)/ 3.0 + + def htmlFindAll(self, page): + soup = bs4.BeautifulSoup(page, "html.parser") + return soup.findAll + + def clearText(self, text: str): + if text.startswith("\n\n"): + text = text.replace("\n\n", "", 1) + + return text + +class Genius(): + def __init__(self) -> None: + self.module = import_module("lyricsgenius") + self.genius = self.module.Genius(func.tokens.genius_token) + + async def getLyrics(self, name: str): + song = self.genius.search_song(title=name) + if not song: + return None + + return {"default": song.lyrics} + +lyricsPlatform = { + "a_zlyrics": A_ZLyrics, + "genius": Genius +} \ No newline at end of file diff --git a/addons/settings.py b/addons/settings.py index c810338..56cd0ff 100644 --- a/addons/settings.py +++ b/addons/settings.py @@ -13,6 +13,7 @@ class Settings: self.cooldowns_settings = settings.get("cooldowns", {}) self.aliases_settings = settings.get("aliases", {}) self.controller_settings = settings.get("controller", [["back", "resume", "skip", {"stop": "red"}, "add"], ["tracks"]]) + self.lyrics_platform = settings.get("lyrics_platform", "A_ZLyrics").lower() self.ipc_server = settings.get("ipc_server", { "host": "127.0.0.1", "port": 8000, diff --git a/cogs/basic.py b/cogs/basic.py index b048509..336926f 100644 --- a/cogs/basic.py +++ b/cogs/basic.py @@ -17,7 +17,7 @@ from function import ( connect_channel ) -from addons import getLyrics +from addons import lyricsPlatform from views import SearchView, ListView, LinkView, LyricsView, ChapterView, HelpView from validators import url @@ -664,12 +664,12 @@ class Basic(commands.Cog): return await ctx.send(get_lang(ctx.guild.id, 'noTrackPlaying'), ephemeral=True) name = player.current.title + " " + player.current.author await ctx.defer() - song = await getLyrics(name) + + song = await lyricsPlatform.get(settings.lyrics_platform)().getLyrics(name) if not song: return await ctx.send(get_lang(ctx.guild.id, 'lyricsNotFound'), ephemeral=True) - view = LyricsView(name=name, source={_: re.findall( - r'.*\n(?:.*\n){,22}', v) for _, v in song.items()}, author=ctx.author) + view = LyricsView(name=name, source={_: re.findall(r'.*\n(?:.*\n){,22}', v) for _, v in song.items()}, author=ctx.author) message = await ctx.send(embed=view.build_embed(), view=view) view.response = message diff --git a/settings Example.json b/settings Example.json index bbc1608..3bead3d 100644 --- a/settings Example.json +++ b/settings Example.json @@ -12,6 +12,7 @@ "bot_access_user": [], "color_code":"0xb3b3b3", "default_max_queue": 1000, + "lyrics_platform": "A_ZLyrics", "ipc_server": { "host": "127.0.0.1", "port": 8000,