Mal ein Lebenszeichen von mir...
Ich habe mal versucht, ein kleines Tool für Playlisten(*.m3u) zu erstellen. Dabei ging es mir vor Allem darum, Duplikate und verwaiste Einträge zu entfernen oder zu korrigieren. Aber mittlerweile hat es auch noch weitere Funktionen…
• einlesen und erstellen von m3u, m3u8 Playlists
• erkennen doppelter Einträge
• erkennen von verwaisten Einträgen
• nach verwaisten Einträgen in bestimmtem Pfad suchen ([Interpret] - [Titel])
• entfernen von Einträgen und/oder löschen vom Datenträger
• sortieren/mischen von Einträgen
• ausgewählte Einträge in Ordner kopieren neu
• kompletten Ordnerinhalt an Playliste anfügen
• per Drag&Drop Dateien hinzufügen
• per Drag&Drop Dateien verschieben(dank Pullovers Class_LV_Rows)
• erzeuge zur Playlist relative oder absolute Pfade
Update 24.02.2023
Dowload der kompilierten Version
Spoiler
Dieses kleine Tool habe ich in einer früheren Version im alten Forum schon einmal gepostet. Code: Select all
/*
* * * Compile_AHK SETTINGS BEGIN * * *
[AHK2EXE]
Exe_File=%In_Dir%\M3U-Editor.exe
No_UPX=0
[VERSION]
Set_Version_Info=1
Company_Name=CF
File_Version=0.0.0.29
Inc_File_Version=1
Product_Version=1.1.11.2
Set_AHK_Version=1
[ICONS]
Icon_1=%In_Dir%\PL.ico
* * * Compile_AHK SETTINGS END * * *
*/
;@Ahk2Exe-SetName CF
;@Ahk2Exe-SetVersion 0.0.0.29
;@Ahk2Exe-SetCopyright Copyright (c) 2019`, CF
/*
Thanks to
Deo for 'Shell Context Menu'
Pulover for 'Class_LV_Rows'
############################# Anmerkung für CF ###########################
Sonderzeichen in Pfaden und Dateinamen machen manchmal Probleme
Web-Pfade:
replacehtml(t[A_Index + 1]) ; sollte Webadresse in UNC-Pfade wandeln, Verbesserung mit UriDecode
pl[zz,"Pfad"] := UriDecode(t[A_Index + 1]) ; UriDecode hat mit Umlauten und einigen Sonderzeichen Probleme, deshalb nur noch bedingte Nutzung für den Pfad
##########################################################################
*/
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
#Include Class_LV_Rows.ahk
FileEncoding, UTF-8
StringCaseSense, Locale
FileInstall, M3U-Editor-AHK.mht, % A_Temp "\M3U-Editor-AHK.mht", 1
ctc_hilfe := A_Temp "\M3U-Editor-AHK.mht"
ftmp := A_Temp "\tmp.m3u" ; Tempdatei PL
Menu, mymenü, add , Datei im Explorer anzeigen, zeige_datei
Menu, mymenü, Default , Datei im Explorer anzeigen
gosub, load
; ---------BLOCK Shell Context Menu von Deo---------------------------------------
/*
[AHK_L] Shell Context Menu von Deo
http://www.autohotkey.com/board/topic/89281-ahk-l-shell-context-menu/#entry565580
optionales Kontextmenü für Playlisteneinträge
falls nicht benötigt, diesen Block und Sub 'zeige_ex' entfernen/auskommentieren
*/
#Include, %A_ScriptDir%\ShellContextMenu.ahk
Menu, mymenü, add , Kontextmenü des Explorers anzeigen, zeige_ex
; -----------Ende BLOCK Shell Context Menu von Deo-------------------------------
; ---------------------Größen für Controls---------------------------------------
b_w := 80
b_h := 35
html_list := ; Zeichenfolgen lösen UriDecode ein
( join
"%21,%23,%24,%26,%27,%28,%29,%2b,%2c,%2f,%3b,%3c,%3d,%3e,%3f,%40,%5b,%5d,%5e,%60,%7b,%7c,%7d,%7e,%80,%82,%83,%84,%88,%8b,%91,%92,%93,%94,%96,%97
,%98,%9b,%a1,%a3,%a7,%a8,%b4,%b7,%b8,%C2%A0,%C2%AE,%C2%B4,%C2%BF,%C26,%C2¡,%C3%89,%C3%9C,%C3%9F,%C3%A0,%C3%A4,%C3%A5,%C3%A9,%C3%AB,%C3%AD,%C3%AE
,%C3%B1,%C3%B3,%C3%B6,%C3%BA,%C3%BC,%C3¡,%C3§,%C3¨,%C3´,%C3¸,%C3˜,%C3–,%C3„,%C3‹,%c4,%d6,%d8,%dc,%df,%e4,%f6,%f7,%fc"
)
;~ %%%
; ------------------------Drag&Drop-List-----------------------------------------
; akzeptierte Dateitypen
audio_list :=
(
"AAC,AMF,APL,ASF,AU,AVI,CDA,FLAC,MIDI,MOD,MPG,MPEG,ES,MP3,MP4,PS,PVA,TS,MKV,MP1,MP2
,MP3,MP4,MTM,M2V,M4A,NSA,NST,NSV,OGG,VOC,WAV,WMA,WMV,VOB"
)
; ------------------------------------------------------------------------------
men1 := "Ordnerinhalt hinzufügen"
men2 := "Speichern und Abs&pielen`tCtrl+P"
men3 := "doppelte Einträge markieren"
men4 := "selektierte Einträge löschen"
men5 := "erzeuge absolute Pfade"
men6 := "selektierte Dateien vom Datenträger löschen"
Random := "Liste zufällig mischen"
doppelte_er := "Doppete ermitteln"
missingfiles := "Fehlende suchen in..."
mrel := "erzeuge relative Pfade"
entp := "Gewählte kopieren nach"
; ------------------------------------------------------------------------------
tool := {"doppelte auswählen":"selektiert die doppelten Einträge`nDer erste Eintrag wird nicht selektiert!"
,"Löschen":"entfernt die selektierten Einträge, ohne die Playlist zu Speichern"
,"Speichern":"Speichert die aktuelle Ansicht der Titel in die gewählte Playlist im UTF-8-Format und als erweiterte m3u"
,"SysListView321":"Titelliste`nDrag&Drop möglich","Edit1":"aktueller Playlistpfad"}
; ------------------------------------------------------------------------------
Menu, mymenü, add , Dateipfad ändern, pfad
SetTitleMatchMode, 2
file := (A_UserName = "CF" or A_UserName = "ChristianFoelsch") and !A_IsCompiled ? "E:\15.11.2022.m3u" : ""
Menu, Dateimenü, Add, &Neu`tCtrl+N, neu ; Siehe untere Bemerkungen zu Ctrl+F.
Menu, Dateimenü, Add, &Speichen`tCtrl+S, speichern ; Siehe untere Bemerkungen zu Ctrl+F.
Menu, Dateimenü, Add, Speichen unter, speichern_u ; Siehe untere Bemerkungen zu Ctrl+F.
Menu, Dateimenü, Add, &Öffnen`tCtrl+O, öffnen ; Siehe untere Bemerkungen zu Ctrl+F.
Menu, Dateimenü, Add, %men2%, MenuHandler ; Siehe untere Bemerkungen zu Ctrl+F.
Menu, Dateimenü, Add, PL neu laden, drop
Menu, Dateimenü, Add
Menu, Dateimenü, Add, &Beenden, Exit
Menu, Dateimenü, icon, &Beenden, %A_Windir%\system32\shell32.dll, 132
Menu, Bearbeitenmenü, Add, %men1%, MenuHandler
Menu, Bearbeitenmenü, icon, %men1%, %A_Windir%\system32\shell32.dll, 4
Menu, Bearbeitenmenü, Add, %random%, MenuHandler
Menu, Bearbeitenmenü, icon, %random%, %A_Windir%\system32\shell32.dll, 171
Menu, Bearbeitenmenü, Add, %missingfiles%, MenuHandler
Menu, Bearbeitenmenü, icon, %missingfiles%, %A_Windir%\system32\shell32.dll, 23
Menu, Bearbeitenmenü, Add, %mrel%, MenuHandler
Menu, Bearbeitenmenü, icon, %mrel%, %A_Windir%\system32\shell32.dll, 173
Menu, Bearbeitenmenü, Add, %men5%, MenuHandler
Menu, Bearbeitenmenü, icon, %men5%, %A_Windir%\system32\shell32.dll, 173
Menu, Bearbeitenmenü, Add, %men3%, MenuHandler
Menu, Bearbeitenmenü, icon, %men3%, %A_Windir%\system32\shell32.dll, 148
Menu, Bearbeitenmenü, Add, %men4%, MenuHandler
Menu, Bearbeitenmenü, icon, %men4%, %A_Windir%\system32\shell32.dll, 132
Menu, Bearbeitenmenü, Add, %men6%, MenuHandler
Menu, Bearbeitenmenü, icon, %men6%, %A_Windir%\system32\shell32.dll, 132
Menu, Bearbeitenmenü, Add
Menu, Bearbeitenmenü, Add, %entp%, MenuHandler
Menu, Bearbeitenmenü, icon, %entp%, %A_Windir%\system32\shell32.dll, 7
Menu, Hilfsmenü, Add, Inf&o, MenuHandler
Menu, Hilfsmenü, icon, Inf&o, %A_Windir%\system32\shell32.dll, 24
Menu, menüleiste, Add, &Datei, :Dateimenü ; Fügt die oben erstellten Untermenüs hinzu.
Menu, menüleiste, Add, &Bearbeiten, :Bearbeitenmenü
Menu, menüleiste, Add, &?, :Hilfsmenü
Gui, m3u:Menu, menüleiste
gui, m3u:+Resize MinSize420x400
gui, m3u:+HwndAusgabevariable
gui, m3u:add, edit, vmytext w400 R2 +ReadOnly, % file
gui, m3u:add, ListView, vmylv w400 R20 gd_lv +AltSubmit LV0x10000, Index|Titel|Vorkommen|mehrfach|Bemerkung|Pfad
gui, m3u:add, Button, w%b_w% h%b_h% gdoppelt_markieren vdoppelt_markieren +Hwndidbutt, doppelte auswählen
gui, m3u:add, Button, x+5 w%b_w% h%b_h% geintr_löschen veintr_löschen +Hwndidbutt2, Löschen
gui, m3u:add, Button, x+5 w%b_w% h%b_h% gspeichern vspeichern +Hwndidbutt3, Speichern
gui, m3u:add, Button, x+15 w%b_w% h%b_h% gplay_titel vplay_titel +Hwndidbutt4, > anspielen
gui, m3u:add, Button, x+5 w%b_w% h%b_h% gstop vstop +Hwndidbutt5, # Stop
gui, m3u:add, StatusBar,
gui, m3u:Default
SB_SetParts(200)
gui, m3u:Show, % "w" A_ScreenWidth // 5 * 3
SetTimer, tool_control , 200
LV_ModifyCol(1, "Integer") ; For sorting purposes, indicate that column 2 is an integer.
; Create a handle for the History of first ListView.
HistoryLv1 := New LV_Rows()
HistoryLv1.Add()
;~ gosub, htmlmsg
drop:
LV_Delete()
SetWorkingDir, % SplitPath(file).Dir
GuiControl, , mytext, % file
FileRead, st, % file
t := {} ; Titelindex, alter Dateien
t_d := {} ; Duplikate
fehlt := {} ; fehlende Dateien, derzeit nicht genutzt
pl := {} ; neue Titelindex
zz := 0 ; Zähler für neuen Index
; ------------------------------------------------------------------------------
Loop, Parse, st , `n, `r
t[A_Index] := A_LoopField
SB_SetText("PL einlesen...",2)
Loop, % t.MaxIndex()
{
if (!t[A_Index] or InStr(t[A_Index],"#EXTM3U") or InStr(t[A_Index - 1],"#EXTINF:"))
continue
SB_SetText("PL einlesen fertig(" Round(A_Index / t.MaxIndex() * 100,2) "%)",2)
if (InStr(t[A_Index],"#EXTINF:"))
{
zz++
RegExMatch(t[A_Index],"#EXTINF:-?\d+,(.*)", un)
pl[zz,"Titel"] := un1
pl[zz,"Meta"] := t[A_Index]
tmp_s := t[A_Index + 1] ; Pfad zwischenspeichern
if tmp_s contains % html_list
tmp_s := UriDecode(tmp_s)
pl[zz,"Pfad"] := tmp_s
pl[zz,"Funde"] := ""
if !FileExist(tmp_s)
{
fehlt.Insert(zz)
pl[zz,"Bemerk"] .= "Fehlt"
}
}
else
{
if (RegExMatch(t[A_Index - 1],"#EXTINF:-?\d+,(.*)", un))
continue
zz++
pt := t[A_Index]
if pt contains % html_list
pt := UriDecode(pt)
te := SplitPath(pt)
pl[zz,"Titel"] := te.NameNoExt
pl[zz,"Meta"] := "#EXTINF:-1," te.NameNoExt
pl[zz,"Pfad"] := pt
pl[zz,"Funde"] := ""
if !FileExist(pt)
{
fehlt.Insert(zz)
pl[zz,"Bemerk"] .= "Fehlt"
}
}
}
SB_SetText("PL einlesen fertig",2)
gosub, doppelte_er
return
; ------------------------------------------------------------------------------
play_titel:
Gui m3u:ListView, mylv
Reihennummer := LV_GetNext(0)
LV_GetText(file_anspielen, Reihennummer, 6)
SoundPlay, % file_anspielen
return
; ------------------------------------------------------------------------------
stop:
SoundPlay, Nonexistent.mp3
return
; ------------------------------------------------------------------------------
m3uGuiSize:
GuiControl, MoveDraw, mytext, % "W" . (A_GuiWidth - 30)
GuiControl, MoveDraw, mylv, % "W" . (A_GuiWidth - 30) "H" (A_GuiHeight - 115)
GuiControl, MoveDraw, %idbutt%, % "Y" . (A_GuiHeight - 62)
GuiControl, MoveDraw, %idbutt2%, % "Y" . (A_GuiHeight - 62)
GuiControl, MoveDraw, %idbutt3%, % "Y" . (A_GuiHeight - 62)
GuiControl, MoveDraw, %idbutt4%, % "Y" . (A_GuiHeight - 62)
GuiControl, MoveDraw, %idbutt5%, % "Y" . (A_GuiHeight - 62)
return
; ------------------------------------------------------------------------------
MenuHandler:
if A_ThisMenuItem = %men1%
gosub, men1
if A_ThisMenuItem = %men2%
{
gosub, speichern
gosub, play
}
if A_ThisMenuItem = %Random%
gosub, random
if A_ThisMenuItem = Inf&o
gosub, info
if A_ThisMenuItem = %mrel%
gosub, mrel
if A_ThisMenuItem = %missingfiles%
gosub, fehlende_suchen
if A_ThisMenuItem = %entp%
gosub, entpacken
if A_ThisMenuItem = %men3%
gosub, doppelt_markieren
if A_ThisMenuItem = %men4%
gosub, eintr_löschen
if A_ThisMenuItem = %men5%
gosub, unrel
if A_ThisMenuItem = %men6%
gosub, Dateien_löschen
return
; ------------------------------------------------------------------------------
unrel: ; erszeuge absolute Pfade
ToolTip
SB_SetText("wird markiert...",2)
Gui m3u:ListView, mylv
LV_Modify(0, "-Select") ; selektion für alle aufheben
LV_Modify(0,"Select")
GuiControl, Focus, mylv,
SB_SetText(LV_GetCount("S") . " von " . LV_GetCount() . " Einträgen markiert",1)
if !LV_GetCount("S")
{
Gui m3u:+OwnDialogs
MsgBox, 64, Hinweis!, Keine Einträge gefunden.`nAbbruch!
return
}
SB_SetText("Bitte Warten! Dateien werden gesucht...",2)
function_control("speichern|doppelt_markieren|eintr_löschen",0)
GuiControl, hide, mylv
Gui, m3u:Menu
Reihennummer = 0
Loop
{
Reihennummer := LV_GetNext(Reihennummer) ; Setzt die Suche bei der nächsten Reihe fort.
If not Reihennummer ; Wenn die obige Funktion eine 0 zurückgibt, ist keine weitere Reihe ausgewählt.
break
o_lv := {}
Loop, 6
{
LV_GetText(ttext, Reihennummer, A_Index)
o_lv[A_Index] := ttext
}
gesamt++
FileFullPath := make_unrel(o_lv.6) ; 6 = Fullpath
if FileFullPath
{
pl[o_lv.1,"Pfad"] := FileFullPath
LV_Modify(Reihennummer, "", o_lv.1,o_lv.2,o_lv.3,o_lv.4,"",FileFullPath)
}
}
SB_SetText("fertig",2)
Gui, m3u:Menu, menüleiste
GuiControl, Show, mylv
function_control("speichern|doppelt_markieren|eintr_löschen",1)
return
; ------------------------------------------------------------------------------
mrel:
ToolTip
SB_SetText("wird markiert...",2)
Gui m3u:ListView, mylv
LV_Modify(0, "-Select") ; selektion für alle aufheben
Loop, % LV_GetCount()
{
LV_GetText(lv_text, A_Index, 5)
if (SubStr(lv_text,1,1) <> ".")
LV_Modify(A_Index,"Select")
}
GuiControl, Focus, mylv,
SB_SetText(LV_GetCount("S") . " von " . LV_GetCount() . " Einträgen markiert",1)
if !LV_GetCount("S")
{
Gui m3u:+OwnDialogs
MsgBox, 64, Hinweis!, Keine Einträge gefunden.`nAbbruch!
return
}
SB_SetText("Bitte Warten! Dateien werden gesucht...",2)
;~ SplashTextOn, 300, 150, arbeite..., Bitte Warten! Dateien werden gesucht.
function_control("speichern|doppelt_markieren|eintr_löschen",0)
GuiControl, hide, mylv
Gui, m3u:Menu
Reihennummer = 0
Loop
{
Reihennummer := LV_GetNext(Reihennummer) ; Setzt die Suche bei der nächsten Reihe fort.
If not Reihennummer ; Wenn die obige Funktion eine 0 zurückgibt, ist keine weitere Reihe ausgewählt.
break
o_lv := {}
Loop, 6
{
LV_GetText(ttext, Reihennummer, A_Index)
o_lv[A_Index] := ttext
}
datei := SplitPath(o_lv.6).FileName ; zwischenspeichern (Performance)
;~ MsgBox, % "suche nach: " datei " in:`n" suchfolder
gesamt++
;~ MsgBox, % make_rel(SplitPath(o_lv.6).Dir, SplitPath(file).Dir) "`n" o_lv.6 "`n" file "`n" SplitPath(o_lv.6).Dir "`n" SplitPath(file).Dir "`n" (SplitPath(o_lv.6).Dir = SplitPath(file).DirSplitPath(file).Dir)
FileFullPath := make_rel(SplitPath(o_lv.6).Dir, SplitPath(file).Dir)
if FileFullPath and datei
{
FileFullPath := FileFullPath . datei
pl[o_lv.1,"Pfad"] := FileFullPath
LV_Modify(Reihennummer, "", o_lv.1,o_lv.2,o_lv.3,o_lv.4,"",FileFullPath)
}
}
SB_SetText("fertig",2)
Gui, m3u:Menu, menüleiste
GuiControl, Show, mylv
function_control("speichern|doppelt_markieren|eintr_löschen",1)
Gui m3u:+Resize -MaximizeBox ; Ändert die Einstellungen der GUI namens MeineGui.
return
; ------------------------------------------------------------------------------
entpacken:
gui, m3u:+OwnDialogs
von := LV_GetCount("S")
fehler =
fehlertext =
zukopieren := {}
Loop
{
Reihennummer := LV_GetNext(Reihennummer) ; Setzt die Suche bei der nächsten Reihe fort.
If not Reihennummer ; Wenn die obige Funktion eine 0 zurückgibt, ist keine weitere Reihe ausgewählt.
break
LV_GetText(ttext, Reihennummer, 6)
zukopieren.Insert(ttext) ; zwischenspeichern (Performance)
}
FileSelectFolder, todir, , , In welchen Ordner soll kopiert werden?
if ErrorLevel
return
gui, m3u:+Disabled
Progress, % "y" (A_ScreenHeight // 2 - 200) " b w400", % "`n`n" Round(100 * A_Index // von,1) "% von " von " Dateien", entpacken der Playlist, Eigener Titel
For k , Value in zukopieren
{
Progress, % 100 * A_Index // von, % SplitPath(value).FileName "`n" Round(100 * A_Index // von,1) "% von " von " Dateien", entpacken der Playlist, Eigener Titel
FileCopy, % value, %todir%
if Errorlevel
{
fehler++
fehlertext .= value "<br>"
}
}
Progress, , Fertig!, entpacken der Playlist, Eigener Titel
Progress, 100
Sleep, 4000
Progress, Off
if fehlertext
gosub, htmlmsg
else
{
MsgBox, 64, Playlisteneinträge kopiert, % "Kopieren beendet.`n`n" von " erfolgreich kopiert"
Gui, m3u:-Disabled
}
return
; ------------------------------------------------------------------------------
fehlende_suchen:
ToolTip
found =
foundz = 0
gesamt =
SB_SetText("wird markiert...",2)
Gui m3u:ListView, mylv
LV_Modify(0, "-Select") ; selektion für alle aufheben
Loop, % LV_GetCount()
{
LV_GetText(lv_text, A_Index, 5)
if (lv_text = "fehlt")
LV_Modify(A_Index,"Select")
}
GuiControl, Focus, mylv,
SB_SetText(LV_GetCount("S") . " von " . LV_GetCount() . " Einträgen markiert",1)
z_markiert := LV_GetCount("S")
if !LV_GetCount("S")
{
Gui m3u:+OwnDialogs
MsgBox, 64, Hinweis!, Keine fehlenden Einträge gefunden.`nAbbruch!
return
}
lsuch := RegRead("HKEY_CURRENT_USER", "Software\M3U-Editor", "Suchordner")
FileSelectFolder, suchfolder, *%lsuch%, , In welchem Ordner soll gesucht werden?
if Errorlevel
return
RegWrite("REG_SZ", "HKEY_CURRENT_USER", "Software\M3U-Editor", "Suchordner", suchfolder)
SB_SetText("Bitte Warten! Dateien werden gesucht...",2)
;~ SplashTextOn, 300, 150, arbeite..., Bitte Warten! Dateien werden gesucht.
function_control("speichern|doppelt_markieren|eintr_löschen",0)
if A_IsCompiled
GuiControl, hide, mylv
Gui, m3u:Menu
Reihennummer = 0
Loop
{
z_aktuell := A_Index
Reihennummer := LV_GetNext(Reihennummer) ; Setzt die Suche bei der nächsten Reihe fort.
If not Reihennummer ; Wenn die obige Funktion eine 0 zurückgibt, ist keine weitere Reihe ausgewählt.
break
o_lv := {}
Loop, 6
{
LV_GetText(ttext, Reihennummer, A_Index)
o_lv[A_Index] := ttext
}
datei := SplitPath(o_lv.6).FileName ; zwischenspeichern (Performance)
SB_SetText("suche " z_aktuell " von " z_markiert " : " datei,2)
;~ ToolTip, % "suche " z_aktuell " von " z_markiert " : " datei
;~ MsgBox, % "suche nach: " datei " in:`n" suchfolder
gesamt++
FileFullPath =
Loop, %suchfolder%\*.* , 0, 1
{
if (A_LoopFileName = datei)
{
FileFullPath := A_LoopFileFullPath
foundz++
found .= foundz ": " Datei "`t -->> `t" FileFullPath "`r`n"
break
}
}
if FileFullPath
{
pl[o_lv.1,"Pfad"] := FileFullPath
LV_Modify(Reihennummer, "", o_lv.1,o_lv.2,o_lv.3,o_lv.4,"",FileFullPath)
}
found := found " Datei nicht gefunden`t -->> `t" datei "`r`n"
}
;~ SplashTextOff
SB_SetText("fertig",2)
Gui, m3u:Menu, menüleiste
GuiControl, Show, mylv
function_control("speichern|doppelt_markieren|eintr_löschen",1)
MsgBox, 68, Dateien neu zugeordnet, % "Es konnten " foundz " von " gesamt " Dateien automatisch neu zugeordnet werden. Soll ein Protokoll gezeigt werden?"
IfMsgBox, Yes
notepad_out(found)
return
; ------------------------------------------------------------------------------
Random: ; Liste zufällig mischen
ran := ""
for, key, val in pl
{
if (StrLen(pl[key,"Titel"]) > 1)
ran .= key "ÿ" pl[key,"Titel"] "ÿ" pl[key,"Funde"] "ÿ" zähle_pipe(pl[key,"Funde"]) "ÿ" pl[key,"Bemerk"] "ÿ" pl[key,"Pfad"] "`n"
}
StringTrimRight, ran, ran, 1
Sort, ran, Random
LV_Delete()
Loop, Parse, ran , `n
{
CurrentField := StringSplit(A_LoopField, "ÿ")
;~ MsgBox, % CurrentField.1 "," CurrentField.2 "," CurrentField.3 "," CurrentField.4 "," CurrentField.5 "," CurrentField.6
LV_Add("",CurrentField.1,CurrentField.2,CurrentField.3,CurrentField.4,CurrentField.5,CurrentField.6)
}
SB_SetText("Pfad ändern...",2)
pl[row,"Pfad"] := new_pf
SB_SetText("Liste mischen fertig",2)
return
; ------------------------------------------------------------------------------
doppelte_er: ; doppelte Einträge ermitteln und LV neu aufbauen
t_d := {}
for, key, val in pl
{
pl[key,"Funde"] := ""
t_d[pl[key,"Titel"]] := t_d[pl[key,"Titel"]] ? t_d[pl[key,"Titel"]] "|" key : key
}
for, key, val in pl
pl[key,"Funde"] := t_d[pl[key,"Titel"]]
LV_Delete()
gosub, lvadd
return
; ------------------------------------------------------------------------------
men1: ; Ordnerinhalt hinzufügen
gui, m3u:+OwnDialogs
FileSelectFolder, folder, *%A_WorkingDir%, , Ordner wählen
if ErrorLevel
return
SB_SetText("Mediendateien werden gesucht",2)
SB_SetText("...",1)
Loop, % folder "\*.*", 0, 1
{
file_p := SplitPath(A_LoopFileFullPath)
if A_LoopFileExt in %audio_list%
{
jo++
zz++
pl[zz,"Titel"] := file_p.NameNoExt
pl[zz,"Meta"] := "#EXTINF:-1," file_p.NameNoExt
pl[zz,"Pfad"] := A_LoopFileFullPath
}
}
if jo
{
LV_Delete()
gosub, doppelte_er
SB_SetText(jo " Mediendateien hinzugefügt",2)
}
else
SB_SetText("keine Mediendateien gefunden",2)
SB_SetText(LV_GetCount("S") . " von " . LV_GetCount() . " Einträgen markiert",1)
return
; ------------------------------------------------------------------------------
play:
run, %file%
SB_SetText("Playlist gestartet",2)
return
; ------------------------------------------------------------------------------
lvadd: ; LV füllen
GuiControl, -Redraw, mylv
for, key, val in pl
{
if (StrLen(pl[key,"Titel"]) > 1)
LV_Add("",key, pl[key,"Titel"], pl[key,"Funde"],zähle_pipe(pl[key,"Funde"]),pl[key,"Bemerk"],pl[key,"Pfad"])
}
GuiControl, +Redraw, mylv
LV_ModifyCol()
SB_SetText(LV_GetCount("S") . " von " . LV_GetCount() . " Einträgen markiert",1)
return
; ------------------------------------------------------------------------------
m3uGuiDropFiles:
ToolTip
drop_files := {}
jo =
Loop, parse, A_GuiEvent, `n
drop_files.Insert(A_LoopField)
file_p := SplitPath(drop_files.1)
if (file_p.Extension = "m3u" or file_p.Extension = "m3u8") ; m3u Datei gedropt, muss die erste oder besser einzige Datei sein
{
file := drop_files.1
goto, drop
}
for key, v in drop_files
{
file_p := SplitPath(drop_files[A_Index])
ex := file_p.Extension
if ex in %audio_list%
{
jo++
zz++
pl[zz,"Titel"] := file_p.NameNoExt
pl[zz,"Meta"] := "#EXTINF:-1," file_p.NameNoExt
pl[zz,"Pfad"] := drop_files[A_Index]
LV_Add("",zz, pl[zz,"Titel"], pl[zz,"Funde"],zähle_pipe(pl[zz,"Funde"]),pl[zz,"Bemerk"],pl[zz,"Pfad"])
}
}
if jo
{
gosub, doppelte_er
SB_SetText("Drop Files: " jo " Audiodateien hinzugefügt",2)
}
else
SB_SetText("Drop Files: keine m3u-, oder Audiodatei",2)
SB_SetText(LV_GetCount("S") . " von " . LV_GetCount() . " Einträgen markiert",1)
return
; ------------------------------------------------------------------------------
öffnen:
gui, m3u:+OwnDialogs
FileSelectFile, file_t, , %file%, neue Playlist speichern, M3U-Playlists(*.m3u;*.m3u8)
if Errorlevel
return
file := file_t
goto, drop
return
; ------------------------------------------------------------------------------
speichern_u:
gui, m3u:+OwnDialogs
FileSelectFile, file_t, S16, %file%, neue Playlist speichern, M3U-Playlists(*.m3u;*.m3u8)
if Errorlevel
return
file := SplitPath(file_t).Extension = "m3u" ? file_t : file_t ".m3u"
gosub, speichern
return
; ------------------------------------------------------------------------------
speichern:
ToolTip
SB_SetText("wird gespeichert...",2)
FileDelete, % ftmp
stmp := "#EXTM3U"
Loop, % LV_GetCount()
{
LV_GetText(lv_text, A_Index, 1)
stmp .= "`n" pl[lv_text,"Meta"] "`n" pl[lv_text,"Pfad"]
}
;~ StrPutVar(stmp, &stmp, "UTF-8") ; wandelt String in UTF-8 um
FileAppend, % stmp, % ftmp, ; UTF-8
FileCopy, % ftmp, % file, 1
SB_SetText("fertig gespeichert",2)
SetWorkingDir, % SplitPath(file).Dir
GuiControl, , mytext, % file
return
; ------------------------------------------------------------------------------
doppelt_markieren: ; markiert mehrfache Einträge, aber nicht den Ersten
ToolTip
SB_SetText("wird markiert...",2)
Gui m3u:ListView, mylv
LV_Modify(0, "-Select") ; selektion für alle aufheben
Loop, % LV_GetCount()
{
LV_GetText(lv_text, A_Index, 4)
LV_GetText(lv_text2, A_Index, 3)
LV_GetText(lv_text3, A_Index, 1)
StringSplit, feld, lv_text2, |
if (lv_text > 0 and feld1 != lv_text3)
LV_Modify(A_Index,"Select")
}
GuiControl, Focus, mylv,
SB_SetText(LV_GetCount("S") . " von " . LV_GetCount() . " Einträgen markiert",1)
SB_SetText("fertig markiert (ohne Erstvorkommende)",2)
return
; ------------------------------------------------------------------------------
Dateien_löschen: ; entfernt selektierte Dateien
ToolTip
gui, m3u:+OwnDialogs
MsgBox, 262212, Löschen bestätigen!, Sollen ausgewählte Einträge und Dateien wirklich endgültig gelöscht werden?,
IfMsgBox, No
return
SB_SetText("wird gelöscht...",2)
Loop
{
Reihennummer := LV_GetNext(0) ; Setzt die Suche bei der nächsten Reihe fort.
If not Reihennummer ; Wenn die obige Funktion eine 0 zurückgibt, ist keine weitere Reihe ausgewählt.
break
LV_GetText(dertext, Reihennummer, 1)
pl[dertext,"Meta"] := {}
pl[dertext,"Titel"] := {}
pl[dertext,"Funde"] := {}
FileDelete, % pl[dertext,"Pfad"]
pl[dertext,"Pfad"] := {}
LV_Delete(Reihennummer)
}
if !LV_GetCount()
{
zz=
t := {}
pl := {}
Fehlt := {}
}
gosub, doppelte_er
LV_Delete()
gosub, lvadd
SB_SetText(LV_GetCount("S") . " von " . LV_GetCount() . " Einträgen markiert",1)
SB_SetText("fertig gelöscht",2)
return
; ------------------------------------------------------------------------------
eintr_löschen: ; entfernt selektierte Einträge
ToolTip
gui, m3u:+OwnDialogs
MsgBox, 262212, Löschen bestätigen!, Sollen ausgewählte Einträge wirklich aus der Playliste entfernt werden?,
IfMsgBox, No
return
SB_SetText("wird gelöscht...",2)
Loop
{
Reihennummer := LV_GetNext(0) ; Setzt die Suche bei der nächsten Reihe fort.
If not Reihennummer ; Wenn die obige Funktion eine 0 zurückgibt, ist keine weitere Reihe ausgewählt.
break
LV_GetText(dertext, Reihennummer, 1)
pl[dertext,"Meta"] := {}
pl[dertext,"Titel"] := {}
pl[dertext,"Funde"] := {}
pl[dertext,"Pfad"] := {}
LV_Delete(Reihennummer)
}
if !LV_GetCount()
{
zz=
t := {}
pl := {}
Fehlt := {}
}
gosub, doppelte_er
LV_Delete()
gosub, lvadd
SB_SetText(LV_GetCount("S") . " von " . LV_GetCount() . " Einträgen markiert",1)
SB_SetText("fertig gelöscht",2)
return
; ------------------------------------------------------------------------------
neu: ; neue PL erzeugen
pl := {}
ToolTip
gui, m3u:+OwnDialogs
FileSelectFile, file_t, S16, %file%, neue Playlist speichern, M3U-Playlists(*.m3u;*.m3u8)
if Errorlevel
return
file := SplitPath(file_t).Extension = "m3u" ? file_t : file_t ".m3u"
LV_Delete()
SetWorkingDir, % SplitPath(file).Dir
;~ MsgBox, % "#" SplitPath(file).Extension "#`n" file "`n" file_t
GuiControl, , mytext, % file
SB_SetText(LV_GetCount("S") . " von " . LV_GetCount() . " Einträgen markiert",1)
SB_SetText("neue Playlist",2)
ToolTip, Audiodateien per Drag&Drop hinzufügen
return
; ------------------------------------------------------------------------------
Exit:
m3uGuiClose:
ExitApp
; ------------------------------------------------------------------------------
zähle_pipe(st)
{
StringReplace, out, st, |, , UseErrorLevel
return ErrorLevel
}
; ------------------------------------------------------------------------------
; http://www.autohotkey.com/board/topic/73107-solvedscript-in-unicode-string-in-ansisolved/
StrPutVar(String, ByRef Var, Codierung)
{
; Kapazität gewährleisten.
VarSetCapacity(Var, StrPut(String, Codierung)
; StrPut gibt die Zeichenanzahl zurück, aber VarSetCapacity benötigt Bytes.
* ((Codierung = "utf-16" || Codierung = "cp1200") ? 2 : 1) )
; Kopiert oder wandelt den String um.
Return StrPut(String, &Var, Codierung)
}
; ------------------------------------------------------------------------------
SplitPath(InputVar="")
{
out := Object()
SplitPath, InputVar, FileName, Dir, Extension, NameNoExt, Drive
out["FileName"] := FileName
out["Dir"] := Dir
out["Extension"] := Extension
out["NameNoExt"] := NameNoExt
out["Drive"] := Drive
out["Errorlevel"] := Errorlevel
Return out
}
; ------------------------------------------------------------------------------
zeige_ex:
loop, % pl[o_lv.1,"Pfad"] ; falls releativer Pfad wird Suchmuster geloopt und gibt den absoluten Pfad zurück
kontextfile := A_LoopFileLongPath
ShellContextMenu(kontextfile)
return
; ------------------------------------------------------------------------------
zeige_datei:
run, % A_WinDir "\explorer.exe /select,/e," (InStr(pl[o_lv.1,"Pfad"], "\") ? "" : SplitPath(file).Dir "\") pl[o_lv.1,"Pfad"], , Max
return
; ------------------------------------------------------------------------------
d_lv:
ToolTip
If A_GuiEvent = D
{
LV_Rows.Drag() ; Call Drag function.
History%ActiveList%.Add() ; Add an entry in History.
return
}
SB_SetText(LV_GetCount("S") . " von " . LV_GetCount() . " Einträgen markiert",1)
if A_GuiEvent not in RightClick,DoubleClick
return
row := !LV_GetNext(1, "F") ? 1 : LV_GetNext(1, "F")
o_lv := {}
Loop, 6
{
LV_GetText(lv_text, row, A_Index)
o_lv[A_Index] := lv_text
}
if A_GuiEvent = DoubleClick
gosub, zeige_datei
if A_GuiEvent = RightClick
Menu, mymenü, Show
Return
; ------------------------------------------------------------------------------
pfad:
gui, m3u:+OwnDialogs
SB_SetText("Pfad ändern...",2)
FileSelectFile, new_pf,
, % FileExist(SplitPath(pl[o_lv.1,"Pfad"]).Dir) ? SplitPath(pl[o_lv.1,"Pfad"]).Dir : ""
, neuen Pfad zum Titel
, Audio(*.mp3;.*wma;*.ogg;*.acc;*.wav)
if ErrorLevel
{
SB_SetText("Pfad ändern abgebrochen",2)
return
}
gui m3u:Default
LV_Modify(row, "", o_lv.1,o_lv.2,o_lv.3,o_lv.4,"",new_pf)
pl[row,"Pfad"] := new_pf
SB_SetText("Pfad ändern fertig",2)
return
; ------------------------------------------------------------------------------
tt:
ToolTip
return
; ------------------------------------------------------------------------------
tool_control:
if (A_TimeIdle > 700)
{
MouseGetPos, , , id, Control
ControlGetText, Text, %Control%, ahk_id %Ausgabevariable%
if (tool[text] and id = Ausgabevariable and control)
{
ToolTip, % tool[text] ; "`n" id "`n" control
is_tool++
SetTimer, tt , -2000
}
if (tool[Control] and id = Ausgabevariable)
{
is_tool++
ToolTip, % tool[Control] ; "`n" id "`n" control
SetTimer, tt , -2000
}
}
else
if is_tool
{
is_tool := ""
ToolTip, ; % Control "`n" text
}
return
; ------------------------------------------------------------------------------
StringSplit(InputVar="", Delimiters="", OmitChars="")
{
realArray := {}
StringSplit, out, InputVar, %Delimiters%, %OmitChars%
loop, % out0
realArray.Insert(out%A_Index%)
realArray["Errorlevel"] := Errorlevel
Return realArray
}
; ------------------------------------------------------------------------------
info:
breite := A_ScreenWidth // 10 * 9
Gui 3: Add, ActiveX, x0 y-5 w%breite% h600 vwb, Shell.Explorer
Gui 3: font, S12 bold
Gui 3: Add, Button, x5 y+10 w55 gok, OK
; Document.write(html)
WB.Navigate(ctc_hilfe) ; Speziell für das Web-Browser-Steuerelement.
Gui 3:+Ownerm3u
Gui m3u:+Disabled
Gui 3: Show, ,
Return
; ------------------------------------------------------------------------------
3GuiClose:
ok:
Gui 3: Destroy
gui m3u:Default
Gui m3u:-Disabled
if !Hidden_f
Gui m3u:Show
Return
notepad_out( data) {
static Pid := 0
Process, exist, % PID
If (Errorlevel = 0)
Run Notepad.exe, , , PID
WinActivate, ahk_pid %PID%
WinWaitActive, ahk_pid %PID%
ControlSetText, Edit1, %data%, ahk_pid %PID%
}
; ------------------------------------------------------------------------------
RegRead(RootKey="", SubKey="", ValueName="")
{
RegRead, out, %RootKey%, %SubKey%, %ValueName%
Return out
}
; ------------------------------------------------------------------------------
RegWrite(ValueType="", RootKey="", SubKey="", ValueName="", Value="")
{
try
RegWrite, %ValueType%, %RootKey%, %SubKey%, %ValueName%, %Value%
catch e
Return e.Message
}
; ------------------------------------------------------------------------------
date()
{
FormatTime, dd
return dd
}
; ------------------------------------------------------------------------------
#If WinActive("ahk_id " Ausgabevariable)
^a::
gui, m3u:Default
LV_Modify(0,"Select")
return
*Space::
gui, m3u:Default
gosub, play_titel
return
#If
; ------------------------------------------------------------------------------
htmlmsg:
html =
(
<body>
<h2>Kopieren beendet! %fehler% von %von%
Dateien konnten nicht kopiert werden:</h2>
<br><br>
%fehlertext%
</body>
)
Gui, msg:Add, ActiveX, x0 y-5 w840 h350 vDocument, HTMLFile
Gui, msg:font, S12
Gui, msg:Add, Button, x5 y+10 w85 gokhtml, OK
Document.write(html)
Gui, m3u:-Disabled
Gui, msg:+Ownerm3u
Gui, m3u:+Disabled
Gui, msg:Show
Return
okhtml:
msgGuiClose:
Gui, msg:Destroy
Gui, m3u:-Disabled
Gui, m3u:Show
return
; ------------------------------------------------------------------------------
function_control(f_contr, f_en=1)
{
global
local contr_array
StringSplit, contr_array, f_contr, |
Loop, %contr_array0%
GuiControl, % (f_en ? "Enable" : "Disable"), % contr_array%A_Index%
Return
}
; ------------------------------------------------------------------------------
; Run, % make_rel(OutDir,ordner) OutFileName, %ordner%
; ----------------------------Funktion------------------------------------------
; gibt den relativen Windowspfad zurück bei Übergabe von Pfad(p) und Referenz(ref),beide OHNE Backslash übergeben
; zurückgegebener Pfad MIT Backslash
make_rel(p,ref) ; anzupassender Pfad,Referenz
{
p_old := p
if SubStr(p,1,2) = "\\" ; Netzwerkpfad
{
p := "ÿ" SubStr(p,3,500)
}
if SubStr(ref,1,2) = "\\" ; Netzwerkpfad
{
ref := "ÿ" SubStr(ref,3,500)
}
StringSplit, arr_p, p, \
StringSplit, arr_ref, ref, \
If (p = ref) ; identische Ordner
Return ".\"
If (arr_p1 != arr_ref1)
Return ;"kein gemeinsames Root"
Loop, 300 ; Tiefe
{
tp := tp ? tp "\" arr_p%A_Index% : arr_p%A_Index%
tp_r := tp_r ? tp_r "\" arr_ref%A_Index% : arr_ref%A_Index%
If (tp != tp_r)
Break
zz++
tmp := tp ; größter gemeinsamer Nenner
}
If (tmp = ref) ; Referenz ist Root von Pfad
{
StringReplace, Out, p, %ref%
Return "." Out "\"
}
StringReplace, Out, p, % tmp (tmp = p ? "" : "\")
out := out ? (SubStr(out, 1, 1) = "\" ? out : "\" out) : ""
;~ MsgBox, % "größter Nenner:`n" tmp "`n" p "`n" ref "`n" zz "`nPfadtiefe: " arr_p0 "`nPfadtiefe Ref: " arr_ref0 "`n" m_p(arr_ref0 - zz) out "\"
Return StringReplace((m_p(arr_ref0 - zz) out "\"),"ÿ","\\")
}
; --------------------------------------------------------
make_unrel(ss)
{
Loop, % ss
t := A_LoopFileLongPath
return t
}
; -----------------------gehört dazu--------------------------------------------
m_p(st)
{
Loop, %st%
ID := ID ? ID "\.." : ".."
Return ID
}
; ------------------------------------------------------------------------------
replacehtml(st) ; wirdnicht mehr benötigt
{
global d_k
;~ StringReplace, o, st, `%, `%25, All
StringReplace, o, st, `%20, %a_space%, All
;~ StringReplace, o, o, ``, `%22, All
For Key , Value in d_k
{
;~ MsgBox, % key
StringReplace, o, o, % key, % value, All
}
return o
}
load: ; wirdnicht mehr benötigt
d_k := {}
d_k := { "%80": "€"
, "%82": "‚"
, "%83": "ƒ"
, "%84": "„"
, "%88": "ˆ"
, "%8b": "‹"
, "%91": "‘"
, "%92": "’"
, "%93": "“"
, "%94": "”"
, "%96": "–"
, "%97": "—"
, "%98": "˜"
, "%9b": "›"
, "%a1": "¡"
, "%a3": "£"
, "%a7": "§"
, "%a8": "¨"
, "%b4": "´"
, "%b7": "·"
, "%b8": "¸"
, "%c4": "Ä"
, "%d6": "Ö"
, "%d8": "Ø"
, "%dc": "Ü"
, "%df": "ß"
, "%e4": "ä"
, "%f6": "ö"
, "%f7": "÷"
, "%fc": "ü"
, "%24": "$"
, "%26": "&"
, "%2b": "+"
, "%2c": ","
, "%2f": "/"
, "%3b": ";"
, "%3d": "="
, "%3f": "?"
, "%40": "@"
, "%3c": "<"
, "%3e": ">"
, "%23": "#"
, "%7b": "{"
, "%7d": "}"
, "%7c": "|"
, "%5e": "^"
, "%7e": "~"
, "%5b": "["
, "%28": "("
, "%29": ")"
, "%C3%BC": "ü"
, "%C26": "&"
, "%21": "!"
, "%C3%BA": "ú"
, "%27": "'"
, "%C3%A9": "é"
, "%C3˜": "Ø"
, "%5d": "]"
, "%C3%9C": "ü"
, "%C3%A5": "å"
, "%C3%B6": "ö"
, "%C3%A4": "ä"
, "%C3%AB": "ë"
, "%C3¨": "è"
, "%C3¡": "á"
, "%C2%A0": " "
, "%C3§": "ç"
, "%C3–": "Ö"
, "%C2%BF": "¿"
, "%C2%AE": "®"
, "%C3%B1": "ñ"
, "%C3%89": "É"
, "%C3%9F": "ß"
, "%C3%AE": "î"
, "%C3%B3": "ó"
, "%C2¡": "¡"
, "%C3´": "ô"
, "%C3„": "Ä"
, "%C3%AD": "í"
, "%C3%A0": "à"
, "%C3‹": "Ë"
, "%C2%B4": "´"
, "%C3¸": "ø"
, "%60": "``"}
return
; ------------------------------------------------------------------------------
StringReplace(InputVar="", SearchText="", ReplaceText="", ReplaceAll="")
{
StringReplace, out, InputVar, %SearchText%, %ReplaceText%, %ReplaceAll%
Return out
}
; ------------------------------------------------------------------------------
;~ https://www.autohotkey.com/boards/viewtopic.php?p=31904&sid=31cdf32af43e34e6d2213dc8354a2d46#p31904
UriDecode(Uri, Encoding := "UTF-8") { ; Encoding must be either "UTF-16" or "CP0"
If (Encoding <> "UTF-8") && (Encoding <> "CP0")
Encoding := "UTF-8"
Split := StrSplit(Uri)
Length := Split.MaxIndex()
VarSetCapacity(AStr, Length, 0)
Index := 1
Addr := &AStr
While (Index <= Length) {
If (Split[Index] <> "%")
Addr := NumPut(Asc(Split[Index]), Addr + 0, "UChar")
Else
Addr := NumPut("0x" . Split[++Index] . Split[++Index], Addr + 0, "UChar")
Index++
}
Return StrGet(&AStr, Encoding)
}
; ------------------------------------------------------------------------------
;~ https://www.autohotkey.com/boards/viewtopic.php?t=84825#p372134
EncodeDecodeURI(str, encode := true, component := true) {
static Doc, JS
if !Doc {
Doc := ComObjCreate("htmlfile")
Doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
JS := Doc.parentWindow
( Doc.documentMode < 9 && JS.execScript() )
}
Return JS[ (encode ? "en" : "de") . "codeURI" . (component ? "Component" : "") ](str)
}