Bläddra i källkod

Partial commit. WIP

Miek Stagl 5 år sedan
förälder
incheckning
2e8b3b3a3b
5 ändrade filer med 362 tillägg och 60 borttagningar
  1. 11 0
      CHANGELOG
  2. 17 0
      config.ini
  3. 0 0
      list.txt
  4. 209 60
      ytsearch
  5. 125 0
      ytsearch.save

+ 11 - 0
CHANGELOG

@@ -0,0 +1,11 @@
+Version 0.0.1 Initial Development
+  
+Version 0.0.2 - 5/12/2020
+  - Split program into several callable functions
+  - Added config file reader for variables
+  - Added Iteration function to retry ultiple appempts to download all files
+  - Changed audio-format from mp3 to best
+  - Added getopts routine to check for command line arguments
+    - Command line arguments will override config.ini for download=true
+    - will take -d and number to download jsons from Discogs.com API
+  - Added first implementation of Verbosity (needs teaking)

+ 17 - 0
config.ini

@@ -0,0 +1,17 @@
+[DEFAULT]
+Musicfile = list.txt
+DefaultStoragePath = $HOME/Music
+Retries = 3
+Download = False
+Key = AdmufSbEgfzbRjaxHBMvyvdKqBxhNYvCzvXHXWQK
+
+#Set Verbosity level [0-3]
+#0 - Quiet <- Lowest number of messages
+#1 - Error
+#2 - Warn
+#3 - Info <- Highest number of messages
+Verbosity = 3
+
+#Logging location
+#Default is present working directory
+LogLocation = log.txt

+ 0 - 0
list.txt


+ 209 - 60
ytsearch

@@ -2,81 +2,230 @@
 
 from youtube_search import YoutubeSearch
 import os
+import configparser
+import sys, getopt
+import requests, json
 
 ##Import list of songs, artists from list.txt
 ##parse this file into a list of dictionaries
 ##for each dictionary pair, search youtube and output formatted links in file
 ##
