forked from CLAW1200/Spotify-YTDL
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fileIntegrity.py
220 lines (191 loc) · 8.74 KB
/
fileIntegrity.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
"""
To do:
Change code so that rather that being passed directory, it is passed a list of files
This is easier said than done, good luck future me!
"""
import os
import re
from mutagen.flac import FLAC
from mutagen.id3 import ID3, TIT2, TALB, TPE1, TPE2
def compareStrings(fileNameShort, artistFromMetadata, titleFromMetadata):
# Function to compare two strings word by word, ignoring symbols and making everything lowercase
# True if strings match
fileNameHold = fileNameShort
# Filename (no extension) is fileNameShort
fileNameShort = re.sub(r'[^\w\s]', '', fileNameShort.lower())
fileNameShort = re.sub(r'\s+', ' ', fileNameShort) # Replace double spaces with single spaces
# Artist is artistFromMetadata
artistFromMetadata = re.sub(r'[^\w\s]', '', artistFromMetadata.lower())
artistFromMetadata = re.sub(r'\s+', ' ', artistFromMetadata) # Replace double spaces with single spaces
# Title is titleFromMetadata
titleFromMetadata = re.sub(r'[^\w\s]', '', titleFromMetadata.lower())
titleFromMetadata = re.sub(r'\s+', ' ', titleFromMetadata) # Replace double spaces with single spaces
# Check if artistFromMetadata is a substring of fileNameShort, or vice versa
# if any word in artistFromMetadata is in fileNameShort and any word in titleFromMetadata is in fileNameShort, or if fileNameShort is a substring of artistFromMetadata + titleFromMetadata
artistCondition = any(word in fileNameShort for word in artistFromMetadata.split()) # any word in artistFromMetadata is in fileNameShort
fileNameHoldFormat = fileNameHold.rsplit(' - ', 1)[-1]
fileNameHoldFormat = fileNameHoldFormat.strip().lower() #filename Title
fileNameHoldFormat = re.sub(r'[^\w\s]', '', fileNameHoldFormat.lower())
fileNameHoldFormat = re.sub(r'\s+', ' ', fileNameHoldFormat)
titleCondition = fileNameHoldFormat in titleFromMetadata
if artistCondition and titleCondition or (fileNameShort in artistFromMetadata + titleFromMetadata):
return True
#print(f"{fileNameShort} |-| {artistFromMetadata} | {titleFromMetadata}")
#print (f"{fileNameHoldFormat} | {titleFromMetadata}")
return False
def getMetadata(file):
#returns metadataArtist and metadataTitle
if not file.endswith((".flac", ".mp3")): # Check for both FLAC, MP3
metadataArtist = ""
metadataTitle = ""
filenameWithoutExtension = ""
pass
if file.endswith(".flac"):
# Read FLAC metadata
audio = FLAC(file)
metadataArtist = audio.get("artist", [""])[0]
metadataTitle = audio.get("title", [""])[0]
elif file.endswith(".mp3"):
# Read MP3 metadata
audio = ID3(file)
metadataArtist = audio.getall("TPE1")[0].text[0] if len(audio.getall("TPE1")) > 0 else ""
metadataTitle = audio.getall("TIT2")[0].text[0] if len(audio.getall("TIT2")) > 0 else ""
return metadataArtist, metadataTitle
def checkMetadata(filePath):
# Function to check if the metadata is correct for artist and title
# Returns a list of tuples with the filename, artist, and title if there is a mismatch
os.chdir(filePath)
mismatchedFiles = [] # Create a list to store mismatched filenames
for file in os.listdir():
# Loop through all files in the directory
# Check if the metadata is correct for artist and title
metadataArtist, metadataTitle = getMetadata(file)
# Remove the file extension and compare to the original file name
filenameWithoutExtension, _ = os.path.splitext(file)
if not (compareStrings(filenameWithoutExtension, metadataArtist, metadataTitle)) and (file.endswith(".mp3") or file.endswith(".flac")):
mismatchedFiles.append((file, metadataArtist, metadataTitle))
return mismatchedFiles
def copyFilenameToMetadata(fileName, filePath):
# Function to copy the filename to the metadata
# Returns True if successful, False if unsuccessful
if not fileName.endswith((".flac", ".mp3")): # Check for both FLAC and MP3 files
return False
fileNameShort = _ = os.path.splitext(fileName)[0]
#split filename after last -
try:
fileNameArtist, fileNameTitle = fileNameShort.rsplit(' - ', 1)
fileNameArtist = fileNameArtist.strip()
fileNameTitle = fileNameTitle.strip()
except ValueError:
print ("Error: Filename does not contain '-' to split artist and title")
pass
#Use FileName to update metadata
try:
if fileName.endswith(".flac"):
# Read FLAC metadata
audio = FLAC(filePath + fileName)
audio["artist"] = fileNameArtist
audio["title"] = fileNameTitle
audio.save()
elif fileName.endswith(".mp3"):
# Read MP3 metadata
audio = ID3(filePath + fileName)
audio.setall("TPE1", [TPE2(fileNameArtist)]) if fileNameArtist != "" else audio.setall("TPE1", [TPE2("")])
audio.setall("TIT2", [TALB(fileNameTitle)]) if fileNameTitle != "" else audio.setall("TIT2", [TALB("")])
audio.save()
except Exception as e:
print(f"Error processing {fileName}: {e}")
return False
return True
def copyMetadataToFileName(fileName, filePath):
#Use Metadata to update filename
metadataArtist, metadataTitle = getMetadata(filePath + fileName)
if metadataArtist == "" and metadataTitle == "":
print ("Error: Metadata is empty. File not renamed.\n")
return False
fileNameExtension = _ = os.path.splitext(fileName)[1]
newFileName = metadataArtist + " - " + metadataTitle + fileNameExtension
os.rename(filePath + fileName, filePath + newFileName)
print (f"Renamed {fileName} to {newFileName}\n")
def copyAllFileNameToMetadata(fileNameList, filePath):
for fileName in fileNameList:
copyFilenameToMetadata(fileName[0], filePath)
def copyAllMetadataToFileName(fileNameList, filePath):
for fileName in fileNameList:
copyMetadataToFileName(fileName[0], filePath)
def decideForEachFile(fileName, filePath):
for fileName in mismatchedFiles:
print (f"Filename: {fileName[0]}")
print (f"Artist: {fileName[1]}")
print (f"Title: {fileName[2]}")
print ("1. Use filenames")
print ("2. Use metadata")
print ("3. Delete file")
print ("4. Skip")
print ("5. Exit\n")
choice = input("Enter your choice: ")
if choice == "1":
copyFilenameToMetadata(fileName[0], filePath)
elif choice == "2":
copyMetadataToFileName(fileName[0], filePath)
elif choice == "3":
if userConfirm():
deleteFile(fileName[0], filePath)
elif choice == "4":
continue
elif choice == "5":
break
else:
print ("Invalid choice\n")
def userConfirm():
# Function to confirm that the user wants to make the changes
# Returns True if the user confirms, False if the user does not confirm
print ("Are you sure you want to make these changes? (Y/N)")
choice = input("Enter your choice: ")
if choice == "Y" or choice == "y":
return True
elif choice == "N" or choice == "n":
return False
else:
print ("Invalid choice\n")
return False
def deleteFile(fileName, filePath):
os.remove(filePath + fileName)
print (f"Deleted {fileName}")
def deleteFiles(fileNameList, filePath):
for fileName in fileNameList:
deleteFile(fileName[0], filePath)
def menu(mismatchedFiles, filePath):
print(f"{len(mismatchedFiles)} mismatched files found.\n{mismatchedFiles}\n")
if len(mismatchedFiles) < 1:
print("No changes made.")
exit()
print ("1. Use filenames for all")
print ("2. Use metadata for all")
print ("3. Delete all files")
print ("4. Let me decide for each file")
print ("5. Exit\n")
choice = input("Enter your choice: ")
if choice == "1":
if userConfirm():
copyAllFileNameToMetadata(mismatchedFiles, filePath)
elif choice == "2":
if userConfirm():
copyAllMetadataToFileName(mismatchedFiles, filePath)
elif choice == "3":
if userConfirm():
deleteFiles(mismatchedFiles, filePath)
elif choice == "4":
decideForEachFile(mismatchedFiles, filePath)
elif choice == "5":
print ("No changes made.\n")
exit()
else:
print ("Invalid choice\n")
if __name__ == "__main__":
"""
A command line interface to check and correct the metadata of all files in a directory
"""
filePath = "C:\\Users\\User\\Music\\test\\"
mismatchedFiles = checkMetadata(filePath) # --> mismatchedFiles = checkMetadata(getFileListFromDirectory())
menu(mismatchedFiles, filePath)