Add all files
This commit is contained in:
5
cowboy bebop lofi.url
Executable file
5
cowboy bebop lofi.url
Executable file
@@ -0,0 +1,5 @@
|
||||
[{000214A0-0000-0000-C000-000000000046}]
|
||||
Prop3=19,11
|
||||
[InternetShortcut]
|
||||
IDList=
|
||||
URL=https://www.youtube.com/watch?v=Z-Rl3LhVakc
|
||||
8
download-soundcloud.sh
Executable file
8
download-soundcloud.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
echo "Downloading $1"
|
||||
source .env/bin/activate
|
||||
scdl -l $1
|
||||
|
||||
./process_music.sh
|
||||
|
||||
echo "Done!"
|
||||
8
download-spotify.sh
Executable file
8
download-spotify.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
echo "Downloading spotify song $1"
|
||||
source .env/bin/activate
|
||||
python3 download_spotify.py $1
|
||||
|
||||
./process_music.sh
|
||||
|
||||
echo "Done!"
|
||||
8
download-youtube.sh
Executable file
8
download-youtube.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
echo "Downloading youtube song $1"
|
||||
source .env/bin/activate
|
||||
python3 download_youtube.py $1
|
||||
|
||||
./process_music.sh
|
||||
|
||||
echo "Done!"
|
||||
18
download_soundcloud.py
Executable file
18
download_soundcloud.py
Executable file
@@ -0,0 +1,18 @@
|
||||
import sys
|
||||
from subprocess import call
|
||||
import subprocess
|
||||
def main():
|
||||
if (len(sys.argv) != 2):
|
||||
print("Wrong parameters!")
|
||||
sys.exit(-1)
|
||||
url = sys.argv[1].strip()
|
||||
print("passing link " + str(url))
|
||||
if ("soundcloud" not in url):
|
||||
print("Url has to be a soundcloud link!")
|
||||
sys.exit(-1)
|
||||
print("executing command")
|
||||
call("cd /home/sem/TODO\ MUSIC/",shell=True)
|
||||
call("./download-soundcloud.sh " + url,shell=True)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
26
download_spotify.py
Executable file
26
download_spotify.py
Executable file
@@ -0,0 +1,26 @@
|
||||
import sys
|
||||
from subprocess import call
|
||||
import re
|
||||
|
||||
url_pattern = "^https?:\\/\\/(?:www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b(?:[-a-zA-Z0-9()@:%_\\+.~#?&\\/=]*)$"
|
||||
|
||||
def main():
|
||||
if (len(sys.argv) != 2):
|
||||
print("Wrong parameters!")
|
||||
sys.exit(-1)
|
||||
url = sys.argv[1].strip()
|
||||
print("passing link " + str(url))
|
||||
if (re.match(url_pattern,url) == None):
|
||||
print("Url has to be a valid link!")
|
||||
sys.exit(-1)
|
||||
|
||||
if ("spotify" not in url or "https://" not in url):
|
||||
print("Url has to be a spotify link!")
|
||||
sys.exit(-1)
|
||||
print("executing command")
|
||||
call("cd \"/home/sem/TODO MUSIC\"", shell=True)
|
||||
call("spotdl download " + url, shell=True, user="sem")
|
||||
# call("./download-spotify.sh " + url, shell=True, user="sem") # run as user sem to have the SPOTIPY_CLIENT_ID and SPOTIPY_CLIENT_SECRET environment variables set
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
18
download_youtube.py
Normal file
18
download_youtube.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from __future__ import unicode_literals
|
||||
import yt_dlp
|
||||
import sys
|
||||
|
||||
ydl_opts = {
|
||||
'format': 'bestaudio/best',
|
||||
'postprocessors': [{
|
||||
'key': 'FFmpegExtractAudio',
|
||||
'preferredcodec': 'mp3',
|
||||
'preferredquality': '0', # 0 = best quality
|
||||
}],
|
||||
}
|
||||
|
||||
url = sys.argv[1]
|
||||
print("Downloading youtube song " + url)
|
||||
|
||||
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
||||
ydl.download([url])
|
||||
888
example result.txt
Executable file
888
example result.txt
Executable file
@@ -0,0 +1,888 @@
|
||||
[
|
||||
{
|
||||
"album": {
|
||||
"album_type": "compilation",
|
||||
"artists": [
|
||||
{
|
||||
"external_urls": {
|
||||
"spotify": "https://open.spotify.com/artist/7dGJo4pcD2V6oG8kP0tJRR"
|
||||
},
|
||||
"href": "https://api.spotify.com/v1/artists/7dGJo4pcD2V6oG8kP0tJRR",
|
||||
"id": "7dGJo4pcD2V6oG8kP0tJRR",
|
||||
"name": "Eminem",
|
||||
"type": "artist",
|
||||
"uri": "spotify:artist:7dGJo4pcD2V6oG8kP0tJRR",
|
||||
}
|
||||
],
|
||||
"available_markets": [
|
||||
"AD",
|
||||
"AE",
|
||||
"AG",
|
||||
"AL",
|
||||
"AM",
|
||||
"AO",
|
||||
"AR",
|
||||
"AT",
|
||||
"AU",
|
||||
"AZ",
|
||||
"BA",
|
||||
"BB",
|
||||
"BD",
|
||||
"BE",
|
||||
"BF",
|
||||
"BG",
|
||||
"BH",
|
||||
"BI",
|
||||
"BJ",
|
||||
"BN",
|
||||
"BO",
|
||||
"BR",
|
||||
"BS",
|
||||
"BT",
|
||||
"BW",
|
||||
"BY",
|
||||
"BZ",
|
||||
"CA",
|
||||
"CD",
|
||||
"CG",
|
||||
"CH",
|
||||
"CI",
|
||||
"CL",
|
||||
"CM",
|
||||
"CO",
|
||||
"CR",
|
||||
"CV",
|
||||
"CW",
|
||||
"CY",
|
||||
"CZ",
|
||||
"DE",
|
||||
"DJ",
|
||||
"DK",
|
||||
"DM",
|
||||
"DO",
|
||||
"DZ",
|
||||
"EC",
|
||||
"EE",
|
||||
"EG",
|
||||
"ES",
|
||||
"FI",
|
||||
"FJ",
|
||||
"FM",
|
||||
"FR",
|
||||
"GA",
|
||||
"GB",
|
||||
"GD",
|
||||
"GE",
|
||||
"GH",
|
||||
"GM",
|
||||
"GN",
|
||||
"GQ",
|
||||
"GR",
|
||||
"GT",
|
||||
"GW",
|
||||
"GY",
|
||||
"HK",
|
||||
"HN",
|
||||
"HR",
|
||||
"HT",
|
||||
"HU",
|
||||
"ID",
|
||||
"IE",
|
||||
"IL",
|
||||
"IN",
|
||||
"IQ",
|
||||
"IS",
|
||||
"IT",
|
||||
"JM",
|
||||
"JO",
|
||||
"JP",
|
||||
"KE",
|
||||
"KG",
|
||||
"KH",
|
||||
"KI",
|
||||
"KM",
|
||||
"KN",
|
||||
"KR",
|
||||
"KW",
|
||||
"KZ",
|
||||
"LA",
|
||||
"LB",
|
||||
"LC",
|
||||
"LI",
|
||||
"LK",
|
||||
"LR",
|
||||
"LS",
|
||||
"LT",
|
||||
"LU",
|
||||
"LV",
|
||||
"LY",
|
||||
"MA",
|
||||
"MC",
|
||||
"MD",
|
||||
"ME",
|
||||
"MG",
|
||||
"MH",
|
||||
"MK",
|
||||
"ML",
|
||||
"MN",
|
||||
"MO",
|
||||
"MR",
|
||||
"MT",
|
||||
"MU",
|
||||
"MV",
|
||||
"MW",
|
||||
"MX",
|
||||
"MY",
|
||||
"MZ",
|
||||
"NA",
|
||||
"NE",
|
||||
"NG",
|
||||
"NI",
|
||||
"NL",
|
||||
"NO",
|
||||
"NP",
|
||||
"NR",
|
||||
"NZ",
|
||||
"OM",
|
||||
"PA",
|
||||
"PE",
|
||||
"PG",
|
||||
"PH",
|
||||
"PK",
|
||||
"PL",
|
||||
"PS",
|
||||
"PT",
|
||||
"PW",
|
||||
"PY",
|
||||
"QA",
|
||||
"RO",
|
||||
"RS",
|
||||
"RW",
|
||||
"SA",
|
||||
"SB",
|
||||
"SC",
|
||||
"SE",
|
||||
"SG",
|
||||
"SI",
|
||||
"SK",
|
||||
"SL",
|
||||
"SM",
|
||||
"SN",
|
||||
"SR",
|
||||
"ST",
|
||||
"SV",
|
||||
"SZ",
|
||||
"TD",
|
||||
"TG",
|
||||
"TH",
|
||||
"TJ",
|
||||
"TL",
|
||||
"TN",
|
||||
"TO",
|
||||
"TR",
|
||||
"TT",
|
||||
"TV",
|
||||
"TW",
|
||||
"TZ",
|
||||
"UA",
|
||||
"UG",
|
||||
"US",
|
||||
"UY",
|
||||
"UZ",
|
||||
"VC",
|
||||
"VE",
|
||||
"VN",
|
||||
"VU",
|
||||
"WS",
|
||||
"XK",
|
||||
"ZA",
|
||||
"ZM",
|
||||
"ZW",
|
||||
],
|
||||
"external_urls": {
|
||||
"spotify": "https://open.spotify.com/album/5qENHeCSlwWpEzb25peRmQ"
|
||||
},
|
||||
"href": "https://api.spotify.com/v1/albums/5qENHeCSlwWpEzb25peRmQ",
|
||||
"id": "5qENHeCSlwWpEzb25peRmQ",
|
||||
"images": [
|
||||
{
|
||||
"height": 640,
|
||||
"url": "https://i.scdn.co/image/ab67616d0000b273eab40fc794b88b9d1e012578",
|
||||
"width": 640,
|
||||
},
|
||||
{
|
||||
"height": 300,
|
||||
"url": "https://i.scdn.co/image/ab67616d00001e02eab40fc794b88b9d1e012578",
|
||||
"width": 300,
|
||||
},
|
||||
{
|
||||
"height": 64,
|
||||
"url": "https://i.scdn.co/image/ab67616d00004851eab40fc794b88b9d1e012578",
|
||||
"width": 64,
|
||||
},
|
||||
],
|
||||
"name": "Curtain Call: The Hits (Deluxe Edition)",
|
||||
"release_date": "2005-12-06",
|
||||
"release_date_precision": "day",
|
||||
"total_tracks": 24,
|
||||
"type": "album",
|
||||
"uri": "spotify:album:5qENHeCSlwWpEzb25peRmQ",
|
||||
},
|
||||
"artists": [
|
||||
{
|
||||
"external_urls": {
|
||||
"spotify": "https://open.spotify.com/artist/7dGJo4pcD2V6oG8kP0tJRR"
|
||||
},
|
||||
"href": "https://api.spotify.com/v1/artists/7dGJo4pcD2V6oG8kP0tJRR",
|
||||
"id": "7dGJo4pcD2V6oG8kP0tJRR",
|
||||
"name": "Eminem",
|
||||
"type": "artist",
|
||||
"uri": "spotify:artist:7dGJo4pcD2V6oG8kP0tJRR",
|
||||
}
|
||||
],
|
||||
"available_markets": [
|
||||
"AD",
|
||||
"AE",
|
||||
"AG",
|
||||
"AL",
|
||||
"AM",
|
||||
"AO",
|
||||
"AR",
|
||||
"AT",
|
||||
"AU",
|
||||
"AZ",
|
||||
"BA",
|
||||
"BB",
|
||||
"BD",
|
||||
"BE",
|
||||
"BF",
|
||||
"BG",
|
||||
"BH",
|
||||
"BI",
|
||||
"BJ",
|
||||
"BN",
|
||||
"BO",
|
||||
"BR",
|
||||
"BS",
|
||||
"BT",
|
||||
"BW",
|
||||
"BY",
|
||||
"BZ",
|
||||
"CA",
|
||||
"CD",
|
||||
"CG",
|
||||
"CH",
|
||||
"CI",
|
||||
"CL",
|
||||
"CM",
|
||||
"CO",
|
||||
"CR",
|
||||
"CV",
|
||||
"CW",
|
||||
"CY",
|
||||
"CZ",
|
||||
"DE",
|
||||
"DJ",
|
||||
"DK",
|
||||
"DM",
|
||||
"DO",
|
||||
"DZ",
|
||||
"EC",
|
||||
"EE",
|
||||
"EG",
|
||||
"ES",
|
||||
"FI",
|
||||
"FJ",
|
||||
"FM",
|
||||
"FR",
|
||||
"GA",
|
||||
"GB",
|
||||
"GD",
|
||||
"GE",
|
||||
"GH",
|
||||
"GM",
|
||||
"GN",
|
||||
"GQ",
|
||||
"GR",
|
||||
"GT",
|
||||
"GW",
|
||||
"GY",
|
||||
"HK",
|
||||
"HN",
|
||||
"HR",
|
||||
"HT",
|
||||
"HU",
|
||||
"ID",
|
||||
"IE",
|
||||
"IL",
|
||||
"IN",
|
||||
"IQ",
|
||||
"IS",
|
||||
"IT",
|
||||
"JM",
|
||||
"JO",
|
||||
"JP",
|
||||
"KE",
|
||||
"KG",
|
||||
"KH",
|
||||
"KI",
|
||||
"KM",
|
||||
"KN",
|
||||
"KR",
|
||||
"KW",
|
||||
"KZ",
|
||||
"LA",
|
||||
"LB",
|
||||
"LC",
|
||||
"LI",
|
||||
"LK",
|
||||
"LR",
|
||||
"LS",
|
||||
"LT",
|
||||
"LU",
|
||||
"LV",
|
||||
"LY",
|
||||
"MA",
|
||||
"MC",
|
||||
"MD",
|
||||
"ME",
|
||||
"MG",
|
||||
"MH",
|
||||
"MK",
|
||||
"ML",
|
||||
"MN",
|
||||
"MO",
|
||||
"MR",
|
||||
"MT",
|
||||
"MU",
|
||||
"MV",
|
||||
"MW",
|
||||
"MX",
|
||||
"MY",
|
||||
"MZ",
|
||||
"NA",
|
||||
"NE",
|
||||
"NG",
|
||||
"NI",
|
||||
"NL",
|
||||
"NO",
|
||||
"NP",
|
||||
"NR",
|
||||
"NZ",
|
||||
"OM",
|
||||
"PA",
|
||||
"PE",
|
||||
"PG",
|
||||
"PH",
|
||||
"PK",
|
||||
"PL",
|
||||
"PS",
|
||||
"PT",
|
||||
"PW",
|
||||
"PY",
|
||||
"QA",
|
||||
"RO",
|
||||
"RS",
|
||||
"RW",
|
||||
"SA",
|
||||
"SB",
|
||||
"SC",
|
||||
"SE",
|
||||
"SG",
|
||||
"SI",
|
||||
"SK",
|
||||
"SL",
|
||||
"SM",
|
||||
"SN",
|
||||
"SR",
|
||||
"ST",
|
||||
"SV",
|
||||
"SZ",
|
||||
"TD",
|
||||
"TG",
|
||||
"TH",
|
||||
"TJ",
|
||||
"TL",
|
||||
"TN",
|
||||
"TO",
|
||||
"TR",
|
||||
"TT",
|
||||
"TV",
|
||||
"TW",
|
||||
"TZ",
|
||||
"UA",
|
||||
"UG",
|
||||
"US",
|
||||
"UY",
|
||||
"UZ",
|
||||
"VC",
|
||||
"VE",
|
||||
"VN",
|
||||
"VU",
|
||||
"WS",
|
||||
"XK",
|
||||
"ZA",
|
||||
"ZM",
|
||||
"ZW",
|
||||
],
|
||||
"disc_number": 1,
|
||||
"duration_ms": 205760,
|
||||
"explicit": True,
|
||||
"external_ids": {"isrc": "USUM70506387"},
|
||||
"external_urls": {
|
||||
"spotify": "https://open.spotify.com/track/0fMWtRhzOoWoCo7dRHVEEa"
|
||||
},
|
||||
"href": "https://api.spotify.com/v1/tracks/0fMWtRhzOoWoCo7dRHVEEa",
|
||||
"id": "0fMWtRhzOoWoCo7dRHVEEa",
|
||||
"is_local": False,
|
||||
"name": "FACK",
|
||||
"popularity": 63,
|
||||
"preview_url": None,
|
||||
"track_number": 2,
|
||||
"type": "track",
|
||||
"uri": "spotify:track:0fMWtRhzOoWoCo7dRHVEEa",
|
||||
},
|
||||
{
|
||||
"album": {
|
||||
"album_type": "compilation",
|
||||
"artists": [
|
||||
{
|
||||
"external_urls": {
|
||||
"spotify": "https://open.spotify.com/artist/7dGJo4pcD2V6oG8kP0tJRR"
|
||||
},
|
||||
"href": "https://api.spotify.com/v1/artists/7dGJo4pcD2V6oG8kP0tJRR",
|
||||
"id": "7dGJo4pcD2V6oG8kP0tJRR",
|
||||
"name": "Eminem",
|
||||
"type": "artist",
|
||||
"uri": "spotify:artist:7dGJo4pcD2V6oG8kP0tJRR",
|
||||
}
|
||||
],
|
||||
"available_markets": [
|
||||
"AD",
|
||||
"AE",
|
||||
"AG",
|
||||
"AL",
|
||||
"AM",
|
||||
"AO",
|
||||
"AR",
|
||||
"AT",
|
||||
"AU",
|
||||
"AZ",
|
||||
"BA",
|
||||
"BB",
|
||||
"BD",
|
||||
"BE",
|
||||
"BF",
|
||||
"BG",
|
||||
"BH",
|
||||
"BI",
|
||||
"BJ",
|
||||
"BN",
|
||||
"BO",
|
||||
"BR",
|
||||
"BS",
|
||||
"BT",
|
||||
"BW",
|
||||
"BY",
|
||||
"BZ",
|
||||
"CA",
|
||||
"CD",
|
||||
"CG",
|
||||
"CH",
|
||||
"CI",
|
||||
"CL",
|
||||
"CM",
|
||||
"CO",
|
||||
"CR",
|
||||
"CV",
|
||||
"CW",
|
||||
"CY",
|
||||
"CZ",
|
||||
"DE",
|
||||
"DJ",
|
||||
"DK",
|
||||
"DM",
|
||||
"DO",
|
||||
"DZ",
|
||||
"EC",
|
||||
"EE",
|
||||
"EG",
|
||||
"ES",
|
||||
"FI",
|
||||
"FJ",
|
||||
"FM",
|
||||
"FR",
|
||||
"GA",
|
||||
"GB",
|
||||
"GD",
|
||||
"GE",
|
||||
"GH",
|
||||
"GM",
|
||||
"GN",
|
||||
"GQ",
|
||||
"GR",
|
||||
"GT",
|
||||
"GW",
|
||||
"GY",
|
||||
"HK",
|
||||
"HN",
|
||||
"HR",
|
||||
"HT",
|
||||
"HU",
|
||||
"ID",
|
||||
"IE",
|
||||
"IL",
|
||||
"IN",
|
||||
"IQ",
|
||||
"IS",
|
||||
"IT",
|
||||
"JM",
|
||||
"JO",
|
||||
"JP",
|
||||
"KE",
|
||||
"KG",
|
||||
"KH",
|
||||
"KI",
|
||||
"KM",
|
||||
"KN",
|
||||
"KR",
|
||||
"KW",
|
||||
"KZ",
|
||||
"LA",
|
||||
"LB",
|
||||
"LC",
|
||||
"LI",
|
||||
"LK",
|
||||
"LR",
|
||||
"LS",
|
||||
"LT",
|
||||
"LU",
|
||||
"LV",
|
||||
"LY",
|
||||
"MA",
|
||||
"MC",
|
||||
"MD",
|
||||
"ME",
|
||||
"MG",
|
||||
"MH",
|
||||
"MK",
|
||||
"ML",
|
||||
"MN",
|
||||
"MO",
|
||||
"MR",
|
||||
"MT",
|
||||
"MU",
|
||||
"MV",
|
||||
"MW",
|
||||
"MX",
|
||||
"MY",
|
||||
"MZ",
|
||||
"NA",
|
||||
"NE",
|
||||
"NG",
|
||||
"NI",
|
||||
"NL",
|
||||
"NO",
|
||||
"NP",
|
||||
"NR",
|
||||
"NZ",
|
||||
"OM",
|
||||
"PA",
|
||||
"PE",
|
||||
"PG",
|
||||
"PH",
|
||||
"PK",
|
||||
"PL",
|
||||
"PS",
|
||||
"PT",
|
||||
"PW",
|
||||
"PY",
|
||||
"QA",
|
||||
"RO",
|
||||
"RS",
|
||||
"RW",
|
||||
"SA",
|
||||
"SB",
|
||||
"SC",
|
||||
"SE",
|
||||
"SG",
|
||||
"SI",
|
||||
"SK",
|
||||
"SL",
|
||||
"SM",
|
||||
"SN",
|
||||
"SR",
|
||||
"ST",
|
||||
"SV",
|
||||
"SZ",
|
||||
"TD",
|
||||
"TG",
|
||||
"TH",
|
||||
"TJ",
|
||||
"TL",
|
||||
"TN",
|
||||
"TO",
|
||||
"TR",
|
||||
"TT",
|
||||
"TV",
|
||||
"TW",
|
||||
"TZ",
|
||||
"UA",
|
||||
"UG",
|
||||
"US",
|
||||
"UY",
|
||||
"UZ",
|
||||
"VC",
|
||||
"VE",
|
||||
"VN",
|
||||
"VU",
|
||||
"WS",
|
||||
"XK",
|
||||
"ZA",
|
||||
"ZM",
|
||||
"ZW",
|
||||
],
|
||||
"external_urls": {
|
||||
"spotify": "https://open.spotify.com/album/1zUY4PAFrNUOCeaEBrEHzh"
|
||||
},
|
||||
"href": "https://api.spotify.com/v1/albums/1zUY4PAFrNUOCeaEBrEHzh",
|
||||
"id": "1zUY4PAFrNUOCeaEBrEHzh",
|
||||
"images": [
|
||||
{
|
||||
"height": 640,
|
||||
"url": "https://i.scdn.co/image/ab67616d0000b2733686f349e17589993adacddd",
|
||||
"width": 640,
|
||||
},
|
||||
{
|
||||
"height": 300,
|
||||
"url": "https://i.scdn.co/image/ab67616d00001e023686f349e17589993adacddd",
|
||||
"width": 300,
|
||||
},
|
||||
{
|
||||
"height": 64,
|
||||
"url": "https://i.scdn.co/image/ab67616d000048513686f349e17589993adacddd",
|
||||
"width": 64,
|
||||
},
|
||||
],
|
||||
"name": "Curtain Call: The Hits",
|
||||
"release_date": "2005-12-06",
|
||||
"release_date_precision": "day",
|
||||
"total_tracks": 17,
|
||||
"type": "album",
|
||||
"uri": "spotify:album:1zUY4PAFrNUOCeaEBrEHzh",
|
||||
},
|
||||
"artists": [
|
||||
{
|
||||
"external_urls": {
|
||||
"spotify": "https://open.spotify.com/artist/7dGJo4pcD2V6oG8kP0tJRR"
|
||||
},
|
||||
"href": "https://api.spotify.com/v1/artists/7dGJo4pcD2V6oG8kP0tJRR",
|
||||
"id": "7dGJo4pcD2V6oG8kP0tJRR",
|
||||
"name": "Eminem",
|
||||
"type": "artist",
|
||||
"uri": "spotify:artist:7dGJo4pcD2V6oG8kP0tJRR",
|
||||
}
|
||||
],
|
||||
"available_markets": [
|
||||
"AD",
|
||||
"AE",
|
||||
"AG",
|
||||
"AL",
|
||||
"AM",
|
||||
"AO",
|
||||
"AR",
|
||||
"AT",
|
||||
"AU",
|
||||
"AZ",
|
||||
"BA",
|
||||
"BB",
|
||||
"BD",
|
||||
"BE",
|
||||
"BF",
|
||||
"BG",
|
||||
"BH",
|
||||
"BI",
|
||||
"BJ",
|
||||
"BN",
|
||||
"BO",
|
||||
"BR",
|
||||
"BS",
|
||||
"BT",
|
||||
"BW",
|
||||
"BY",
|
||||
"BZ",
|
||||
"CA",
|
||||
"CD",
|
||||
"CG",
|
||||
"CH",
|
||||
"CI",
|
||||
"CL",
|
||||
"CM",
|
||||
"CO",
|
||||
"CR",
|
||||
"CV",
|
||||
"CW",
|
||||
"CY",
|
||||
"CZ",
|
||||
"DE",
|
||||
"DJ",
|
||||
"DK",
|
||||
"DM",
|
||||
"DO",
|
||||
"DZ",
|
||||
"EC",
|
||||
"EE",
|
||||
"EG",
|
||||
"ES",
|
||||
"FI",
|
||||
"FJ",
|
||||
"FM",
|
||||
"FR",
|
||||
"GA",
|
||||
"GB",
|
||||
"GD",
|
||||
"GE",
|
||||
"GH",
|
||||
"GM",
|
||||
"GN",
|
||||
"GQ",
|
||||
"GR",
|
||||
"GT",
|
||||
"GW",
|
||||
"GY",
|
||||
"HK",
|
||||
"HN",
|
||||
"HR",
|
||||
"HT",
|
||||
"HU",
|
||||
"ID",
|
||||
"IE",
|
||||
"IL",
|
||||
"IN",
|
||||
"IQ",
|
||||
"IS",
|
||||
"IT",
|
||||
"JM",
|
||||
"JO",
|
||||
"JP",
|
||||
"KE",
|
||||
"KG",
|
||||
"KH",
|
||||
"KI",
|
||||
"KM",
|
||||
"KN",
|
||||
"KR",
|
||||
"KW",
|
||||
"KZ",
|
||||
"LA",
|
||||
"LB",
|
||||
"LC",
|
||||
"LI",
|
||||
"LK",
|
||||
"LR",
|
||||
"LS",
|
||||
"LT",
|
||||
"LU",
|
||||
"LV",
|
||||
"LY",
|
||||
"MA",
|
||||
"MC",
|
||||
"MD",
|
||||
"ME",
|
||||
"MG",
|
||||
"MH",
|
||||
"MK",
|
||||
"ML",
|
||||
"MN",
|
||||
"MO",
|
||||
"MR",
|
||||
"MT",
|
||||
"MU",
|
||||
"MV",
|
||||
"MW",
|
||||
"MX",
|
||||
"MY",
|
||||
"MZ",
|
||||
"NA",
|
||||
"NE",
|
||||
"NG",
|
||||
"NI",
|
||||
"NL",
|
||||
"NO",
|
||||
"NP",
|
||||
"NR",
|
||||
"NZ",
|
||||
"OM",
|
||||
"PA",
|
||||
"PE",
|
||||
"PG",
|
||||
"PH",
|
||||
"PK",
|
||||
"PL",
|
||||
"PS",
|
||||
"PT",
|
||||
"PW",
|
||||
"PY",
|
||||
"QA",
|
||||
"RO",
|
||||
"RS",
|
||||
"RW",
|
||||
"SA",
|
||||
"SB",
|
||||
"SC",
|
||||
"SE",
|
||||
"SG",
|
||||
"SI",
|
||||
"SK",
|
||||
"SL",
|
||||
"SM",
|
||||
"SN",
|
||||
"SR",
|
||||
"ST",
|
||||
"SV",
|
||||
"SZ",
|
||||
"TD",
|
||||
"TG",
|
||||
"TH",
|
||||
"TJ",
|
||||
"TL",
|
||||
"TN",
|
||||
"TO",
|
||||
"TR",
|
||||
"TT",
|
||||
"TV",
|
||||
"TW",
|
||||
"TZ",
|
||||
"UA",
|
||||
"UG",
|
||||
"US",
|
||||
"UY",
|
||||
"UZ",
|
||||
"VC",
|
||||
"VE",
|
||||
"VN",
|
||||
"VU",
|
||||
"WS",
|
||||
"XK",
|
||||
"ZA",
|
||||
"ZM",
|
||||
"ZW",
|
||||
],
|
||||
"disc_number": 1,
|
||||
"duration_ms": 205760,
|
||||
"explicit": True,
|
||||
"external_ids": {"isrc": "USUM70506387"},
|
||||
"external_urls": {
|
||||
"spotify": "https://open.spotify.com/track/3vllUzZChqpEaAat9brOYV"
|
||||
},
|
||||
"href": "https://api.spotify.com/v1/tracks/3vllUzZChqpEaAat9brOYV",
|
||||
"id": "3vllUzZChqpEaAat9brOYV",
|
||||
"is_local": False,
|
||||
"name": "FACK",
|
||||
"popularity": 42,
|
||||
"preview_url": None,
|
||||
"track_number": 2,
|
||||
"type": "track",
|
||||
"uri": "spotify:track:3vllUzZChqpEaAat9brOYV",
|
||||
},
|
||||
]
|
||||
765
make_folders.py
Executable file
765
make_folders.py
Executable file
@@ -0,0 +1,765 @@
|
||||
from ast import keyword
|
||||
import sys
|
||||
import mutagen
|
||||
import eyed3
|
||||
from eyed3.id3.frames import ImageFrame
|
||||
from mutagen.flac import FLAC
|
||||
from mutagen.mp3 import MP3
|
||||
from mutagen.id3 import ID3
|
||||
from mutagen.wave import WAVE
|
||||
from mutagen.oggvorbis import OggVorbis
|
||||
from mutagen.id3 import ID3, TIT2, TALB, TPE1, TPE2, COMM, TCOM, TCON, TDRC, TRCK, TPUB, POPM, APIC
|
||||
from mutagen.easyid3 import EasyID3
|
||||
import os
|
||||
from os import listdir
|
||||
from os.path import isfile, join
|
||||
|
||||
from icrawler.builtin import GoogleImageCrawler
|
||||
|
||||
import spotipy
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import requests
|
||||
import time
|
||||
|
||||
import logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="{asctime} - {levelname} - [{funcName}:{lineno}] - {message}",
|
||||
style="{",
|
||||
datefmt="%Y-%m-%d %H:%M",
|
||||
)
|
||||
|
||||
# TODO check if title is correct (not like "artist - name")
|
||||
|
||||
def switch_ID3_flag_tag(audio, ID3_tag, flac_tag):
|
||||
try:
|
||||
audio[flac_tag] = str(audio[ID3_tag][0].text[0])
|
||||
logging.info("switched ID3 tag " + ID3_tag + " to flac tag " + flac_tag + " with value " + str(audio[flac_tag]) + ", type " + str(type(audio[flac_tag])))
|
||||
audio.pop(ID3_tag, None)
|
||||
except:
|
||||
logging.info("could not switch ID3 tag " + ID3_tag + " to flac tag " + flac_tag)
|
||||
|
||||
def remove_flac_ID3_tags(audio, x: str):
|
||||
if x.endswith(".flac"):
|
||||
logging.info("switching ID3 tags to flac tags for file " + x)
|
||||
|
||||
switch_ID3_flag_tag(audio,"TPE2","BAND")
|
||||
switch_ID3_flag_tag(audio, "TPE1", "ARTIST")
|
||||
switch_ID3_flag_tag(audio, "TIT2", "TITLE")
|
||||
switch_ID3_flag_tag(audio, "TALB", "ALBUM")
|
||||
switch_ID3_flag_tag(audio, "COMM", "COMMENT")
|
||||
switch_ID3_flag_tag(audio, "TCOM", "COMPOSER")
|
||||
switch_ID3_flag_tag(audio, "TCON", "GENRE")
|
||||
switch_ID3_flag_tag(audio, "TRCK", "TRACKNUMBER")
|
||||
switch_ID3_flag_tag(audio, "TDRC", "DATE")
|
||||
switch_ID3_flag_tag(audio, "TPUB", "PUBLISHER")
|
||||
|
||||
audio.pop("POPM", None)
|
||||
audio.pop("APIC", None)
|
||||
|
||||
|
||||
|
||||
def make_folder(foldername):
|
||||
try:
|
||||
logging.info("Creating folder " + foldername)
|
||||
if "/" in foldername:
|
||||
folders = foldername.split('/')
|
||||
pos = "."
|
||||
for fold in folders:
|
||||
pos = join(pos,fold)
|
||||
if not os.path.exists(pos):
|
||||
os.mkdir(pos)
|
||||
else:
|
||||
os.mkdir(foldername)
|
||||
except Exception as err:
|
||||
logging.error("could not create folder " + foldername)
|
||||
logging.error(err)
|
||||
|
||||
|
||||
def search_google_images_and_save(x: str, audio):
|
||||
if x.endswith(".flac"):
|
||||
remove_flac_ID3_tags(audio,x)
|
||||
|
||||
audio.save(x)
|
||||
|
||||
found_image = False
|
||||
if (check_tag(audio, x, "TALB","album")):
|
||||
# search for artist and album
|
||||
if x.endswith(".flac"):
|
||||
songpath = join(".",str(audio["artist"]),str(audio["album"]))
|
||||
else:
|
||||
songpath = join(".",str(audio["TPE2"]),str(audio["TALB"]))
|
||||
if "\x00" in songpath:
|
||||
# having null bytes in os.replace will throw an error
|
||||
songpath = songpath.replace("\x00",", ")
|
||||
make_folder(songpath)
|
||||
os.replace(join(".",x),join(songpath,x))
|
||||
google_keyword = ""
|
||||
if x.endswith(".flac"):
|
||||
google_keyword = str(audio["artist"]) + " " + str(audio["album"]) + " album"
|
||||
else:
|
||||
google_keyword = str(audio["TPE2"]) + " " + str(audio["TALB"]) + " album"
|
||||
logging.info("Moved file! Now searching for album art... keyword is " + google_keyword)
|
||||
google_Crawler = GoogleImageCrawler(storage = {'root_dir': songpath})
|
||||
try:
|
||||
google_Crawler.crawl(keyword = str(audio["TPE2"]) + " " + str(audio["TALB"]) + " album", max_num = 1)
|
||||
found_image = True
|
||||
except:
|
||||
logging.info("could not find Google result by album, searching by track and artist")
|
||||
if (found_image):
|
||||
logging.info("changing name of cover art file...")
|
||||
logging.info(songpath)
|
||||
for f in listdir(songpath):
|
||||
logging.info(f)
|
||||
if (isfile(join(songpath,f)) and f.split(".")[-1].lower() in ["jpg","png"]):
|
||||
os.replace(join(songpath,f),join(songpath,"Cover." + f.split(".")[-1].lower()))
|
||||
logging.info("Done!")
|
||||
#TODO search for song name and artist if album not found on google images
|
||||
# else:
|
||||
# songpath = join(".",str(audio["TPE1"]),str(audio["TIT2"]))
|
||||
# make_folder(songpath)
|
||||
# os.replace(join(".",x),join(songpath,x))
|
||||
# logging.info("Moved file! Now searching for album art... keyword is " + str(audio["TPE1"]) + " " + str(audio["TIT2"]))
|
||||
# google_Crawler = GoogleImageCrawler(storage = {'root_dir': songpath})
|
||||
|
||||
|
||||
else:
|
||||
# search for song name and artist
|
||||
# search for artist and album
|
||||
# use TPE2 (album artist), because we want to find the album
|
||||
songpath = join(".",str(audio["TPE2"]),str(audio["TIT2"]))
|
||||
make_folder(songpath)
|
||||
os.replace(join(".",x),join(songpath,x))
|
||||
logging.info("Moved file! Now searching for album art... keyword is " + str(audio["TPE2"]) + " " + str(audio["TIT2"]))
|
||||
google_Crawler = GoogleImageCrawler(storage = {'root_dir': songpath})
|
||||
try:
|
||||
google_Crawler.crawl(keyword = str(audio["TPE2"]) + " " + str(audio["TIT2"]), max_num = 1)
|
||||
found_image = True
|
||||
except:
|
||||
logging.info("could not find Google result by track and artist")
|
||||
if (found_image):
|
||||
logging.info("changing name of cover art file...")
|
||||
logging.info(songpath)
|
||||
for f in listdir(songpath):
|
||||
logging.info(f)
|
||||
if (isfile(join(songpath,f)) and f.split(".")[-1].lower() in ["jpg","png"]):
|
||||
os.replace(join(songpath,f),join(songpath,"Cover." + f.split(".")[-1].lower()))
|
||||
logging.info("Done!")
|
||||
|
||||
# TIT2 = title,
|
||||
# TPE1 = artist,
|
||||
# TPE2 = band,
|
||||
# TALB = album,
|
||||
# COMM = comment,
|
||||
# TCOM = composer,
|
||||
# TCON = genre,
|
||||
# TRCK = number,
|
||||
# TDRC = year,
|
||||
# TPUB = publisher
|
||||
|
||||
def create_ID3_tag(audio, tagname: str, textvalue: str):
|
||||
logging.info("creating ID3 tag " + tagname + " with value " + textvalue)
|
||||
if tagname == "TALB":
|
||||
audio[tagname] = TALB(encoding=3,text=textvalue)
|
||||
elif tagname == "TIT2":
|
||||
audio[tagname] = TIT2(encoding=3,text=textvalue)
|
||||
elif tagname == "TPE1":
|
||||
audio[tagname] = TPE1(encoding=3,text=textvalue)
|
||||
elif tagname == "TPE2":
|
||||
audio[tagname] = TPE2(encoding=3,text=textvalue)
|
||||
elif tagname == "COMM":
|
||||
audio[tagname] = COMM(encoding=3,text=textvalue)
|
||||
elif tagname == "TCOM":
|
||||
audio[tagname] = TCOM(encoding=3,text=textvalue)
|
||||
elif tagname == "TCON":
|
||||
audio[tagname] = TCON(encoding=3,text=textvalue)
|
||||
elif tagname == "TRCK":
|
||||
audio[tagname] = TRCK(encoding=3,text=textvalue)
|
||||
elif tagname == "TDRC":
|
||||
try:
|
||||
audio[tagname] = TDRC(encoding=3,text=textvalue)
|
||||
except:
|
||||
pass
|
||||
elif tagname == "TPUB":
|
||||
audio[tagname] = TPUB(encoding=3,text=textvalue)
|
||||
|
||||
def check_tag(audio, filename: str, ID3_tag: str, normal_tag) -> bool:
|
||||
res = False
|
||||
|
||||
# check if the ID3 artist tag exists
|
||||
if (ID3_tag in audio.keys() and len(str(audio[ID3_tag])) != 0):
|
||||
logging.info(ID3_tag + " ID3 tag found! " + str(audio[ID3_tag]))
|
||||
|
||||
# apply it to the general album tag
|
||||
if audio[ID3_tag] is not str and filename.endswith(".mp3"):
|
||||
audio[normal_tag] = audio[ID3_tag]
|
||||
else:
|
||||
audio[normal_tag] = audio[ID3_tag]
|
||||
logging.info("Set " + normal_tag + " to " + str(audio[normal_tag]))
|
||||
res = True
|
||||
|
||||
# check if general album tag exists
|
||||
elif (normal_tag in audio.keys() and len(str(audio[normal_tag])) != 0):
|
||||
logging.info(normal_tag + " normal tag found! " + str(audio[normal_tag]))
|
||||
if audio[normal_tag] is not str:
|
||||
audio[normal_tag] = audio[normal_tag][0]
|
||||
logging.info("normal tag is not str, set it to " + str(audio[normal_tag][0]))
|
||||
if (not filename.endswith(".flac")):
|
||||
#apply it to the ID3 tag
|
||||
if audio[normal_tag] is not str:
|
||||
create_ID3_tag(audio, ID3_tag,audio[normal_tag][0])
|
||||
else:
|
||||
create_ID3_tag(audio, ID3_tag,audio[normal_tag])
|
||||
else:
|
||||
logging.debug(filename + " is a flac file, not creating ID3 tag")
|
||||
res = True
|
||||
|
||||
return res
|
||||
|
||||
def check_title_songname(x: str, audio):
|
||||
logging.info("checking title by name " + x)
|
||||
extension = x.split(".")[-1].lower()
|
||||
if (extension in ["mp3","flac","ogg","wav","m4a","mp4"]):
|
||||
x = x.rsplit(".",1)[0] # remove the file extension
|
||||
logging.info("file has extension " + extension + ". removing it from title. New title: " + x)
|
||||
|
||||
items = x.split(" - ")
|
||||
if (len(items) > 2):
|
||||
logging.info("song title has more than 1 part after the -: " + str(items))
|
||||
if (items[1].count(".mp3") >= 1):
|
||||
logging.info("setting TIT2 tag to: " + str(items[1].strip().rstrip().rsplit(".")[0])) # get second part of title and remove the file extension
|
||||
audio["TIT2"] = TIT2(encoding=3,text=str(items[1].strip().rstrip().rsplit(".")[0]))
|
||||
elif (items[1].count(".flac") >= 1):
|
||||
logging.info("setting title tag to " + str(items[1].strip().rstrip().rsplit(".")[0])) # get second part of title and remove the file extension
|
||||
audio["title"] = str(items[1].strip().rstrip().rsplit(".")[0])
|
||||
else:
|
||||
logging.info("title: " + str(items[1].strip().rstrip())) # get second part of title and remove the file extension
|
||||
audio["TIT2"] = TIT2(encoding=3,text=str(items[1].strip().rstrip()))
|
||||
audio["title"] = TIT2(encoding=3,text=str(items[1].strip().rstrip()))
|
||||
else:
|
||||
logging.info("song title has only 1 part after the -: " + items[1])
|
||||
if ("TIT2" not in audio.keys()):
|
||||
song_title = items[1].strip().rstrip()
|
||||
logging.info("TIT2 tag not found, creating it. Using song title: " + song_title)
|
||||
audio["TIT2"] = TIT2(encoding=3,text=song_title)
|
||||
audio["title"] = TIT2(encoding=3,text=song_title)
|
||||
|
||||
def check_for_multiple_artists(audio, filename: str, name: str):
|
||||
logging.info("checking for multiple artists for name " + name)
|
||||
artists = []
|
||||
if (" x " in name):
|
||||
artists = name.split(" x ")
|
||||
elif (" X " in name):
|
||||
artists = name.split(" X ")
|
||||
elif ("," in name):
|
||||
artists = name.split(",")
|
||||
elif ("/" in name):
|
||||
artists = name.split("/")
|
||||
elif ("\x00" in name):
|
||||
artists = name.split("\x00")
|
||||
|
||||
if (len(artists) > 0):
|
||||
logging.info("multiple artists: " + str(artists))
|
||||
if filename.endswith(".flac"):
|
||||
audio["artist"] = TPE2(encoding=3,text=["\0".join(artists)])
|
||||
else:
|
||||
audio["TPE1"] = TPE2(encoding=3,text=["\0".join(artists)])
|
||||
else:
|
||||
logging.info("no multiple artists found in name " + name)
|
||||
|
||||
|
||||
# checks for any artist from the song name. If it exists it sets the properties of the file
|
||||
def check_artist_songname(x: str, audio):
|
||||
items = x.split(" - ")
|
||||
logging.info("Checking artist by name. items: " + str(items))
|
||||
if (len(items) > 2):
|
||||
check_for_multiple_artists(audio, x, items[0].strip())
|
||||
|
||||
else: # no multiple artists in name
|
||||
logging.info("Setting artist tags TPE1 and TPE2 to " + str(items[0].strip().rstrip()))
|
||||
|
||||
audio["TPE1"] = TPE1(encoding=3,text=str(items[0].strip().rstrip()))
|
||||
audio["TPE2"] = TPE2(encoding=3,text=str(items[0].strip().rstrip()))
|
||||
audio["artist"] = audio["TPE1"]
|
||||
|
||||
def check_artist(audio, filename: str) -> bool:
|
||||
res = False
|
||||
|
||||
# check if the ID3 artist tag exists
|
||||
if ("TPE1" in audio.keys()):
|
||||
if (len(str(audio["TPE1"])) != 0):
|
||||
logging.info("TPE1 tag was found! " + str(audio["TPE1"]))
|
||||
|
||||
# apply it to general artist tag
|
||||
audio["TPE2"] = TPE2(encoding=3,text=str(audio["TPE1"]))
|
||||
audio["artist"] = audio["TPE1"]
|
||||
logging.info("checking for multiple artists")
|
||||
check_for_multiple_artists(audio, filename ,str(audio["TPE1"]))
|
||||
res = True
|
||||
|
||||
|
||||
# if no TPE1, check if the ID3 band tag exists
|
||||
elif ("TPE2" in audio.keys()):
|
||||
if (len(str(audio["TPE2"])) != 0):
|
||||
logging.info("TPE2 tag was found! " + str(audio["TPE2"]))
|
||||
|
||||
# apply it to TPE1 and general artist tags
|
||||
audio["TPE1"] = TPE1(encoding=3,text=str(audio["TPE2"]))
|
||||
audio["artist"] = audio["TPE1"]
|
||||
check_for_multiple_artists(audio,filename,str(audio["TPE2"]))
|
||||
res = True
|
||||
|
||||
# check if artist audio tag exists
|
||||
elif ("artist" in audio.keys()):
|
||||
if (len(str(audio["artist"])) != 0):
|
||||
logging.info("artist tag was found! " + str(audio["artist"]))
|
||||
|
||||
artist = ""
|
||||
if (audio["artist"] is not str):
|
||||
artist = audio["artist"][0]
|
||||
else:
|
||||
artist = audio["artist"]
|
||||
|
||||
logging.info("artist: " + artist)
|
||||
# apply to both ID3 artist tags
|
||||
audio["TPE1"] = TPE1(encoding=3,text=artist)
|
||||
audio["TPE2"] = TPE2(encoding=3,text=artist)
|
||||
|
||||
if (audio["TPE2"][0].text is not str):
|
||||
audio["TPE2"][0].text = str(audio["TPE2"][0].text[0])
|
||||
|
||||
if (audio["TPE1"] is not str):
|
||||
audio["TPE1"] = audio["TPE1"][0]
|
||||
|
||||
logging.info("Set TPE1 and TPE2 to " + str(audio["TPE1"][0]) + " and " + str(audio["TPE2"][0]))
|
||||
check_for_multiple_artists(audio,filename,artist)
|
||||
res = True
|
||||
|
||||
return res
|
||||
|
||||
def check_spotify_genre(genres,audio):
|
||||
genre = ""
|
||||
if (len(genres) > 0):
|
||||
if (len(genres) == 1):
|
||||
audio["TCON"] = TCON(encoding=3,text=str(genres[0]))
|
||||
else:
|
||||
for i in range(len(genres)):
|
||||
if (i == 0):
|
||||
genre = str(genres[i])
|
||||
else:
|
||||
genre += "," + str(genres[i])
|
||||
|
||||
logging.info("genre set to " + genre)
|
||||
audio["TCON"] = TCON(encoding=3,text=genre)
|
||||
|
||||
audio["genre"] = audio["TCON"]
|
||||
|
||||
def embed_music_file(audiostr: str, coverfile: str):
|
||||
try:
|
||||
new_audio = ID3(audiostr)
|
||||
with open(coverfile,'rb') as albumart:
|
||||
new_audio.add(APIC(
|
||||
encoding=3,
|
||||
mime='image/jpeg',
|
||||
type=3, desc=u'Cover image',
|
||||
data=albumart.read()
|
||||
))
|
||||
new_audio.save(audiostr)
|
||||
logging.info("Finished!")
|
||||
except:
|
||||
logging.info("could not embed music file")
|
||||
|
||||
|
||||
def check_spotify_album_and_save(spotify, audio,x: str) -> bool:
|
||||
found = False
|
||||
logging.info("Searching on spotify for album...")
|
||||
querystring = ""
|
||||
if x.endswith(".flac"):
|
||||
querystring = "artist:{0} album:{1}".format(str(audio["artist"]),str(audio["album"]))
|
||||
else:
|
||||
querystring = "artist:{0} album:{1}".format(str(audio["TPE2"]),str(audio["TALB"]))
|
||||
|
||||
logging.info("query string: " + querystring)
|
||||
try:
|
||||
results = spotify.search(q=querystring,type='album')
|
||||
except Exception as err:
|
||||
logging.error("could not search on spotify")
|
||||
logging.error(err)
|
||||
logging.info("waiting 30 seconds before trying again")
|
||||
time.sleep(30)
|
||||
try:
|
||||
results = spotify.search(q=querystring,type='album')
|
||||
except Exception as err:
|
||||
logging.error("could not search on spotify again")
|
||||
logging.error(err)
|
||||
return found
|
||||
|
||||
if (len(results["albums"]["items"]) > 0):
|
||||
logging.info("album found on spotify!")
|
||||
found = True
|
||||
album = results["albums"]["items"][0]
|
||||
album_artist = album["artists"][0]["name"]
|
||||
|
||||
if (x.endswith(".flac")):
|
||||
try:
|
||||
if str(audio["album_artist"]) != album_artist:
|
||||
audio["album_artist"] = album_artist
|
||||
except:
|
||||
audio["album_artist"] = album_artist
|
||||
else:
|
||||
if (str(audio["TPE2"]) != album_artist):
|
||||
audio["TPE2"] = TPE2(encoding=3,text=album_artist)
|
||||
|
||||
album_image_url = album["images"][0]["url"]
|
||||
album_name = album["name"]
|
||||
|
||||
if x.endswith(".flac"):
|
||||
if str(audio["album"] != album_name):
|
||||
audio["album"] = album_name
|
||||
elif (str(audio["TALB"]) != album_name):
|
||||
audio["TALB"] = TALB(encoding=3,text=album_name)
|
||||
|
||||
if (x.endswith(".flac")):
|
||||
audio["year"] = album["release_date"]
|
||||
else:
|
||||
audio["TDRC"] = TDRC(encoding=3,text=album["release_date"])
|
||||
|
||||
artist_search = spotify.artist(album['artists'][0]['external_urls']['spotify'])
|
||||
logging.info("genres: " + str(artist_search['genres']))
|
||||
check_spotify_genre(artist_search['genres'],audio)
|
||||
|
||||
comment ="Spotify ID: {0}. Release date precision: {1}, total tracks in album: {2}. This album has {3} version(s)".format(album["id"],album["release_date_precision"], album["total_tracks"],len(results["albums"]["items"]))
|
||||
logging.info("Comment: " + comment)
|
||||
if x.endswith(".flac"):
|
||||
audio["comment"] = comment
|
||||
else:
|
||||
audio["COMM"] = COMM(encoding=3,text=comment)
|
||||
|
||||
if x.endswith(".flac"):
|
||||
remove_flac_ID3_tags(audio,x)
|
||||
|
||||
audio.save(x)
|
||||
|
||||
songpath = ""
|
||||
|
||||
if x.endswith(".flac"):
|
||||
songpath = join(".",str(audio["artist"][0]),str(audio["album"][0]))
|
||||
make_folder(join(".",str(audio["artist"][0])))
|
||||
else:
|
||||
if "/" in audio["TPE2"]:
|
||||
audio["TPE2"] = audio["TPE2"].replace("/","")
|
||||
songpath = join(".",str(audio["TPE2"]),str(audio["TALB"]))
|
||||
make_folder(join(".",str(audio["TPE2"])))
|
||||
|
||||
|
||||
|
||||
if (not x.endswith(".flac")):
|
||||
if ("/" in str(audio["TALB"])):
|
||||
logging.info("album contains /")
|
||||
folders = str(audio["TALB"]).split('/')
|
||||
logging.info(folders)
|
||||
pos = join(".",str(audio["TPE2"]))
|
||||
for fold in folders:
|
||||
make_folder(join(pos,fold))
|
||||
pos = join(pos,fold)
|
||||
logging.info(pos)
|
||||
|
||||
make_folder(songpath)
|
||||
os.replace(join(".",x),join(songpath,x))
|
||||
logging.info("moved song file, now downloading cover art")
|
||||
|
||||
img_data = requests.get(str(album_image_url)).content
|
||||
with open(join(songpath,"Cover.jpg"),'wb') as handler:
|
||||
handler.write(img_data)
|
||||
logging.info("done getting cover art!")
|
||||
|
||||
logging.info("now setting cover art..")
|
||||
embed_music_file(join(songpath,x),join(songpath,"Cover.jpg"))
|
||||
else:
|
||||
logging.info("No album found on spotify")
|
||||
return found
|
||||
|
||||
def check_spotify_and_save(spotify, audio,x: str) -> bool:
|
||||
found = False
|
||||
logging.info("Searching spotify for file " + x)
|
||||
artist = ""
|
||||
track = ""
|
||||
if x.endswith(".flac"):
|
||||
if audio["artist"] is not str:
|
||||
artist = str(audio["artist"][0])
|
||||
else:
|
||||
artist = str(audio["artist"])
|
||||
if audio["title"] is not str:
|
||||
track = str(audio["title"][0])
|
||||
else:
|
||||
track = str(audio["title"])
|
||||
else:
|
||||
if audio["TPE2"] is not str:
|
||||
logging.info("TPE2 is not str")
|
||||
artist = str(audio["TPE2"][0])
|
||||
else:
|
||||
artist = str(audio["TPE2"])
|
||||
|
||||
if audio["TIT2"] is not str:
|
||||
track = str(audio["TIT2"][0])
|
||||
else:
|
||||
track = str(audio["TIT2"])
|
||||
|
||||
querystring = "artist:{0} track:{1}".format(artist.split("\00")[0],track)
|
||||
logging.info("query string: " + querystring)
|
||||
results = spotify.search(q=querystring,type='track')
|
||||
if (len(results['tracks']['items']) > 0):
|
||||
logging.info("track found on spotify!")
|
||||
found = True
|
||||
album = results['tracks']['items'][0]["album"]
|
||||
found_artist = album["artists"][0]["name"]
|
||||
if (found_artist != artist):
|
||||
logging.info("Changing album artist from " + artist + " to " + found_artist)
|
||||
if x.endswith(".flac"):
|
||||
audio["album_artist"] = found_artist
|
||||
else:
|
||||
audio["TPE2"] = TPE2(encoding=3,text=found_artist)
|
||||
found_album = album["name"]
|
||||
if (len(found_album) > 0):
|
||||
if x.endswith(".flac"):
|
||||
audio["album"] = found_album
|
||||
else:
|
||||
audio["TALB"] = TALB(encoding=3,text=found_album)
|
||||
else:
|
||||
if (x.endswith(".flac")):
|
||||
audio["album"] = audio["title"][0]
|
||||
else:
|
||||
audio["TALB"] = TALB(encoding=3,text=str(audio["TIT2"]))
|
||||
|
||||
comment ="Spotify ID: {0}. Release date precision: {1}, total tracks in album: {2}. This album has {3} version(s)".format(album["id"],album["release_date_precision"], album["total_tracks"],len(results["albums"]["items"]))
|
||||
logging.info("Comment: " + comment)
|
||||
if x.endswith(".flac"):
|
||||
audio["comment"] = comment
|
||||
else:
|
||||
audio["COMM"] = COMM(encoding=3,text=comment)
|
||||
|
||||
try:
|
||||
year = str(datetime.strptime(album["release_date"], '%Y-%m-%d').year)
|
||||
|
||||
if x.endswith(".flac"):
|
||||
audio["year"] = year
|
||||
else:
|
||||
audio["TDRC"] = TDRC(encoding=3,text=year)
|
||||
|
||||
except Exception as err:
|
||||
logging.info(err)
|
||||
year = str(album["release_date"])
|
||||
audio["year"] = year
|
||||
|
||||
|
||||
if x.endswith(".flac"):
|
||||
audio["TRACKNUMBER"] = str(results['tracks']['items'][0]["track_number"]) +"/" + str(album["total_tracks"])
|
||||
else:
|
||||
audio["TRCK"] = TRCK(encoding=3,text=str(results['tracks']['items'][0]["track_number"]) +"/" + str(album["total_tracks"]))
|
||||
|
||||
if x.endswith(".flac"):
|
||||
audio["popularity"] = str(results['tracks']['items'][0]["popularity"])
|
||||
else:
|
||||
audio["POPM"] = POPM(encoding=3,text=str(results['tracks']['items'][0]["popularity"]))
|
||||
|
||||
|
||||
found_image_url = album["images"][0]["url"]
|
||||
logging.info("found cover art image at " + str(found_image_url))
|
||||
|
||||
artist_search = spotify.artist(results['tracks']['items'][0]['artists'][0]['external_urls']['spotify'])
|
||||
logging.info("genres: " + str(artist_search['genres']))
|
||||
check_spotify_genre(artist_search['genres'],audio)
|
||||
|
||||
# remove ID3 tags if it's a flac file, otherwise it will throw an error
|
||||
remove_flac_ID3_tags(audio,x)
|
||||
|
||||
audio.save(x)
|
||||
|
||||
artist_path = ""
|
||||
songpath = ""
|
||||
if x.endswith(".flac"):
|
||||
artist_path = str(audio["artist"][0])
|
||||
else:
|
||||
if audio["TPE2"] is not str:
|
||||
artist_path = str(audio["TPE2"][0])
|
||||
else:
|
||||
artist_path = str(audio["TPE2"])
|
||||
|
||||
logging.info("artist path: " + artist_path)
|
||||
if x.endswith(".flac"):
|
||||
songpath = join(".",artist_path,str(audio["ALBUM"][0]))
|
||||
else:
|
||||
songpath = join(".",artist_path,str(audio["TALB"]))
|
||||
logging.info("song path: " + songpath)
|
||||
|
||||
make_folder(join(".",artist_path))
|
||||
|
||||
if (not x.endswith(".flac") and "/" in str(audio["TALB"])):
|
||||
logging.info("album contains /")
|
||||
folders = str(audio["TALB"]).split('/')
|
||||
logging.info(folders)
|
||||
pos = join(".",str(audio["TPE2"]))
|
||||
for fold in folders:
|
||||
make_folder(join(pos,fold))
|
||||
pos = join(pos,fold)
|
||||
logging.info(pos)
|
||||
|
||||
make_folder(songpath)
|
||||
os.replace(join(".",x),join(songpath,x))
|
||||
logging.info("moved song file, now downloading cover art")
|
||||
|
||||
img_data = requests.get(str(found_image_url)).content
|
||||
with open(join(songpath,"Cover.jpg"),'wb') as handler:
|
||||
handler.write(img_data)
|
||||
logging.info("done getting cover art!")
|
||||
|
||||
logging.info("now setting cover art..")
|
||||
embed_music_file(join(songpath,x),join(songpath,"Cover.jpg"))
|
||||
|
||||
|
||||
return found
|
||||
|
||||
def main():
|
||||
|
||||
# for spotipy to be able to log in, the environment variables SPOTIPY_CLIENT_ID and SPOTIPY_CLIENT_SECRET have to be set
|
||||
# these can be obtained from the spotify developer dashboard
|
||||
# they are defined in /etc/profile.d/spotipy.sh
|
||||
spotify = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials())
|
||||
|
||||
onlyfiles = [f for f in listdir(".") if (isfile(join(".",f)) and f.split(".")[-1] in ['mp3','mp4','ogg','wav','flac','m4a','MP3','FLAC','OGG','MP4','WAV','M4A'])]
|
||||
# TIT2 = title,
|
||||
# TPE1 = artist,
|
||||
# TPE2 = band,
|
||||
# TALB = album,
|
||||
# COMM = comment,
|
||||
# TCOM = composer,
|
||||
# TCON = genre,
|
||||
# TRCK = number,
|
||||
# TDRC = year,
|
||||
# TPUB = publisher
|
||||
|
||||
# use: audio["TRCK"] = TRCK(encoding=3, text=u'track_number') and replace the tags with appropriate values
|
||||
for x in onlyfiles:
|
||||
logging.info("------------------------------------------------")
|
||||
logging.info(x)
|
||||
|
||||
# try to open tags, if the file has none, create a new ID3 object
|
||||
try:
|
||||
audio = mutagen.File(x)
|
||||
except mutagen.mp3.HeaderNotFoundError as err:
|
||||
logging.info(err)
|
||||
logging.info("header not found")
|
||||
audio = mutagen.File(x,easy=True)
|
||||
audio.add_tags()
|
||||
except mutagen.id3.ID3NoHeaderError:
|
||||
logging.info("no header")
|
||||
audio = mutagen.File(x,easy=True)
|
||||
audio.add_tags()
|
||||
except:
|
||||
logging.info("opening as ID3")
|
||||
audio = ID3(x)
|
||||
audio.add_tags()
|
||||
|
||||
logging.info(type(audio))
|
||||
try:
|
||||
if (audio.tags == None):
|
||||
logging.info("audio has no tags")
|
||||
audio.add_tags()
|
||||
except:
|
||||
pass
|
||||
|
||||
has_valid_artist = check_artist(audio,x)
|
||||
has_valid_album = check_tag(audio,x,"TALB","album")
|
||||
has_valid_title = check_tag(audio,x,"TIT2","title")
|
||||
if (has_valid_title):
|
||||
if x.endswith(".flac"):
|
||||
logging.info("Found valid title in title tag: " + str(audio["TITLE"]))
|
||||
if audio["TITLE"] is not str:
|
||||
check_title_songname(audio["TITLE"][0],audio)
|
||||
else:
|
||||
check_title_songname(audio["TITLE"],audio)
|
||||
else:
|
||||
logging.info("Found valid title in TTI2 tag: " + str(audio["TIT2"]) + ". type: " + str(type(audio["TIT2"])))
|
||||
if not isinstance(audio["TIT2"], str):
|
||||
if (isinstance(audio["TIT2"][0], str)):
|
||||
check_title_songname(audio["TIT2"][0],audio)
|
||||
else:
|
||||
logging.info(type(audio["TIT2"][0]))
|
||||
check_title_songname(audio["TIT2"][0].text[0],audio)
|
||||
else:
|
||||
check_title_songname(audio["TIT2"].text[0],audio)
|
||||
else:
|
||||
logging.info("No valid title found in TTI2 tag, using name " + x)
|
||||
check_title_songname(x,audio)
|
||||
has_valid_title = True
|
||||
|
||||
if (has_valid_artist == False):
|
||||
logging.info("No valid artist found, checking for artist by songname of the file (" + x + ")")
|
||||
if (" - " in x):
|
||||
check_artist_songname(x, audio)
|
||||
has_valid_artist = True
|
||||
|
||||
if (has_valid_artist == False and has_valid_title):
|
||||
logging.info("No valid artist found but valid title found, checking for multiple artists")
|
||||
check_for_multiple_artists(audio,x,str(audio["TIT2"]))
|
||||
has_valid_artist = check_artist(audio, x) # check again
|
||||
|
||||
check_tag(audio,x,"COMM","comment")
|
||||
check_tag(audio,x,"TCOM","composer")
|
||||
|
||||
has_genre = check_tag(audio,x,"TCON","genre")
|
||||
if (has_genre):
|
||||
if x.endswith(".flac"):
|
||||
audio["genre"] = str(audio["genre"]).replace(" & ",",")
|
||||
else:
|
||||
audio["TCON"] = TCON(encoding=3, text=str(audio["TCON"]).replace(" & ",",")) # convert genres like Hip-Hop & Rap to Hip-Hop,Rap
|
||||
|
||||
check_tag(audio,x,"TRCK","track")
|
||||
check_tag(audio,x,"TDRC","year")
|
||||
check_tag(audio,x,"TPUB","publisher")
|
||||
|
||||
if (has_valid_artist and has_valid_title):
|
||||
found = False
|
||||
try:
|
||||
found = check_spotify_and_save(spotify, audio,x)
|
||||
except Exception as err:
|
||||
logging.error("could not find track on spotify: " + str(err))
|
||||
found = False
|
||||
|
||||
if (found == False):
|
||||
if (x.endswith(".flac")):
|
||||
logging.info("valid artist found. making folder for artist " + str(audio["artist"][0]))
|
||||
make_folder(join(".",str(audio["artist"][0])))
|
||||
else:
|
||||
logging.info("valid artist found. making folder for artist " + str(audio["TPE1"]))
|
||||
if "/" in audio["TPE2"]:
|
||||
audio["TPE2"] = audio["TPE2"].replace("/","")
|
||||
make_folder(join(".",str(audio["TPE2"])))
|
||||
|
||||
if (has_valid_album):
|
||||
if (x.endswith(".flac")):
|
||||
make_folder(join(".",str(audio["artist"][0]),str(audio["album"][0])))
|
||||
else:
|
||||
make_folder(join(".",str(audio["TPE2"]),str(audio["TALB"])))
|
||||
|
||||
logging.info("spotify did not find artist and track, searching for album...")
|
||||
if (has_valid_album):
|
||||
album_found = check_spotify_album_and_save(spotify,audio,x)
|
||||
if (album_found == False):
|
||||
logging.info("Nothing found on spotify, searching Google Images...")
|
||||
search_google_images_and_save(x, audio)
|
||||
else:
|
||||
if x.endswith(".flac"):
|
||||
audio["album"] = audio["title"][0]
|
||||
else:
|
||||
audio["TALB"] = TALB(encoding=3,text=str(audio["TIT2"]))
|
||||
search_google_images_and_save(x, audio)
|
||||
|
||||
logging.info("------------------------------------------------")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
11
process_music.sh
Executable file
11
process_music.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
source .env/bin/activate
|
||||
python3 make_folders.py
|
||||
for f in ./*.mp3; do ffprobe "$f"; done
|
||||
for f in ./*.flac; do ffprobe "$f"; done
|
||||
mkdir ../temp
|
||||
rm -r ../temp/*
|
||||
mv ./*/ ../temp #move all directories
|
||||
mv ./*.mp3 ../temp #move all mp3 files
|
||||
mv ./*.flac ../temp #move all flac files
|
||||
mv ./*.m4a ../temp #move all m4a files
|
||||
rsync -arv ../temp/* ../Music
|
||||
1
youtube-dl-command.txt
Normal file
1
youtube-dl-command.txt
Normal file
@@ -0,0 +1 @@
|
||||
youtube-dl -i -x --prefer-ffmpeg --audio-format mp3 <URL>
|
||||
Reference in New Issue
Block a user