-##FUTURE - remove successful downloads from text file!!
-## -assign each line read a number
-## -remember numbers that are successful downloads
-## -at end of script, delete lines from those numbers
-## -OR-
-## -Find lines that match successful downloads
-
-DOWNLOAD=True
-
-musicfile="list.txt"
-
-music=[]
-songnum = 0
-with open(musicfile) as f:
-  for line in f:
-    song={}
-    (key, val) = line.split(", ")
-    songnum += 1
-    song['songnum'] = songnum
-    song['Title'] = key
-    song['Artist'] = val.rstrip()
-    song['raw'] = line
-    music.append(song)
-f.close()
-
-logresults=[]
-linkresults=[]
-completed=[]
-for song in music:
-  searchterm = song['Title'] + " " + song['Artist'] + ' lyrics'
-  dictlink={}
-  try:
-    ytresult = YoutubeSearch(searchterm, max_results=1).to_dict()
-    link = 'https://youtube.com' + ytresult[0]['link']
-    dictlink['Title'] = song['Title']
-    dictlink['Artist'] = song['Artist']
-    dictlink['link'] = link
-    linkresults.append(dictlink)
-    logresults.append(song['Title'] + ", " + song['Artist'] + " Link Created")
-    if DOWNLOAD:
-       print("Attempting to download", song['Title'])
+## - Download over tor
+##   - Check if Tor installed
+##   - Warn user if NOT using tor
+##
+## - Multi-thread conversion to audio format
+##
+## - Logging and Verbosity levels
+##
+## - Check for dependencies
+##    - Tor?
+##    - Write Permissions in log files?
+##    - YoutubeSearch
+##
+## - Differentiate between releases and masters when calling api
+
+##Vars
+if os.path.exists('config.ini'):
+	config = configparser.ConfigParser()
+	config.read('config.ini')
+else:
+	print("Config.ini file not found in", os.getcwd())
+	print("Exiting...")
+	exit(1)
+
+DOWNLOAD=config['DEFAULT'].getboolean('Download')	#Download True/False
+MUSICFILE=config['DEFAULT']['Musicfile']		#location of text file containing songs
+RETRIES=config['DEFAULT'].getint('Retries')		#Number of retries to search for songs
+ITERATOR=0						#Number or current tries
+VERBOSITY=config['DEFAULT'].getint('Verbosity')
+KEY=config['DEFAULT']['Key']
+DISCOG=""
+HELP=	"Takes list.txt or Discogs.com Master/Release number \n" \
+	"And downloads albums by stripping the audio from Yuotube videos. \n" \
+	"USAGE: ytsearch [-flag] [Discog Num] \n" \
+	"	-h 		This help file \n" \
+	"	-d --discog	set Discog.com Release or Master number \n" \
+	"	-D --download	override config.ini and set Download=True"
+JSONDATA=[]
+
+music=[]	# list to hold dictionaries of songnum, Title, Artist
+logresults=[]	# list to hold results of link creation attempts, and download attempts
+linkresults=[]	#
+completed=[]	# list to hold song numbers of completed downloads so they can be removed from MUSICFILE
+
+
+def msg(message, level):
+	##Takes message and log level as arguments
+	##Based  on verbosity from config.ini, return messages to user
+	## 1-ERROR, 2-WARN, 3-INFO, -1 [No flag, always show]
+	tlevel = {-1: '', 1: "ERROR", 2: "WARN", 3: "INFO"}
+	if level <= VERBOSITY:
+		print(tlevel.get(level), message)
+
+def arguments(argv):
+	msg("Starting arguments", 3)
+	try:
+		opts, args = getopt.getopt(argv, "hDd:", ["discogno="])
+		for opt, arg in opts:
+			if opt == '-h':
+				print(HELP)
+				sys.exit()
+			elif opt in ("-d", "--discog"):
+				global DISCOG
+				DISCOG = arg
+				msg("Discog number:" + DISCOG, 3)
+			elif opt in ("-D", "--download"):
+				global DOWNLOAD
+				DOWNLOAD = True
+				msg("Override DOWNLOAD from agrs", 2)
+	except getopt.GetoptError as err:
+		msg("cannot get arguments, {0}".format(err), 1)
+
+def fetchjson(discogno, master=True, show=True):
+	msg("Starting fetchjson", 3)
+	if master:
+		url = 'https://api.discogs.com/masters/'
+	else:
+		url = 'https://api.discogs.com/releases/'
+	url = url + discogno
+	msg("Downloading " + url, 3)
+	r = requests.get(url)
+	global JSONDATA
+#	JSONDATA = r.json()
+	JSONDATA = json.loads(r.text)
+	msg("fetchjson complete!", 3)
+	return JSONDATA
+
+def buildlist(jsondata):
+	## takes raw jsons data from Discogs.com and extracts Album, Artist, and tracklist list
+	## passes tracklist to gettracks to create list of track names
+	## appends "," + artist to end of track names
+	## calls buildfolders to create a home for the new file
+	## writes list to list.txt in appropriate folder
+	msg("Staring Buildlist", 3)
+	try:
+		Artist = jsondata['artists'][0]['name']
+		Album = jsondata['title']
+	except:
+		msg("Could not read Artist or Album Name from Jsonfile", 1)
+		print(sys.exc_info()[0])
+		sys.exit()
+	if Artist.find( '(' ) != -1:	## Discovered a Artist 'Tool (2)' (Discogs 1181).  This removes ()
+		Artist = Artist[:Artist.find( '(' )-1]
+		msg("Correcting Artist name to " + Artist, 2)
+	else:
+		print(Artist)
+
+	print(gettracks(jsondata['tracklist']))
+
+	
+
+
+def gettracks(tracks):
+	## takes raw json data from Discogs.com and creates a tracklist for the album
+	## This will return a list
+	msg("Starting gettracks", 3)
+	goodtracks = []
+
+	for track in tracks:
+		goodtracks.append(track['title'])
+
+	return goodtracks
+
+def buildfolders(jsondata, parent_directory):
+	## Takes raw json data and creates foldes in parent_directory for Artist/Album
+	pass
+
+def readlist(file):
+	msg("Starting readlist", 3)
+	##Open list.txt, read into music[]
+	songnum = 0
+	with open(file) as f:
+	  for line in f:
+	    song={}
+	    (key, val) = line.split(", ")
+	    songnum += 1
+	    song['songnum'] = songnum
+	    song['Title'] = key
+	    song['Artist'] = val.rstrip()
+	    music.append(song)
+	f.close()
+	return music
+
+def parselist(musiclist):
+	msg("Starting parselist", 3)
+	global ITERATOR
+	ITERATOR+=1
+	for song in musiclist:
+	  searchterm = song['Title'] + " " + song['Artist'] + ' lyrics'
+	  dictlink={}
+	  try:
+	    ytresult = YoutubeSearch(searchterm, max_results=1).to_dict() ##increase timeout!!
+	    link = 'https://youtube.com' + ytresult[0]['link']
+	    logresults.append(song['Title'] + ", " + song['Artist'] + " Link Created")
+	    if DOWNLOAD:
+              print("Attempting to download", song['Title'])
+              downloadsong(link, song)
+	    else:
+	      print("Not downloading.  Change this in config.ini")
+	  except:
+	    logresults.append(song['Title'] + ", " + song['Artist'] + " COULD NOT CREATE LINK")
+	if DOWNLOAD:
+		cleanup(MUSICFILE)
+
+def downloadsong(link, song):
+       msg("Starling Downloadsong for" + song['Title'], 3)
        try: 
