MP3-Sortierer (nur für den Privaten gebrauch! Teil 2)

  • An alle Hobby-Autoit-Programmierer,

    Herzlichen Dank an alle die Interesse an meinem Programm haben oder hatten. ^^

    Ich habe mein Problem (-für meine Zwecke-) entzwischen gelöst. :D
    Hatte eigendlicht nicht vorgesehen auch noch nach MP3-tags zu sortieren, ist aber vielleicht besser.
    Danke Xenobiologist für den Hinweis.

    Das Programm kann noch weiter optimiert werden, aber es mach schon eigentlich das was ich wollte.
    Es sortiert meine MP3-Dateien...

    Spezial-Thanx an: ---> Oscar <--- Muss wohl ein Profi sein ???

    Sein Code ist wirklich ' BESSER ' als meiner. ;( :wacko: X( und kürzer !
    Hat aber dafür keine Oberfläche (GUI_Fenster). Schade...
    Vielleicht kann jemannd den von Oscar und meinen kombinieren ? Wenn es recht ist und/oder erlaubt :?:

    Wer Interesse hat kann hier meinen zweiten Teil meines Codes herunterladen und Ausprobieren.
    Script vielleicht vorher anschauen... Code Teil2: autoit.de/wcf/attachment/9206/


    MFG
    tv_freeze

    • Offizieller Beitrag

    Ich habe mal schnell so ein Skript geschrieben. :)
    Es wird zuerst versucht, den Interpreten aus den ID3-Tags auszulesen und wenn das nicht klappt, dann aus dem Dateinamen (wichtig ist dabei diese Struktur: "Interpret - Titel").

    Spoiler anzeigen
    [autoit]


    #include <File.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $sMP3Folder = FileSelectFolder('MP3-Verzeichnis (Quelle) auswählen', '', 3)
    If Not FileExists($sMP3Folder) Then Exit MsgBox(0, 'Fehler!', 'Kein Quellverzeichnis ausgewählt!')

    [/autoit] [autoit][/autoit] [autoit]

    $sDestFolder = FileSelectFolder('Ziel-Verzeichnis auswählen (Unterverzeichnisse werden erstellt)', '', 3)
    If Not FileExists($sDestFolder) Then Exit MsgBox(0, 'Fehler!', 'Kein Zielverzeichnis ausgewählt!')

    [/autoit] [autoit][/autoit] [autoit]

    $aMP3Files = _FileListToArray($sMP3Folder, '*.mp3', 1) ; alle MP3s einlesen (nicht rekursiv)
    If @error Then Exit MsgBox(0, 'Fehler!', 'Keine MP3-Dateien gefunden!')

    [/autoit] [autoit][/autoit] [autoit]

    If StringRight($sMP3Folder, 1) <> '\' Then $sMP3Folder &= '\'
    If StringRight($sDestFolder, 1) <> '\' Then $sDestFolder &= '\'
    Dim $aID3
    For $i = 1 To $aMP3Files[0]
    $aID3 = _ReadID3Tag($sMP3Folder & $aMP3Files[$i]) ; ID3-Tags auslesen
    If @error Then
    ConsoleWrite('Die Datei "' & $sMP3Folder & $aMP3Files[$i] & '" verursachte Fehler-Nr. ' & @error & @CR)
    Else
    ; wenn im ID3-Tag der Interpret nicht eingetragen ist, dann aus dem Dateinamen auslesen (" - " als Trenner zwischen Interpret und Titel)
    If $aID3[1][1] = '' Then $aID3[1][1] = StringRegExpReplace($aMP3Files[$i], '(.+) - .+', '$1')
    ToolTip('Kopiere "' & $aMP3Files[$i] & '" nach: "' & $sDestFolder & $aID3[1][1] & '\')
    $iRet = FileMove($sMP3Folder & $aMP3Files[$i], $sDestFolder & $aID3[1][1] & '\', 8)
    If Not $iRet Then ConsoleWrite('Die Datei "' & $sMP3Folder & $aMP3Files[$i] & '" konnte nicht verschoben werden!' & @CR)
    EndIf
    Next
    ToolTip('')

    [/autoit] [autoit][/autoit] [autoit]

    ;===============================================================================
    ; Function Name: _ReadID3Tag($sPath)
    ; Description:: gibt ein Array mit den Daten aus den ID3-Tags zurück
    ; unterstützt werden die ID3-Tag-Versionen 2.3 und 2.4
    ; bei v2.4 müssen sich die ID3-Tags am Anfang der Datei befinden
    ; Parameter(s): $sPath = Pfad zu einer MP3-Datei
    ; Requirement(s): min. AutoIt v3.3.0.0
    ; Return Value(s): bei Erfolg: Array mit den ID3-Tagdaten (@error = 0)
    ; im Fehlerfall bekommt @error:
    ; 1 = Datei existiert nicht
    ; 2 = Datei konnte nicht zum lesen geöffnet werden
    ; 3 = Datei ist keine MP3-Datei
    ; Author(s): Oscar (http://www.autoit.de)
    ;===============================================================================
    Func _ReadID3Tag($sPath)
    If Not FileExists($sPath) Then Return SetError(1, 0, 0)
    Local $hFile, $sData, $sID3Header, $iID3HeaderSize = 0, $iOffset, $iSize, $tmp
    Local $aID3v2Tags[8] = ['TIT2', 'TPE1', 'TALB', 'TYER', 'TLEN', 'TRCK', 'TCON', 'TENC']
    Local $aID3[11][2] = [ _
    ['Title', ''],['Artist', ''],['Album', ''],['Year', ''], _
    ['Length', '0'],['Track', ''],['Genre', ''],['Encoder', ''], _
    ['MPEG-Version', ''],['Bitrate', ''],['Sample-Freq.', '']]
    Local $aMP3Version[4] = ['MPEG2.5', 'Reserved', 'MPEG2', 'MPEG1']
    Local $aMP3Layer[4] = ['Reserved', 'Layer III', 'Layer II', 'Layer I']
    Local $aMP3Bitrate[5][16] = [ _
    [000, 032, 064, 096, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 000], _
    [000, 032, 048, 056, 064, 080, 096, 112, 128, 160, 192, 224, 256, 320, 384, 000], _
    [000, 032, 040, 048, 056, 064, 080, 096, 112, 128, 160, 192, 224, 256, 320, 000], _
    [000, 032, 048, 056, 064, 080, 096, 112, 128, 144, 160, 176, 192, 224, 256, 000], _
    [000, 008, 016, 024, 032, 040, 048, 056, 064, 080, 096, 112, 128, 144, 160, 000]]
    Local $aSampleFreq[3][4] = [[44100, 48000, 32000, 0],[22050, 24000, 16000, 0],[11025, 12000, 8000, 0]]
    Local $sMP3FrameHeader, $iMP3Version, $sMP3Version, $sMP3Layer, $iMP3Bitrate, $iMP3SampleFreq
    Local $iVBRFrames = -1, $iVBRFilesize, $iVBRFlags
    $hFile = FileOpen($sPath, 16)
    If $hFile = -1 Then Return SetError(2, 0, 0)
    $sData = Binary(FileRead($hFile, 4))
    If BinaryMid($sData, 1, 3) = '0x494433' Then ; ID3 v2.x Kennung gefunden
    If BinaryMid($sData, 4, 1) = '0x03' Or BinaryMid($sData, 4, 1) = '0x04' Then ; nur v2.3 und 2.4
    FileRead($hFile, 2) ; 2 Bytes überspringen
    For $i = 0 To 3 ; berechne ID3-Headergröße (4 Bytes, jedoch nur jeweils die unteren 7 Bit)
    $iID3HeaderSize = BitShift($iID3HeaderSize, -7) + ('0x' & Hex(FileRead($hFile, 1), 2))
    Next
    If $iID3HeaderSize > 0 Then
    $sID3Header = Binary(FileRead($hFile, $iID3HeaderSize)) ; lese gesamten ID3-Header
    For $i = 0 To 7
    $iOffset = StringInStr(BinaryToString($sID3Header), $aID3v2Tags[$i]) ; Offset zu dem ID3-Tag
    If $iOffset > 0 Then
    $iSize = Hex(BinaryMid($sID3Header, $iOffset + 4, 4)) ; Größe des ID3-Frames
    $tmp = BinaryMid($sID3Header, $iOffset + 11, Dec($iSize) - 1)
    For $x = 1 To BinaryLen($tmp)
    If BinaryMid($tmp, $x, 1) <> 0x00 Then $aID3[$i][1] &= BinaryToString(BinaryMid($tmp, $x, 1))
    Next
    EndIf
    Next
    EndIf
    $sData = Binary(FileRead($hFile, 4)) ; 1. MP3-Frameheader auslesen
    EndIf
    EndIf
    $sMP3FrameHeader = '0x' & Hex($sData)
    If Hex(BitAND($sMP3FrameHeader, 0xFFE00000), 8) <> 'FFE00000' Then Return SetError(3, 0, 0) ; keine MP3-Datei, dann Return
    $iMP3Version = BitShift(BitAND($sMP3FrameHeader, 0x180000), 19) ; welche MP3-Version
    $sMP3Version = $aMP3Version[$iMP3Version] ; in Textform
    $sMP3Layer = $aMP3Layer[BitShift(BitAND($sMP3FrameHeader, 0x60000), 17)] ; welcher Layer
    $aID3[8][1] = $sMP3Version & ' / ' & $sMP3Layer ; ins Ausgabe-Array
    $iMP3Bitrate = BitShift(BitAND($sMP3FrameHeader, 0xF000), 12) ; Bitraten-Index auslesen
    Switch $sMP3Version ; je nach MPEG-Version Bitrate aus der Tabelle holen
    Case 'MPEG1'
    $aID3[9][1] = $aMP3Bitrate[$iMP3Version - ($iMP3Version > 1)][$iMP3Bitrate]
    Case 'MPEG2', 'MPEG2.5'
    If $sMP3Layer = 'Layer I' Then
    $aID3[9][1] = $aMP3Bitrate[3][$iMP3Bitrate]
    Else
    $aID3[9][1] = $aMP3Bitrate[4][$iMP3Bitrate]
    EndIf
    EndSwitch
    $iMP3SampleFreq = BitShift(BitAND($sMP3FrameHeader, 0xC00), 10) ; Sample-Frequenz-Index auslesen
    $aID3[10][1] = $aSampleFreq[2 - ($iMP3Version - ($iMP3Version > 1))][$iMP3SampleFreq] ; und Wert aus der Tabelle holen
    Do ; evtl. Leerbytes überspringen
    $tmp = FileRead($hFile, 1)
    If @error Then ExitLoop
    Until $tmp <> 0x00 Or @error
    If $tmp = 0x58 And BinaryToString(FileRead($hFile, 3)) = 'ing' Then ; MP3 mit VBR (Xing-Header gefunden)?
    $iVBRFlags = '0x' & Hex(FileRead($hFile, 4)) ; VBR-Flags auslesen
    If BitAND($iVBRFlags, 0x3) Then ; wenn die Einträge vorhanden sind, dann...
    $iVBRFrames = Dec(Hex(FileRead($hFile, 4))) ; Anzahl der VBR-Frames auslesen
    $iVBRFilesize = Dec(Hex(FileRead($hFile, 4))) ; Dateigröße auslesen
    $aID3[4][1] = $iVBRFrames * 1152 / $aID3[10][1] * 1000 ; VBR Laufzeit
    $aID3[9][1] = 'VBR ~' & Int($iVBRFilesize * 8 / ($aID3[4][1] / 1000) / 1000) ; VBR durchschnittliche Bitrate
    EndIf
    Else
    If $aID3[4][1] = 0 Then $aID3[4][1] = (FileGetSize($sPath) * 8) / ($aID3[9][1] * 1000) * 1000 ; alternative CBR Laufzeit
    $aID3[9][1] = 'CBR ' & $aID3[9][1]
    EndIf
    $aID3[4][1] = _MyTicksToTime($aID3[4][1]) ; Laufzeit (Ticks to hour:min:sec)
    $aID3[9][1] &= ' kBit/s'
    $aID3[10][1] &= ' Hz'
    FileClose($hFile)
    Return $aID3
    EndFunc ;==>_ReadID3Tag

    [/autoit] [autoit][/autoit] [autoit]

    Func _MyTicksToTime($iTicks)
    Local $iHour, $iMins, $iSecs
    $iHour = Int($iTicks / 3600000)
    $iTicks -= $iHour * 3600000
    $iMins = Int($iTicks / 60000)
    $iTicks -= $iMins * 60000
    $iSecs = Int($iTicks / 1000)
    Return StringFormat('%02i:%02i:%02i', $iHour, $iMins, $iSecs)
    EndFunc ;==>_MyTicksToTime

    [/autoit]