diff --git a/.idea/irs.iml b/.idea/irs.iml
new file mode 100644
index 0000000..e98082a
--- /dev/null
+++ b/.idea/irs.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..5bbe586
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..0dc461c
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..53bb332
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1482431898415
+
+
+ 1482431898415
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/flexx-app/center.py b/flexx-app/center.py
new file mode 100644
index 0000000..5d17a4b
--- /dev/null
+++ b/flexx-app/center.py
@@ -0,0 +1,9 @@
+def center(lst):
+ length = len(lst)
+ center = -1
+ for num in range(0, length):
+ if not (num % 2):
+ center += 1
+ return lst[center]
+
+print (center(center([1, 2, [1, 2, 3], 4, 5])))
\ No newline at end of file
diff --git a/flexx-app/chat.py b/flexx-app/chat.py
new file mode 100644
index 0000000..0f260c0
--- /dev/null
+++ b/flexx-app/chat.py
@@ -0,0 +1,87 @@
+"""
+Simple chat web app in less than 80 lines.
+
+This app might be running at the demo server: http://flexx1.zoof.io
+"""
+
+from flexx import app, ui, event
+
+
+class Relay(event.HasEvents):
+ """ Global object to relay messages to all participants.
+ """
+ @event.emitter
+ def new_message(self, msg):
+ return dict(msg=msg + '
')
+
+
+class MessageBox(ui.Label):
+ CSS = """
+ .flx-MessageBox {
+ overflow-y:scroll;
+ background: #e8e8e8;
+ border: 1px solid #444;
+ margin: 3px;
+ }
+ """
+
+
+class ChatRoom(ui.Widget):
+ """ Despite the name, this represents one connection to the chat room."""
+
+ def init(self):
+ with ui.HBox():
+ ui.Widget(flex=1)
+ with ui.VBox():
+ self.name = ui.LineEdit(placeholder_text='your name')
+ self.people = ui.Label(flex=1, base_size=(250, 0))
+ with ui.VBox():
+ self.messages = MessageBox(flex=1)
+ with ui.HBox():
+ self.message = ui.LineEdit(flex=1, placeholder_text='enter message')
+ self.ok = ui.Button(text='Send')
+ ui.Widget(flex=1)
+
+ # Pipe messages send by the relay into this app
+ relay.connect(self._push_info, 'new_message:' + self.id)
+
+ self._update_participants()
+
+ def _push_info(self, *events):
+ if self.session.status:
+ for ev in events:
+ self.emit('new_message', ev)
+
+ def _update_participants(self):
+ if not self.session.status:
+ relay.disconnect('new_message:' + self.id)
+ return # and dont't invoke a new call
+ proxies = app.manager.get_connections(self.__class__.__name__)
+ names = [p.app.name.text for p in proxies]
+ del proxies
+ text = '
%i persons in this chat:
' % len(names)
+ text += '
'.join([name or 'anonymous' for name in sorted(names)])
+ self.people.text = text
+ app.call_later(3, self._update_participants)
+
+ @event.connect('ok.mouse_down', 'message.submit')
+ def _send_message(self, *events):
+ text = self.message.text
+ if text:
+ name = self.name.text or 'anonymous'
+ relay.new_message('%s: %s' % (name, text))
+ self.message.text = ''
+
+ class JS:
+
+ @event.connect('new_message')
+ def _update_total_text(self, *events):
+ self.messages.text += ''.join([ev.msg for ev in events])
+
+
+# Create global relay
+relay = Relay()
+
+if __name__ == '__main__':
+ m = app.launch(ChatRoom) # for use during development
+ app.run()
diff --git a/flexx-app/circles.py b/flexx-app/circles.py
new file mode 100644
index 0000000..2a3daef
--- /dev/null
+++ b/flexx-app/circles.py
@@ -0,0 +1,51 @@
+"""
+Example that shows animated circles. The animation is run from Python.
+Doing that in JS would be more efficient, but we have not implemented timers
+yet.
+"""
+
+import math
+
+from flexx import app, ui
+
+
+class Circle(ui.Label):
+ CSS = """
+ .flx-Circle {
+ background: #f00;
+ border-radius: 10px;
+ width: 10px;
+ height: 10px;
+ }
+ """
+
+class Circles(ui.Widget):
+
+ def init(self):
+ self._circles = []
+
+ with ui.PinboardLayout():
+ for i in range(32):
+ x = math.sin(i*0.2)*0.3 + 0.5
+ y = math.cos(i*0.2)*0.3 + 0.5
+ w = Circle(pos=(x, y))
+ self._circles.append(w)
+
+ self.tick()
+ # todo: animate in JS!
+
+ def tick(self):
+ if not self.session.status:
+ return
+ import time
+ t = time.time()
+ for i, circle in enumerate(self._circles):
+ x = math.sin(i*0.2 + t)*0.3 + 0.5
+ y = math.cos(i*0.2 + t)*0.3 + 0.5
+ circle.pos = x, y
+ app.call_later(0.03, self.tick)
+
+
+if __name__ == '__main__':
+ m = app.launch(Circles)
+ app.run()
diff --git a/flexx-app/form.py b/flexx-app/form.py
new file mode 100644
index 0000000..bfb3dc7
--- /dev/null
+++ b/flexx-app/form.py
@@ -0,0 +1,28 @@
+"""
+Simple example that shows two forms, one which is stretched, and one
+in which we use a dummy Widget to fill up space so that the form is
+more compact.
+"""
+
+from flexx import app, ui
+
+
+class Form(ui.Widget):
+
+ def init(self):
+
+ with ui.BoxPanel():
+ with ui.FormLayout() as self.form:
+ self.b1 = ui.Button(title='Name:', text='Hola')
+ self.b2 = ui.Button(title='Age:', text='Hello world')
+ self.b3 = ui.Button(title='Favorite color:', text='Foo bar')
+ with ui.FormLayout() as self.form:
+ self.b4 = ui.Button(title='Name:', text='Hola')
+ self.b5 = ui.Button(title='Age:', text='Hello world')
+ self.b6 = ui.Button(title='Favorite color:', text='Foo bar')
+ ui.Widget(flex=1) # Add a flexer
+
+
+if __name__ == '__main__':
+ m = app.launch(Form)
+ app.run()
diff --git a/flexx-app/irs-app.py b/flexx-app/irs-app.py
new file mode 100644
index 0000000..4c5285a
--- /dev/null
+++ b/flexx-app/irs-app.py
@@ -0,0 +1,22 @@
+from flexx import app, ui, event
+import os
+
+class IRS(ui.Widget):
+
+ def init(self):
+
+ with ui.FormLayout() as self.form:
+ self.song = ui.LineEdit(placeholder_text="Song Name")
+ self.artist = ui.LineEdit(placeholder_text="Artist Name")
+ self.submit = ui.Button(text="Submit")
+ self.output = ui.Label(text="")
+ ui.Widget(flex=2)
+
+ """@event.connect("submit.mouse_click", "artist.submit")
+ def _button_clicked(self, *events):
+ self.output.text = os.system('irs -a "%s" -s "%s"' % (self.artist.text, self.song.text))
+"""
+
+if __name__ == '__main__':
+ m = app.launch(IRS)
+ app.run()
diff --git a/irs/__main__.py b/irs/__main__.py
index f1101a8..c64613d 100644
--- a/irs/__main__.py
+++ b/irs/__main__.py
@@ -1,5 +1,4 @@
#!/usr/bin python
-
HELP = \
"""
usage:
@@ -22,67 +21,22 @@ Options:
-s SONG, --song SONG Specify song name of the artist.
-A ALBUM, --album ALBUM
Specify album name of the artist.
- -st SEARCH_TERMS, --search-terms SEARCH_TERMS
- Only use if calling -A/--album. Acts as extra search
- terms when looking for the album.
-l, --choose-link If supplied, will bring up a console choice for what
link you want to download based off a list of titles.
-ng, --no-organize Only use if calling -p/--playlist. Forces all files
downloaded to be organized normally.
"""
-import argparse
-from os import system
+# For exiting
from sys import exit
-from .manage import *
+
+# Parsing args
+import argparse
+
+# Import the manager
+from .manager import Manager
from .utils import *
-def console(args):
- system("clear")
- media = None
- while type(media) is not int:
- print (bc.HEADER)
- print ("What type of media would you like to download?")
- print ("\t1) Song")
- print ("\t2) Album")
- print ("\t3) Playlist")
- try:
- media = int(input(bc.YELLOW + bc.BOLD + ":: " + bc.ENDC))
- if media not in (1, 2, 3):
- raise ValueError
-
- except ValueError:
- print (bc.FAIL + "\nPlease enter a valid number." + bc.ENDC)
-
- if media in (1, 2):
- print (bc.HEADER + "Artist of song/album ", end="")
- artist = input(bc.BOLD + bc.YELLOW + ": " + bc.ENDC)
-
- if media == 1:
- print (bc.HEADER + "Song you would like to download ", end="")
- song = input(bc.BOLD + bc.YELLOW + ": " + bc.ENDC)
- rip_mp3(song, artist, command=args.command, choose_link=args.link)
-
- elif media == 2:
- print (bc.HEADER + "Album you would like to download ", end="")
- album = input(bc.BOLD + bc.YELLOW + ": " + bc.ENDC)
- rip_album(album, artist, command=args.command, choose_link=args.link)
-
- elif media == 3:
- print (bc.HEADER + "Playlist file name ", end="")
- playlist = input(bc.BOLD + bc.YELLOW + ": " + bc.ENDC)
-
- organize = ""
- while organize not in ("y", "n", "yes", "no", ""):
- print (bc.HEADER + "Would you like to place all songs into a single folder? (Y/n)", end="")
- organize = input(bc.BOLD + bc.YELLOW + ": " + bc.ENDC).lower()
-
- if organize in ("y", "yes", ""):
- rip_playlist(playlist, command=args.command, choose_link=args.link, \
- no_organize=True)
- elif organize in ("n", "no"):
- rip_playlist(playlist, command=args.command, choose_link=args.link)
-
def main():
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('-h', '--help', action='store_true', dest='help')
@@ -95,15 +49,13 @@ def main():
parser.add_argument('-p', '--playlist', dest="playlist", \
help="Specify playlist filename. Each line should be formatted like so: SONGNAME - ARTIST")
- parser.add_argument('-ng', '--no-organize', action="store_false", dest="no_organize", \
+ parser.add_argument('-ng', '--no-organize', action="store_false", dest="organize", \
help="Only use if calling -p/--playlist. Forces all files downloaded to be organizes normally.")
media = parser.add_mutually_exclusive_group()
media.add_argument('-s', '--song', dest="song", help="Specify song name of the artist.")
media.add_argument('-A', '--album', dest="album", help="Specify album name of the artist.")
- parser.add_argument('-st', '--search-terms', dest="search_terms", \
- help="Only use if calling -A/--album. Acts as extra search terms for the album.")
parser.add_argument('-o', '--order-files', action='store_true', dest="order_files",\
help="Only use if callign with -p/--playlist or -A/--album. Adds a digit to front of each file specifying order.")
@@ -111,9 +63,15 @@ def main():
args = parser.parse_args()
+ if args.organize == None:
+ args.organize = True
+
+ manager = Manager(args)
+
if args.help:
global HELP
print (HELP)
+ exit(1)
elif args.version:
import pkg_resources
@@ -121,32 +79,31 @@ def main():
print ("Homepage: " + color("https://github.com/kepoorhampond/irs", ["OKGREEN"]))
print ("License: " + color("The GNU", ["YELLOW"]) + " (http://www.gnu.org/licenses/gpl.html)")
print ("Version: " + pkg_resources.get_distribution("irs").version)
-
print ("\n")
exit(0)
- elif not args.album and args.search_terms:
- parser.error("error: must supply -A/--album if you are going to supply -st/--search-terms")
+ elif not args.organize and not args.playlist:
+ parser.error("error: must supply -p/--playlist if specifying -ng/--no-organize")
exit(1)
elif args.artist and not (args.album or args.song):
- print ("error: must specify -A/--album or -s/--song if specifying -a/--artist")
+ parser.error("error: must supply -A/--album or -s/--song if specifying -a/--artist")
exit(1)
+
+
elif not args.artist and not args.playlist:
- console(args)
+ manager.console()
elif args.playlist:
- rip_playlist(args.playlist, args.command, choose_link=args.link, no_organize=args.no_organize)
+ manager.rip_playlist()
elif args.artist:
if args.album:
- rip_album(args.album, args.artist, command=args.command, \
- search=args.search_terms, choose_link=args.link)
+ manager.rip_album()
elif args.song:
- rip_mp3(args.song, args.artist, command=args.command, choose_link=args.link)
-
+ manager.rip_mp3()
if __name__ == "__main__":
diff --git a/irs/manage.py b/irs/manage.py
deleted file mode 100644
index dd9c83f..0000000
--- a/irs/manage.py
+++ /dev/null
@@ -1,265 +0,0 @@
-# Powered by:
-import youtube_dl
-
-# Info getting
-from urllib.request import urlopen
-from urllib.parse import urlencode
-
-# Info parsing
-from re import findall
-import os, json
-from bs4 import BeautifulSoup
-
-# Local utils
-from .utils import *
-from .metadata import *
-
-def find_mp3(song, artist,
- choose_link=False, # Whether to allow the user to choose the link.
- ):
-
- os.system("clear")
- print (color(song, ["BOLD", "UNDERLINE"]) + ' by ' + color(artist, ["BOLD", "UNDERLINE"]))
-
- search_terms = song + " " + artist + " lyrics"
- query_string = urlencode({"search_query" : (search_terms)})
-
- html_content = urlopen("http://www.youtube.com/results?" + query_string)
- search_results = findall(r'href=\"\/watch\?v=(.{11})', html_content.read().decode())
-
- in_title = False
- i = -1
- given_up_score = 0
-
- if not choose_link:
- print (bc.YELLOW + "\nFinding youtube link ...", end="\r")
- while in_title == False:
- i += 1
- given_up_score += 1
-
- if given_up_score >= 10:
- in_title = True
-
- audio_url = ("http://www.youtube.com/watch?v=" + search_results[i])
- title = strip_special_chars((BeautifulSoup(urlopen(audio_url), 'html.parser')).title.string.lower())
- song_title = song.lower().split("/")
-
- for song in song_title:
- song = strip_special_chars(song)
- if song in title and "full album" not in title:
- in_title = True
-
- print (bc.OKGREEN + "Found youtube link! \n" + bc.ENDC)
- else:
- results = []
-
- print (bc.YELLOW + "Finding links ... " + bc.ENDC, end="\r")
-
- for key in search_results[:10]:
- results.append(BeautifulSoup(urlopen(("http://www.youtube.com/watch?v="\
- + key)), 'html.parser').title.string.replace(" - YouTube" , ""))
-
- valid_choice = False
- while valid_choice == False:
- print (bc.HEADER + "What song would you like to download?")
- index = 0
- for result in results:
- index += 1
- print (" %s) %s" % (index, result))
- i = int(input(bc.YELLOW + bc.BOLD + ":: " + bc.ENDC))
- if i in tuple(range(1, 11)):
- i -= 1
- valid_choice = True
-
- return search_results[i]
-
-def rip_playlist(file_name,
- command=None, # Whether to run a special user-supplied command.
- choose_link=False, # Whether to allow the user to choose the link.
- no_organize=True, # Whether to organize the file downloaded.
- ):
-
- try:
- file = open(file_name, 'r')
- except Exception:
- print (file_name + bc.FAIL + " could not be found." + bc.ENDC)
- exit(1)
-
- errors = []
-
- song_number = 0
-
- for line in file:
- if line.strip() == "":
- pass
-
- try:
- arr = line.strip("\n").split(" - ")
- song = arr[0]
- artist = arr[1]
-
- if os.path.isdir(artist):
- remove = False
- else:
- remove = True
-
- location = rip_mp3(song, artist, command=command)
-
- song_number += 1
-
- locations = location.split("/")
-
- # Enter... the reorganizing...
- if no_organize:
-
- folder_name = ("playlist - " + file_name)[:40]
-
- if not os.path.isdir(folder_name):
- os.makedirs(folder_name)
-
- os.rename(location, "%s/%s - %s" % (folder_name, song_number, locations[-1]))
-
- if remove:
- import shutil # Only import this if I have to.
- shutil.rmtree(locations[0])
-
- if os.path.isfile(filename):
- os.rename(filename, folder_name + "/" + filename)
-
- os.rename(folder_name, folder_name.replace("playlist"))
-
- except Exception as e:
- errors.append(line + color(" : ", ["YELLOW"]) + bc.FAIL + str(e) + bc.ENDC)
-
- if len(errors) > 0:
- print (bc.FAIL + "Something was wrong with the formatting of the following lines:" + bc.ENDC)
-
- for i in errors:
- print ("\t%s" % i)
-
-
-def rip_album(album, artist,
- tried=False, # for if it can't find the album the first time
- search="album", # ditto
- command=None, # For running a command with the song's location
- choose_link=False # Whether to allow the user to choose the link.
- ):
-
- if search in (None, False):
- search = "album"
-
- visible_texts = search_google(album, artist, search)
- errors = []
- try:
- songs = []
- num = True
-
- for i, j in enumerate(visible_texts):
- if 'Songs' in j:
- if visible_texts[i + 1] == "1":
- indexed = i
-
- while num == True:
- try:
-
- if type(int(visible_texts[indexed])) is int:
- a = visible_texts[indexed + 1]
- songs.append(a)
- indexed += 1
-
- except:
- indexed += 1
- if indexed >= 1000:
- num = False
- else:
- pass
-
- print ("")
- print (bc.HEADER + "Album Contents:" + bc.ENDC)
- for i, j in enumerate(songs):
- print (bc.OKBLUE + " - " + j + bc.ENDC)
-
- print (bc.YELLOW + "\nFinding album cover ... " + bc.ENDC, end="\r")
- album_art_url = get_albumart_url(album, artist)
- print (bc.OKGREEN + "Album cover found: " + bc.ENDC + album_art_url)
-
- for i, j in enumerate(songs):
- song = j
- print (color("\n%s/%s - " % (i + 1, len(songs)), ["UNDERLINE"]), end="")
- rip_mp3(j, artist, part_of_album=True, album=album, tracknum=i + 1, \
- album_art_url=album_art_url, command=command, choose_link=choose_link)
-
- if len(errors) > 0:
- for error in errors: print (error)
- else:
- print (bc.BOLD + bc.UNDERLINE + album + bc.ENDC + bc.OKGREEN + " downloaded successfully!\n")
-
- except Exception as e:
- if str(e) == "local variable 'indexed' referenced before assignment" or str(e) == 'list index out of range':
- if tried != True:
- print (bc.OKBLUE + "Trying to find album ..." + bc.ENDC)
- rip_album(album, artist, tried=True, search="", choose_link=choose_link)
- else:
- print (bc.FAIL + 'Could not find album "%s"' % album + bc.ENDC)
- else:
- errors.append(bc.FAIL + "There was a problem with downloading: " + bc.ENDC + song + "\n" + str(e))
- pass
-
-
-def rip_mp3(song, artist,
- part_of_album=False, # neccessary for creating folders.
- album=None, # if you want to specify an album and save a bit of time.
- tracknum=None, # to specify the tracknumber in the album.
- album_art_url=None, # if you want to save a lot of time trying to find album cover.
- command=None, # For running a command with the song's location.
- choose_link=False, # Whether to allow the user to choose the link.
- ):
-
- audio_code = find_mp3(song, artist)
-
- filename = strip_special_chars(song) + ".mp3"
-
- ydl_opts = {
- 'format': 'bestaudio/best',
- #'quiet': True,
- 'postprocessors': [{
- 'key': 'FFmpegExtractAudio',
- 'preferredcodec': 'mp3',
- }],
- }
-
- with youtube_dl.YoutubeDL(ydl_opts) as ydl:
- ydl.download(["http://www.youtube.com/watch?v=" + audio_code])
-
-
- artist_folder = artist
-
- if not os.path.isdir(artist_folder):
- os.makedirs(artist_folder)
-
- if not part_of_album:
- location = artist_folder
-
- if album and part_of_album:
- album_folder = artist + "/" + album
- if not os.path.isdir(album_folder):
- os.makedirs(album_folder)
- location = album_folder
-
-
- for file in os.listdir("."):
- if audio_code in file:
- os.rename(file, location + "/" + filename)
-
-
- parse_metadata(song, artist, location, filename, tracknum=tracknum, album=album, album_art_url=album_art_url)
-
-
- print (color(song, ["BOLD", "UNDERLINE"]) + bc.OKGREEN + ' downloaded successfully!'+ bc.ENDC)
- print ("")
-
- if command:
- loc = location + "/" + filename
- os.system((command.replace("%(loc)s", '"%s"' % loc) + " &"))
-
- return (location + "/" + filename)
diff --git a/irs/manager.py b/irs/manager.py
new file mode 100644
index 0000000..a9a5f91
--- /dev/null
+++ b/irs/manager.py
@@ -0,0 +1,312 @@
+# Powered by:
+import youtube_dl
+import spotipy
+
+# Info getting
+from urllib.request import urlopen
+from urllib.parse import urlencode
+
+# Info parsing
+from re import findall
+import os, json
+from bs4 import BeautifulSoup
+
+# Local utils
+from .utils import *
+from .metadata import *
+
+class Manager:
+ def __init__(self, args):
+ self.args = args
+
+ def console(self):
+
+ args = self.args
+
+ os.system("clear")
+ media = None
+
+ while type(media) is not int:
+ print (bc.HEADER)
+ print ("What type of media would you like to download?")
+ print ("\t1) Song")
+ print ("\t2) Album")
+ print ("\t3) Playlist")
+ try:
+ media = int(input(bc.YELLOW + bc.BOLD + ":: " + bc.ENDC))
+ if media not in (1, 2, 3):
+ raise ValueError
+
+ except ValueError:
+ print (bc.FAIL + "\nPlease enter a valid number." + bc.ENDC)
+
+ if media in (1, 2):
+ self.args.artist = color_input("Artist of song/album")
+
+ if media == 1:
+ self.args.song = color_input("Song you would like to download")
+ self.rip_mp3()
+
+ elif media == 2:
+ self.args.album = color_input("Album you would like to download")
+ self.rip_album()
+
+ elif media == 3:
+ self.args.playlist = color_input("Playlist file name")
+
+ organize = ""
+ while organize not in ("y", "n", "yes", "no", ""):
+ print (bc.HEADER + "Would you like to place all songs into a single folder? (Y/n)", end="")
+ organize = input(bc.BOLD + bc.YELLOW + ": " + bc.ENDC).lower()
+
+ if organize in ("y", "yes", ""):
+ self.args.organize = True
+ elif organize in ("n", "no"):
+ self.args.organize = False
+
+ self.rip_playlist()
+
+ def find_mp3(self, song=None, artist=None):
+ if not song:
+ song = self.args.song
+
+ if not artist:
+ artist = self.args.artist
+
+ os.system("clear")
+ print (color(song, ["BOLD", "UNDERLINE"]) + ' by ' + color(artist, ["BOLD", "UNDERLINE"]))
+
+ search_terms = song + " " + artist + " lyrics"
+ query_string = urlencode({"search_query" : (search_terms)})
+
+ html_content = urlopen("http://www.youtube.com/results?" + query_string)
+ search_results = findall(r'href=\"\/watch\?v=(.{11})', html_content.read().decode())
+
+ in_title = False
+ i = -1
+ given_up_score = 0
+
+ if not self.args.link:
+ print (bc.YELLOW + "\nFinding youtube link ...", end="\r")
+ while in_title == False:
+ i += 1
+ given_up_score += 1
+
+ if given_up_score >= 10:
+ in_title = True
+
+ audio_url = ("http://www.youtube.com/watch?v=" + search_results[i])
+ title = strip_special_chars((BeautifulSoup(urlopen(audio_url), 'html.parser')).title.string.lower())
+ song_title = song.lower().split("/")
+
+ for song in song_title:
+ song = strip_special_chars(song)
+ if song in title and "full album" not in title:
+ in_title = True
+
+ print (bc.OKGREEN + "Found youtube link! \n" + bc.ENDC)
+ else:
+ results = []
+
+ print (bc.YELLOW + "\nFinding links ... " + bc.ENDC, end="\r")
+
+ for key in search_results[:10]:
+ results.append(BeautifulSoup(urlopen(("http://www.youtube.com/watch?v="\
+ + key)), 'html.parser').title.string.replace(" - YouTube" , ""))
+
+ valid_choice = False
+ while valid_choice == False:
+ print (bc.HEADER + "What song would you like to download?")
+ index = 0
+ for result in results:
+ index += 1
+ print (" %s) %s" % (index, result))
+ i = int(input(bc.YELLOW + bc.BOLD + ":: " + bc.ENDC))
+ if i in tuple(range(1, 11)):
+ i -= 1
+ valid_choice = True
+
+ return search_results[i]
+
+
+ def rip_playlist(self):
+ file_name = self.args.playlist
+ organize = self.args.organize
+
+ try:
+ file = open(file_name, 'r')
+ except Exception:
+ print (file_name + bc.FAIL + " could not be found." + bc.ENDC)
+ exit(1)
+
+ errors = []
+ song_number = 0
+
+ for line in file:
+ if line.strip() == "":
+ pass
+
+ #try:
+ arr = line.strip("\n").split(" - ")
+ self.args.song = arr[0]
+ self.args.artist = arr[1]
+
+ if os.path.isdir(self.args.artist):
+ remove = False
+ else:
+ remove = True
+
+ location = self.rip_mp3()
+ locations = location.split("/")
+ song_number += 1
+
+ # Enter... the reorganizing...
+ if organize:
+
+ folder_name = ("playlist - " + file_name)[:40]
+
+ if not os.path.isdir(folder_name):
+ os.makedirs(folder_name)
+
+ os.rename(location, "%s/%s - %s" % (folder_name, song_number, locations[-1]))
+
+ if remove:
+ import shutil # Only import this if I have to.
+ shutil.rmtree(locations[0])
+
+ if organize:
+ os.rename(file_name, folder_name + "/" + file_name)
+
+ os.rename(folder_name, folder_name.replace("playlist - ", ""))
+
+ #except Exception as e:
+ # errors.append(line + color(" : ", ["YELLOW"]) + bc.FAIL + str(e) + bc.ENDC)
+
+ if len(errors) > 0:
+ print (bc.FAIL + "Something was wrong with the formatting of the following lines:" + bc.ENDC)
+
+ for i in errors:
+ print ("\t%s" % i)
+
+ def get_album_contents(self, search):
+ spotify = spotipy.Spotify()
+
+ results = spotify.search(q=search, type='album')
+ items = results['albums']['items']
+ if len(items) > 0:
+ album = items[0]
+ album_id = (album['uri'])
+ contents = spotify.album_tracks(album_id)["items"]
+ contents = contents[0:-1]
+ names = []
+ for song in contents:
+ names.append(song["name"])
+ return names
+
+ def get_album_art(self, artist, album):
+ spotify = spotipy.Spotify()
+
+ results = spotify.search(q="album:" + album, type='album')
+ items = results['albums']['items']
+ if len(items) > 0:
+ album = items[0]['images'][0]['url']
+ return album
+
+
+ def rip_album(self):
+ search = self.args.artist + " " + self.args.album
+ songs = self.get_album_contents(search)
+
+ print ("")
+ print (bc.HEADER + "Album Contents:" + bc.ENDC)
+ for song in songs:
+ print (bc.OKBLUE + " - " + song + bc.ENDC)
+
+ print (bc.YELLOW + "\nFinding album cover ... " + bc.ENDC, end="\r")
+ album_art_url = self.get_album_art(self.args.artist, self.args.album)
+ print (bc.OKGREEN + "Album cover found: " + bc.ENDC + album_art_url)
+
+ for track_number, song in enumerate(songs):
+ print (color("\n%s/%s - " % (track_number + 1, len(songs)), ["UNDERLINE"]), end="")
+ self.rip_mp3(song, album=self.args.album, tracknum=track_number + 1, album_art_url=album_art_url)
+
+ else:
+ print (bc.BOLD + bc.UNDERLINE + self.args.album + bc.ENDC + bc.OKGREEN + " downloaded successfully!\n")
+
+
+ def rip_mp3(self, song=None, artist=None,
+ album=None, # if you want to specify an album and save a bit of time.
+ tracknum=None, # to specify the tracknumber in the album.
+ album_art_url=None, # if you want to save a lot of time trying to find album cover.
+ ):
+
+ if not song:
+ song = self.args.song
+
+ if not artist:
+ artist = self.args.artist
+
+ audio_code = self.find_mp3(song=song, artist=artist)
+
+ filename = strip_special_chars(song) + ".mp3"
+
+ ydl_opts = {
+ 'format': 'bestaudio/best',
+ #'quiet': True,
+ 'postprocessors': [{
+ 'key': 'FFmpegExtractAudio',
+ 'preferredcodec': 'mp3',
+ }],
+ }
+
+ with youtube_dl.YoutubeDL(ydl_opts) as ydl:
+ ydl.download(["http://www.youtube.com/watch?v=" + audio_code])
+
+
+ artist_folder = artist
+
+ if not os.path.isdir(artist_folder):
+ os.makedirs(artist_folder)
+
+ if album:
+ album_folder = artist + "/" + album
+ if not os.path.isdir(album_folder):
+ os.makedirs(album_folder)
+ location = album_folder
+
+ elif not album:
+ location = artist_folder
+
+ for file in os.listdir("."):
+ if audio_code in file:
+ os.rename(file, location + "/" + filename)
+
+
+ # Metadata
+ mp3 = Metadata(location + "/" + filename, song, artist)
+
+ mp3.add_title()
+ exclaim_good("Title added: ", song)
+
+ mp3.add_artist()
+ exclaim_good("Artist added: ", artist)
+
+ test_goodness(mp3.add_album(album), "Album", "album", mp3)
+
+ test_goodness(mp3.add_release_date(), "Release Date", "date", mp3)
+
+ if tracknum:
+ mp3.add_track_number(tracknum)
+
+ image_url = mp3.add_album_art(self.get_album_art(artist, mp3.get_attr('album')))
+ exclaim_good("Album art added: ", image_url)
+
+
+ print (color(song, ["BOLD", "UNDERLINE"]) + bc.OKGREEN + ' downloaded successfully!'+ bc.ENDC)
+ print ("")
+
+ if self.args.command:
+ loc = location + "/" + filename
+ os.system((self.args.command.replace("%(loc)s", '"%s"' % loc) + " &"))
+
+ return (location + "/" + filename)
diff --git a/irs/metadata.py b/irs/metadata.py
index 3dda37e..b6640be 100644
--- a/irs/metadata.py
+++ b/irs/metadata.py
@@ -3,7 +3,7 @@ from mutagen.mp3 import MP3, EasyMP3
from mutagen.easyid3 import EasyID3
from mutagen.id3 import ID3, APIC
-# Info getting
+# Info finding
from urllib.parse import quote_plus, quote
from urllib.request import urlopen, Request
@@ -15,152 +15,115 @@ from bs4 import BeautifulSoup
# Local utils
from .utils import *
-def search_google(song, artist, search_terms=""):
+# Powered by...
+import spotipy
- def visible(element):
- if element.parent.name in ['style', 'script', '[document]', 'head', 'title']:
- return False
- elif match('', str(element)):
- return False
- return True
+class Metadata:
+ def __init__(self, location, song, artist):
+ self.spotify = spotipy.Spotify()
- string = "%s %s %s" % (song, artist, search_terms)
- filename = 'http://www.google.com/search?q=' + quote_plus(string)
- hdr = {
- 'User-Agent':'Mozilla/5.0',
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
- }
+ self.song = song
+ self.artist = artist
+ self.location = location
- texts = BeautifulSoup(urlopen(Request(filename, \
- headers=hdr)).read(), 'html.parser').findAll(text=True)
+ self.info = self.search_google()
+ self.mp3 = MP3(self.location, ID3=EasyID3)
- return list(filter(visible, texts))
-
-def parse_metadata(song, artist, location, filename,
- tracknum="",
- album="",
- album_art_url=""
- ):
- googled = search_google(song, artist)
- mp3file = MP3("%s/%s" % (location, filename), ID3=EasyID3)
-
- # Song title
- mp3file['title'] = song
- mp3file.save()
-
- print("")
- print (bc.OKGREEN + "Title parsed: " + bc.ENDC + mp3file['title'][0])
-
- # Artist
- mp3file['artist'] = artist
- mp3file.save()
-
- print (bc.OKGREEN + "Artist parsed: " + bc.ENDC + mp3file['artist'][0])
-
-
- # Album
- try:
- if not album:
- for i, j in enumerate(googled):
- if "Album:" in j:
- album = (googled[i + 1])
- except Exception as e:
- album = None
-
- if album:
- mp3file['album'] = album
- print (bc.OKGREEN + "Album parsed: " + bc.ENDC + mp3file['album'][0])
- else:
- print (bc.FAIL + "Album not parsed.")
-
- mp3file.save()
-
-
- # Release date
- for i, j in enumerate(googled):
- if "Released:" in j:
- date = (googled[i + 1])
-
- try:
- mp3file['date'] = date
- print (bc.OKGREEN + "Release date parsed: " + bc.ENDC + mp3file['date'][0])
- except Exception:
- mp3file['date'] = ""
- pass
-
- mp3file.save()
-
-
- # Track number
- if tracknum:
- mp3file['tracknumber'] = str(tracknum)
- mp3file.save()
-
-
- # Album art
- try:
- if album:
- if not album_art_url:
- print (bc.YELLOW + "Parsing album art ..." + bc.ENDC, end="\r")
- temp_url = get_albumart_url(album, artist)
- embed_mp3(temp_url, location + "/" + filename)
- print (bc.OKGREEN + "Album art parsed: " + bc.ENDC + temp_url)
-
- else: # If part of an album, it should do this.
- embed_mp3(album_art_url, location + "/" + filename)
- print (bc.OKGREEN + "Album art parsed." + bc.ENDC)
-
-
- except Exception as e:
- print (bc.FAIL + "Album art not parsed: " + bc.ENDC + str(e))
-
-def embed_mp3(albumart_url, song_location):
- image = urlopen(albumart_url)
- audio = EasyMP3(song_location, ID3=ID3)
-
- try:
- audio.add_tags()
- except Exception as e:
- pass
-
- audio.tags.add(
- APIC(
- encoding = 3,
- mime = 'image/png',
- type = 3,
- desc = 'Cover',
- data = image.read()
- )
- )
- audio.save()
-
-def get_albumart_url(album, artist):
- def test_404(url):
+ def get_attr(self, attr):
try:
- urlopen(albumart).read()
+ return self.mp3[attr][0]
except Exception:
return False
+
+ def add_title(self):
+ self.mp3['title'] = self.song
+ self.mp3.save()
return True
- tries = 0
- album = "%s %s Album Art" % (artist, album)
- url = ("https://www.google.com/search?q=" + quote(album.encode('utf-8')) + "&source=lnms&tbm=isch")
- header = {
- 'User-Agent':
- '''
- Mozilla/5.0 (Windows NT 6.1; WOW64)
- AppleWebKit/537.36 (KHTML,like Gecko)
- Chrome/43.0.2357.134 Safari/537.36
- '''
- }
- soup = BeautifulSoup(urlopen(Request(url, headers=header)), "html.parser")
+ def add_artist(self):
+ self.mp3['artist'] = self.artist
+ self.mp3.save()
+ return True
- albumart_divs = soup.findAll("div", {"class": "rg_meta"})
- albumart = json.loads(albumart_divs[tries].text)["ou"]
- while not test_404(albumart):
- tries += 1
- albumart = json.loads(albumart_divs[tries].text)["ou"]
+ def add_album(self, album=None):
+ try:
+ if not album:
+ for i, j in enumerate(self.info):
+ if "Album:" in j:
+ album = (self.info[i + 1])
- return albumart
+ self.mp3['album'] = album
+ self.mp3.save()
+ return True
+ except Exception:
+ self.mp3['album'] = self.song
+ self.mp3.save()
+ return False
+
+
+ def add_release_date(self, release_date=None):
+ try:
+ if not release_date:
+ for i, j in enumerate(self.info):
+ if "Released:" in j:
+ date = (self.info[i + 1])
+
+ self.mp3['date'] = date
+ self.mp3.save()
+ return release_date
+ except UnboundLocalError:
+ return False
+
+
+ def add_track_number(self, track_number):
+ self.mp3['tracknumber'] = str(track_number)
+ self.mp3.save()
+ return True
+
+
+ def add_album_art(self, image_url):
+ mp3 = EasyMP3(self.location, ID3=ID3)
+
+ try:
+ mp3.add_tags()
+ except Exception as e:
+ pass
+
+ if not image_url:
+ image_url = self.get_albumart_url(album)
+
+ mp3.tags.add(
+ APIC(
+ encoding = 3,
+ mime = 'image/png',
+ type = 3,
+ desc = 'cover',
+ data = urlopen(image_url).read()
+ )
+ )
+ mp3.save()
+ return image_url
+
+
+ def search_google(self, search_terms=""):
+ def visible(element):
+ if element.parent.name in ['style', 'script', '[document]', 'head', 'title']:
+ return False
+ elif match('', str(element)):
+ return False
+ return True
+
+ search_terms = "%s %s %s" % (self.song, self.artist, search_terms)
+ url = 'http://www.google.com/search?q=' + quote_plus(search_terms)
+
+ hdr = {
+ 'User-Agent':'Mozilla/5.0',
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
+ }
+
+ texts = BeautifulSoup(urlopen(Request(url, \
+ headers=hdr)).read(), 'html.parser').findAll(text=True)
+
+ return list(filter(visible, texts))
diff --git a/irs/utils.py b/irs/utils.py
index 545c3b2..b75e33f 100644
--- a/irs/utils.py
+++ b/irs/utils.py
@@ -53,3 +53,37 @@ def color(text, colors=[]):
color_string += "bc.%s + " % color
color_string = color_string[:-2]
return (bc.ENDC + eval(color_string) + text + bc.ENDC)
+
+def color_input(text):
+ print (bc.HEADER + text, end=" ")
+ return input(bc.BOLD + bc.YELLOW + ": " + bc.ENDC)
+
+def exclaim_good(text, item):
+ print (bc.OKGREEN + text + bc.ENDC + item)
+
+def test_goodness(test, word, metadata_id, mp3):
+ if test:
+ exclaim_good(word + " added: ", mp3.get_attr(metadata_id))
+ else:
+ print (bc.FAIL + word + " not added." + bc.ENDC)
+
+def search_google(self, search_terms=""):
+ def visible(element):
+ if element.parent.name in ['style', 'script', '[document]', 'head', 'title']:
+ return False
+ elif match('', str(element)):
+ return False
+ return True
+
+ search_terms = "%s %s %s" % (self.song, self.artist, search_terms)
+ url = 'http://www.google.com/search?q=' + quote_plus(search_terms)
+
+ hdr = {
+ 'User-Agent':'Mozilla/5.0',
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
+ }
+
+ texts = BeautifulSoup(urlopen(Request(url, \
+ headers=hdr)).read(), 'html.parser').findAll(text=True)
+
+ return list(filter(visible, texts))
diff --git a/setup.py b/setup.py
index 847282b..9005ac9 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@ from setuptools import setup
setup(
name='irs',
- version='1.6.12',
+ version='2.6.12',
description='A music downloader that just gets metadata.',
url='https://github.com/kepoorhampond/irs',
author='Kepoor Hampond',