-         os.system("youtube-dl --extract-audio --audio-format mp3 --output '%(title)s.%(ext)s' --ignore-errors " + link)
+         os.system("youtube-dl --extract-audio --audio-format best --audio-quality 0 --output '%(title)s.%(ext)s' --ignore-errors " + link)
          completed.append(song['songnum'])
          logresults.append(song['Title'] + ", " + song['Artist'] + " Audio downloaded")
          print("Download Complete!")
        except e as youtubedlexception:
          logresults.append(song['Title'] + ", " + song['Artist'] + " FAILED TO DOWNLOAD SONG (youtube-dl)")
          print(youtubedlexception)
-    else:
-      print("ERROR: Not Downloading for some reason")
-  except:
-    logresults.append(song['Title'] + ", " + song['Artist'] + " COULD NOT CREATE LINK")
+	
+
+def cleanup(file):
+	print("Cleaning completed files from list")
+	print("Completed Downloads:", completed)
+
+	linenum=0
+	count=0
+	with open(file, "r") as f:
+	  lines = f.readlines()
+	with open(file, "w") as f:
+	  for line in lines:
+	    linenum += 1
+	    if linenum not in completed:
+	     f.write(line)
+	     count += 1
+
+	f.close()
 
-print("------------")
-for r in logresults:
-  print(r)
+	if count >=1:
+		print(count, "TRACKS REMAIN")
+		print(RETRIES - ITERATOR, "tries remaining")
+		if ITERATOR <= RETRIES:
+			print("Retrying")
+			global music
+			music = []
+			parselist(readlist(MUSICFILE))
+	else:
+		msg("All downloads complete!", -1)
 
+if __name__ == "__main__":
 
-print(completed)
+#	msg("Starting ytsearch...", -1)
 
-print("Cleaning completed files from list")
+	arguments(sys.argv[1:])
 
-linenum=0
-with open(musicfile, "r") as f:
-  lines = f.readlines()
-with open(musicfile, "w") as f:
-  for line in lines:
-    linenum += 1
-    if linenum not in completed:
-     f.write(line)
+	if DISCOG != "":
+		msg("DISCOG found, fetch json", 3)
+#		print(fetchjson(DISCOG))
+#		print(json_file)
+		buildlist(fetchjson(DISCOG))
+	readlist(MUSICFILE)
+	parselist(music)
 
