|
@@ -6,6 +6,7 @@ import configparser
|
|
|
import sys, getopt
|
|
import sys, getopt
|
|
|
import requests, json
|
|
import requests, json
|
|
|
import random, string
|
|
import random, string
|
|
|
|
|
+import logging
|
|
|
|
|
|
|
|
##Import list of songs, artists from list.txt
|
|
##Import list of songs, artists from list.txt
|
|
|
##parse this file into a list of dictionaries
|
|
##parse this file into a list of dictionaries
|
|
@@ -32,7 +33,7 @@ import random, string
|
|
|
##
|
|
##
|
|
|
## - Download the first X results from YoutubeSearch and pick best result
|
|
## - Download the first X results from YoutubeSearch and pick best result
|
|
|
##
|
|
##
|
|
|
-## - increase timeout in YoutubeSearch
|
|
|
|
|
|
|
+## - Allow interrupt to stop script (CTRL + C)
|
|
|
|
|
|
|
|
##Vars
|
|
##Vars
|
|
|
if os.path.exists('config.ini'):
|
|
if os.path.exists('config.ini'):
|
|
@@ -47,19 +48,23 @@ VERSION="0.0.3"
|
|
|
DOWNLOAD=config['DEFAULT'].getboolean('Download') #Download True/False
|
|
DOWNLOAD=config['DEFAULT'].getboolean('Download') #Download True/False
|
|
|
MUSICFILE=config['DEFAULT']['Musicfile'] #location of text file containing songs
|
|
MUSICFILE=config['DEFAULT']['Musicfile'] #location of text file containing songs
|
|
|
RETRIES=config['DEFAULT'].getint('Retries') #Number of retries to search for songs
|
|
RETRIES=config['DEFAULT'].getint('Retries') #Number of retries to search for songs
|
|
|
|
|
+LOGPATH=config['DEFAULT']['LogLocation']
|
|
|
ITERATOR=0 #Number or current tries
|
|
ITERATOR=0 #Number or current tries
|
|
|
|
|
+STORAGEPATH=config['DEFAULT']['DefaultStoragePath']
|
|
|
VERBOSITY=config['DEFAULT'].getint('Verbosity')
|
|
VERBOSITY=config['DEFAULT'].getint('Verbosity')
|
|
|
KEY=config['DEFAULT']['Key']
|
|
KEY=config['DEFAULT']['Key']
|
|
|
DISCOG=""
|
|
DISCOG=""
|
|
|
DESTFOLDER=""
|
|
DESTFOLDER=""
|
|
|
ALBUM=""
|
|
ALBUM=""
|
|
|
ARTIST=""
|
|
ARTIST=""
|
|
|
|
|
+MASTER=True
|
|
|
TESTFOLDER=config['DEFAULT'].getboolean('TestFolder')
|
|
TESTFOLDER=config['DEFAULT'].getboolean('TestFolder')
|
|
|
HELP= "Takes list.txt or Discogs.com Master/Release number \n" \
|
|
HELP= "Takes list.txt or Discogs.com Master/Release number \n" \
|
|
|
"And downloads albums by stripping the audio from Yuotube videos. \n" \
|
|
"And downloads albums by stripping the audio from Yuotube videos. \n" \
|
|
|
"USAGE: ytsearch [-flag] [Discog Num] \n" \
|
|
"USAGE: ytsearch [-flag] [Discog Num] \n" \
|
|
|
" -h This help file \n" \
|
|
" -h This help file \n" \
|
|
|
" -d --discog set Discog.com Release or Master number \n" \
|
|
" -d --discog set Discog.com Release or Master number \n" \
|
|
|
|
|
+ " -r --release search for Discog.com RELEASE instead of MASTER [default MASTER] \n" \
|
|
|
" -D --download override config.ini and set Download=True \n" \
|
|
" -D --download override config.ini and set Download=True \n" \
|
|
|
" -f --file Allows quick download of a single Youtube link"
|
|
" -f --file Allows quick download of a single Youtube link"
|
|
|
# " -D --download override config.ini and set Download=True"
|
|
# " -D --download override config.ini and set Download=True"
|
|
@@ -78,11 +83,13 @@ def msg(message, level):
|
|
|
tlevel = {-1: '', 1: "ERROR", 2: "WARN", 3: "INFO"}
|
|
tlevel = {-1: '', 1: "ERROR", 2: "WARN", 3: "INFO"}
|
|
|
if level <= VERBOSITY:
|
|
if level <= VERBOSITY:
|
|
|
print(tlevel.get(level), message)
|
|
print(tlevel.get(level), message)
|
|
|
|
|
+
|
|
|
|
|
+ ## Add logging ##T
|
|
|
|
|
|
|
|
def arguments(argv):
|
|
def arguments(argv):
|
|
|
msg("Starting arguments", 3)
|
|
msg("Starting arguments", 3)
|
|
|
try:
|
|
try:
|
|
|
- opts, args = getopt.getopt(argv, "hvDf:d:", ["discog", "help", "download", "version", "file"])
|
|
|
|
|
|
|
+ opts, args = getopt.getopt(argv, "hvrDf:d:", ["discog", "release", "help", "download", "version", "file"])
|
|
|
for opt, arg in opts:
|
|
for opt, arg in opts:
|
|
|
if opt in ('-h', '--help'):
|
|
if opt in ('-h', '--help'):
|
|
|
print(HELP)
|
|
print(HELP)
|
|
@@ -98,6 +105,10 @@ def arguments(argv):
|
|
|
elif opt in ("-v", "--version"):
|
|
elif opt in ("-v", "--version"):
|
|
|
msg("Version: " + VERSION, -1)
|
|
msg("Version: " + VERSION, -1)
|
|
|
sys.exit()
|
|
sys.exit()
|
|
|
|
|
+ elif opt in ("-r", "--release"):
|
|
|
|
|
+ global MASTER
|
|
|
|
|
+ MASTER=False
|
|
|
|
|
+ msg("searching for Release, not Master at Discogs.com", 1)
|
|
|
elif opt in ("-f", "--file"):
|
|
elif opt in ("-f", "--file"):
|
|
|
msg("call singlesong with: " + arg, 3)
|
|
msg("call singlesong with: " + arg, 3)
|
|
|
singlesong(arg)
|
|
singlesong(arg)
|
|
@@ -182,8 +193,10 @@ def buildfolders(artist, album=""):
|
|
|
# msg("buildfolders local album is set to: " + album, 3)
|
|
# msg("buildfolders local album is set to: " + album, 3)
|
|
|
global DESTFOLDER
|
|
global DESTFOLDER
|
|
|
DESTFOLDER = artist + "/" + album + "/"
|
|
DESTFOLDER = artist + "/" + album + "/"
|
|
|
|
|
+ home = os.path.expanduser('~')
|
|
|
if TESTFOLDER:
|
|
if TESTFOLDER:
|
|
|
- DESTFOLDER = randomizer() + "/" + DESTFOLDER
|
|
|
|
|
|
|
+ DESTFOLDER = os.path.join(home, randomizer(), DESTFOLDER)
|
|
|
|
|
+ DESTFOLDER = os.path.join(home, STORAGEPATH, DESTFOLDER)
|
|
|
try:
|
|
try:
|
|
|
os.makedirs(DESTFOLDER)
|
|
os.makedirs(DESTFOLDER)
|
|
|
msg("Folder " + DESTFOLDER + " created", 2)
|
|
msg("Folder " + DESTFOLDER + " created", 2)
|
|
@@ -210,29 +223,76 @@ def readlist(file):
|
|
|
f.close()
|
|
f.close()
|
|
|
return music
|
|
return music
|
|
|
|
|
|
|
|
-def searchlinks(links):
|
|
|
|
|
- ## Takes a list of dictionaries and parses the results
|
|
|
|
|
- ## Discards bad choices
|
|
|
|
|
- ## Returns a dictionary of one entry (best result)
|
|
|
|
|
- for link in links:
|
|
|
|
|
- print(link)
|
|
|
|
|
- print("\n")
|
|
|
|
|
- sys.exit()
|
|
|
|
|
|
|
+#def searchlinks(links, artist):
|
|
|
|
|
+# ## Takes a list of dictionaries and parses the results
|
|
|
|
|
+# ## Discards bad choices
|
|
|
|
|
+# ## Returns a dictionary of one entry (best result)
|
|
|
|
|
+# ## Good results include published by artist,
|
|
|
|
|
+# ## bad results include words live "live" or "Video"
|
|
|
|
|
+# msg("Starting searchlinks", 3)
|
|
|
|
|
+# list_badterms = ["live", "video", "sexy"]
|
|
|
|
|
+#
|
|
|
|
|
+# ### FIX RANKINGS! ##
|
|
|
|
|
+#
|
|
|
|
|
+# for link in links:
|
|
|
|
|
+# rating = 0
|
|
|
|
|
+# for term in list_badterms:
|
|
|
|
|
+# if term.lower() in link['title'].lower():
|
|
|
|
|
+## print("Contains Term!")
|
|
|
|
|
+# rating -= 1
|
|
|
|
|
+# print(rating)
|
|
|
|
|
+# if artist != "":
|
|
|
|
|
+# if artist.lower() == link['publisher'].lower():
|
|
|
|
|
+## print("Published by Artist!")
|
|
|
|
|
+# rating += 10
|
|
|
|
|
+# link["rating"] = rating
|
|
|
|
|
+#
|
|
|
|
|
+# links.sort(reverse=True, key = lambda i: i['rating']) ## Sort links based on rating
|
|
|
|
|
+# msg("Ending serachlinks", 3)
|
|
|
|
|
+# return links[0]
|
|
|
|
|
+
|
|
|
|
|
+def generatelink(searchterm, max_results=10, tries=5):
|
|
|
|
|
+ ## This will retry the link generation routine up to *tries* times and return results
|
|
|
|
|
+ msg("Starting generatelink for " + searchterm, 3)
|
|
|
|
|
+ counter = 0
|
|
|
|
|
+ while counter <= tries:
|
|
|
|
|
+ try:
|
|
|
|
|
+ ytresult = YoutubeSearch(searchterm, max_results).to_dict()
|
|
|
|
|
+ if len(ytresult) > 0:
|
|
|
|
|
+ msg("Link Generated!", 3)
|
|
|
|
|
+ break
|
|
|
|
|
+ else:
|
|
|
|
|
+ raise IndexError("Index Empty")
|
|
|
|
|
+ except:
|
|
|
|
|
+ msg("Unable to generate link on try " + str(counter), 3)
|
|
|
|
|
+ counter += 1
|
|
|
|
|
+ if counter >= tries:
|
|
|
|
|
+ msg("Could Not Generate link for " + searchterm, 2)
|
|
|
|
|
+ raise IndexError("Could not Generate Link")
|
|
|
|
|
+# finally:
|
|
|
|
|
+# msg("Ending generatelink on try " + str(counter), 3)
|
|
|
|
|
+
|
|
|
|
|
+# searchlinks(ytresult)
|
|
|
|
|
+ return ytresult
|
|
|
|
|
|
|
|
def parselist(musiclist):
|
|
def parselist(musiclist):
|
|
|
msg("Starting parselist", 3)
|
|
msg("Starting parselist", 3)
|
|
|
global ITERATOR
|
|
global ITERATOR
|
|
|
- if ITERATOR == 0 and DOWNLOAD:
|
|
|
|
|
|
|
+ if ITERATOR == 0 and DOWNLOAD: ## <- Original Line
|
|
|
|
|
+# if ITERATOR == 0: ## <- Used only for testing buildfolders
|
|
|
buildfolders(musiclist[0]['Artist'])
|
|
buildfolders(musiclist[0]['Artist'])
|
|
|
ITERATOR+=1
|
|
ITERATOR+=1
|
|
|
for song in musiclist:
|
|
for song in musiclist:
|
|
|
# searchterm = song['Title'] + " " + song['Artist'] + ' lyrics HD'
|
|
# searchterm = song['Title'] + " " + song['Artist'] + ' lyrics HD'
|
|
|
searchterm = song['Title'] + " " + song['Artist']
|
|
searchterm = song['Title'] + " " + song['Artist']
|
|
|
dictlink={}
|
|
dictlink={}
|
|
|
|
|
+
|
|
|
try:
|
|
try:
|
|
|
- ytresult = YoutubeSearch(searchterm, max_results=5).to_dict() ##increase timeout!!
|
|
|
|
|
-# searchlinks(ytresult)
|
|
|
|
|
|
|
+## ytresult = generatelink(searchterm)
|
|
|
|
|
+## bestlink = searchlinks(ytresult, song['Artist'])
|
|
|
|
|
+ ytresult = generatelink(searchterm)
|
|
|
link = 'https://youtube.com' + ytresult[0]['link']
|
|
link = 'https://youtube.com' + ytresult[0]['link']
|
|
|
|
|
+# link = 'https://youtube.com' + bestlink['link']
|
|
|
logresults.append(song['Title'] + ", " + song['Artist'] + " Link Created")
|
|
logresults.append(song['Title'] + ", " + song['Artist'] + " Link Created")
|
|
|
if DOWNLOAD:
|
|
if DOWNLOAD:
|
|
|
msg("Attempting to download " + song['Title'], 2)
|
|
msg("Attempting to download " + song['Title'], 2)
|
|
@@ -240,7 +300,10 @@ def parselist(musiclist):
|
|
|
else:
|
|
else:
|
|
|
print("Not downloading " + song['Title'] + ". Change this in config.ini")
|
|
print("Not downloading " + song['Title'] + ". Change this in config.ini")
|
|
|
except Exception as ex:
|
|
except Exception as ex:
|
|
|
- print(ex)
|
|
|
|
|
|
|
+ print(song['Title'], ex)
|
|
|
|
|
+
|
|
|
|
|
+# searchlinks(ytresult, song['Artist'])
|
|
|
|
|
+
|
|
|
if DOWNLOAD:
|
|
if DOWNLOAD:
|
|
|
cleanup(MUSICFILE)
|
|
cleanup(MUSICFILE)
|
|
|
|
|
|
|
@@ -248,10 +311,6 @@ def downloadsong(link, song):
|
|
|
msg("Starling Downloadsong for " + song['Title'], 3)
|
|
msg("Starling Downloadsong for " + song['Title'], 3)
|
|
|
msg("Downloadsong DESTFOLDER: " + DESTFOLDER, 3)
|
|
msg("Downloadsong DESTFOLDER: " + DESTFOLDER, 3)
|
|
|
try:
|
|
try:
|
|
|
-#####
|
|
|
|
|
-##Fix Destination Path
|
|
|
|
|
-##HOW DID I DO THIS BEFORE??
|
|
|
|
|
-#####
|
|
|
|
|
os.system("youtube-dl --extract-audio --audio-format best --audio-quality 0 --output '''" + DESTFOLDER + "%(title)s.%(ext)s' --ignore-errors " + link)
|
|
os.system("youtube-dl --extract-audio --audio-format best --audio-quality 0 --output '''" + DESTFOLDER + "%(title)s.%(ext)s' --ignore-errors " + link)
|
|
|
completed.append(song['songnum'])
|
|
completed.append(song['songnum'])
|
|
|
logresults.append(song['Title'] + ", " + song['Artist'] + " Audio downloaded")
|
|
logresults.append(song['Title'] + ", " + song['Artist'] + " Audio downloaded")
|
|
@@ -297,14 +356,11 @@ def cleanup(file):
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if __name__ == "__main__":
|
|
|
|
|
|
|
|
-# msg("Starting ytsearch...", -1)
|
|
|
|
|
-
|
|
|
|
|
arguments(sys.argv[1:])
|
|
arguments(sys.argv[1:])
|
|
|
|
|
|
|
|
if DISCOG != "":
|
|
if DISCOG != "":
|
|
|
msg("DISCOG found, fetch json", 3)
|
|
msg("DISCOG found, fetch json", 3)
|
|
|
-# print(fetchjson(DISCOG))
|
|
|
|
|
- buildlist(fetchjson(DISCOG), True)
|
|
|
|
|
|
|
+ buildlist(fetchjson(DISCOG), MASTER)
|
|
|
readlist(MUSICFILE)
|
|
readlist(MUSICFILE)
|
|
|
parselist(music)
|
|
parselist(music)
|
|
|
|
|
|