youtube.py~ 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. # This is a youtube-dl youtube song downloader. It uses both youtube-dl
  2. # for actual download and the invidious API for fetching info about the
  3. # song. GPLv3+
  4. import os
  5. from subprocess import *
  6. import json
  7. import random
  8. import urllib.request
  9. import urllib.parse
  10. dfolder = "downloads"
  11. def difference(x,y):
  12. if x > y:
  13. return x - y
  14. else:
  15. return y - x
  16. def fetch_info(videoId):
  17. # This function will output the info about our song.
  18. try:
  19. url = "https://invidious.namazso.eu/api/v1/videos/"+videoId
  20. req = urllib.request.Request(url, data=None)
  21. f = urllib.request.urlopen(req)
  22. data = json.loads(f.read().decode('utf-8'))
  23. except:
  24. url = "https://yewtu.be/api/v1/videos/"+videoId
  25. req = urllib.request.Request(url, data=None)
  26. f = urllib.request.urlopen(req)
  27. data = json.loads(f.read().decode('utf-8'))
  28. return data
  29. def search(query):
  30. # This function will search on youtube a query.
  31. url = "https://invidious.namazso.eu/api/v1/search/?q="+urllib.parse.quote_plus(query)
  32. req = urllib.request.Request(url, data=None)
  33. f = urllib.request.urlopen(req)
  34. data = json.loads(f.read().decode('utf-8'))
  35. return data
  36. def try_download(videoId, filename):
  37. # This fucntion will try download the song via youtube-dl
  38. #print("Trying to download", videoId)
  39. # Making sure that the download folder exists
  40. try:
  41. os.mkdir(dfolder)
  42. except:
  43. pass
  44. try:
  45. # We are using subbrocess.check_output here to catch errors.
  46. check_output(["youtube-dl",
  47. "https://youtube.com/watch?v="+videoId,
  48. "-x",
  49. "--output",
  50. dfolder+"/"+str(filename)+".%(ext)s"])
  51. return True
  52. except Exception as e:
  53. print("youtube-dl error", e)
  54. return False
  55. def insure_song(videoId, filename):
  56. # This function will insure a song is downloaded.
  57. songInfo = fetch_info(videoId)
  58. #print("Song", songInfo["title"], "by", songInfo["author"], "direct attempt.")
  59. # First we will try downloading the song as is.
  60. if try_download(videoId, filename):
  61. #print("Worked!")
  62. return True
  63. else:
  64. #print("Failed! Trying similar...")
  65. # If it failed we are going to try downloading a similar song.
  66. titleblacklist = ["cover", "react", "review", "remix", "acoustic", "teaser", "live"]
  67. query = songInfo["title"]
  68. if " - Topic" in songInfo["author"]:
  69. query = songInfo["author"].replace(" - Topic", "")+" "+query
  70. others = search(query)
  71. for song in others:
  72. # Chekcing that it's a video
  73. if song["type"] != "video":
  74. print("Skipped:", song["title"], "because not a video." )
  75. continue
  76. # Checking if the song is a cover or a remix
  77. cont = False
  78. for i in titleblacklist:
  79. if i.lower() in song["title"].lower():
  80. cont = i
  81. break
  82. if cont:
  83. #print("Skipped:", song["title"], "because", cont )
  84. continue
  85. # Chekcing the length of the song to be roughly the original
  86. if difference(song["lengthSeconds"], songInfo["lengthSeconds"]) > 60:
  87. print("Skipped:", song["title"], "because length is too different." )
  88. continue
  89. #print("Trying to download", song["title"])
  90. if try_download(song["videoId"], filename):
  91. return "Got Similar"
  92. return False