-f.close()
+	msg("ytsearch complete, exiting", -1)

+ 125 - 0
ytsearch.save

@@ -0,0 +1,125 @@
+#!/usr/bin/python3
+
+from youtube_search import YoutubeSearch
+import os
+
+##Import list of songs, artists from list.txt
+##parse this file into a list of dictionaries
+##for each dictionary pair, search youtube and output formatted links in file
+##
+## FUTURE
+## -Config File
+##    -Default Musicfile
+##    -Defualt retrys
+##    -Default save-to location
+##    -Default verbosity and logging location
+##
+## - Download over tor
+##   - Check if Tor installed
+##   - Warn user if NOT using tor
+##
+## - Multi-thread conversion mp3
+##
+## - Retry up to X times the link-generation routine
+##
+## - Allow discogs reference number as argument
+##   - ytsearch will parse discogs website with BeautifulSoup
+##   - Find the Artist, Album Track Titles
+##   - Create folder structure locally and create list.txt
+##   - Begin processing...
+##
+## - Logging and Verbosit levels
+##
+## - Check for dependencies
+##    - Tor?
+##    - Write Permissions in log files?
+##    - YoutubeSearch
+
+##Vars
+
+DOWNLOAD=True
+MUSICFILE="list.txt"
+
+##
+
+
+music=[]	# list to hold dictionaries of songnum, Title, Artist
+logresults=[]	# list to hold results of link creation attempts, and download attempts
+linkresults=[]	#
+completed=[]	# list to hold song numbers of completed downloads so they can be removed from MUSICFILE
+
+##Open list.txt, read into music[]
+def readlist(file):
+	songnum = 0
+	with open(file) as f:
+	  for line in f:
+	    song={}
+	    (key, val) = line.split(", ")
+	    songnum += 1
+	    song['songnum'] = songnum
+	    song['Title'] = key
+	    song['Artist'] = val.rstrip()
+#	    song['raw'] = line
+	    music.append(song)
+	f.close()
+	return music
+
+def parselist(musiclist):
+	for song in musiclist:
+	  searchterm = song['Title'] + " " + song['Artist'] + ' lyrics'
+	  dictlink={}
+	  try:
+	    ytresult = YoutubeSearch(searchterm, max_results=1).to_dict() ##increase timeout!!
+	    link = 'https://youtube.com' + ytresult[0]['link']
+cherokee2
+
+cherokee2
+	    logresults.append(song['Title'] + ", " + song['Artist'] + " Link Created")
+	    if DOWNLOAD:
+              print("Attempting to download", song['Title'])
+              downloadsong(link, song)
+	    else:
+	      print("ERROR: Not Downloading for some reason")
+	  except:
+	    logresults.append(song['Title'] + ", " + song['Artist'] + " COULD NOT CREATE LINK")
+	cleanup(MUSICFILE)
+
+def downloadsong(link, song):
+       try: 
+         os.system("youtube-dl --extract-audio --audio-format mp3 --audio-quality 0 --output '%(title)s.%(ext)s' --ignore-errors " + link)
+         completed.append(song['songnum'])
+         logresults.append(song['Title'] + ", " + song['Artist'] + " Audio downloaded")
+         print("Download Complete!")
+       except e as youtubedlexception:
+         logresults.append(song['Title'] + ", " + song['Artist'] + " FAILED TO DOWNLOAD SONG (youtube-dl)")
+         print(youtubedlexception)
+	
+
+def cleanup(file):
+	print("Cleaning completed files from list")
+	print("Completed Downloads:", completed)
+
+	linenum=0
+	with open(file, "r") as f:
+	  lines = f.readlines()
+	with open(file, "w") as f:
+	  for line in lines:
+	    linenum += 1
+	    if linenum not in completed:
+	     f.write(line)
+
+	f.close()
+
+
+if __name__ == "__main__":
+	readlist(MUSICFILE)
+	parselist(music)
+
+
+print("------------")
+for r in logresults:
+  print(r)
+
+
+#print(completed)
+