Peter Gyger online

"Gring ache u seckle" (Quelle: A. Weyermann)

NAVIGATION - SEARCH

Powershell mit TagLib / taglib-sharp.dll nutzen

Ob man nun Go spielt, ein Sudoku löst oder mit einem Computer programmiert ist aus meiner Sicht gleichwertig. Es zählt, dass man Freude am lernen hat und sich ganz und gar auf eine Aufgabe konzentriert. Meine Begeisterung habe ich in der Programmierung mit Skripten gefunden. Aktuell Powershell, daher auch dieser Blogpost.

TagLib

TagLib ist eine freie Programmbibliothek zur Bearbeitung von Metainformationen in Audiodateien. Ein deutscher Wikipedia Artikel weiss mehr. 

Diese Bibliothek ermöglicht u.a. den Zugriff auf Mediendateien mit MS Powershell. Für die auf dem Microsoft .NET Framework basierten Programme, heisst die Bibliothek "taglib-sharp". Hier der download über eine ZIP-Datei.

In Powershell wird eine DLL wie folgt eingebunden:

[Reflection.Assembly]::LoadFrom([Pfad zur DLL])
Beispiel:
[Reflection.Assembly]::LoadFrom("C:\Program Files\PS1\Podcast-download\taglib-sharp.dll")

 

Welchen praktischen Nutzen hat das?

Beispiel 1:

Wir haben unsere Musik in einem Verzeichnisbaum gespeichert. Struktur: [Künstler] \ [Album]. Das "Cover" des Albums ist im Verzeichnis des Albumes mit dem Namen "folder.jpg" abgelegt. "PNG" wäre besser (Transparenz Ebenen), jedoch beherschen nicht alle Mediensoftware (Kodi / Plex / etc.) dieses Bildformat. Damit beim abspielen der einzelnen Titel, dass "Cover" angezeigt wird, muss die Datei "folder.jpg" in das entsprechende Tag der Mediendatei geschrieben werden. Tools wie "MP3TAG" sind dafür und vieles andere ideal. Jedoch geht es auch automatisch. Z.B. mit dieserm Powershell Skript. Dieses Skript liest nur Audiodateien des Formates "Flac" ein, da meine Musiksammlung keine MP3 Dateien beinhaltet. D.h. diese Zeile muss nach persönlichem Bedarf geändert / ergänzt werden.

#Name:                        Musikdateien in Verzeichnisstruktur - Eigenschaft Bild - Wert zuweisen
#Autor:                       Peter Gyger
#Version:                     1.0
#Datum der letzten Änderung:  18.04.2017

#Wenn im Verzeichnis der MP3 / Flac Dateien eine Bilddatei folder.jpg existiert, wird diese den Dateien hinzugefügt. "folder.jpg" wird von Kodi automatisch erkannt.
#laden der DLL
[Reflection.Assembly]::LoadFrom("C:\Users\Peter\Documents\000 Peter\004 Projekt\Podcast verwalten\taglib-sharp.dll")

$hieristdiemusik ="C:\Temp\000 Musik"

#Mit Foreach alle Musikdaten eines Verzeichnisbaumes finden
foreach ($datei in get-childitem $hieristdiemusik -Filter *.flac -recurse){
    #Datei öffen
    $musikdatei = [TagLib.File]::Create($datei.fullname)
    #prüfen ob die Datei folder.jpg existiert
    if (test-path ($datei.Directoryname+"\folder.jpg")){
        #dann das bild folder.jpg der Variabeln $albumbild zuweisen
        $albumbild = [taglib.picture]::createfrompath($datei.Directoryname+"\folder.jpg")
        }
 
    #Datei Eigenschaft das Bild zuweisen und speichern
    $musikdatei.tag.Pictures = $albumbild
    $musikdatei.save()
    $albumbild = ""
    $musikdatei = ""
    #Anzeige in der PS Konsole, was gerade abgeschlossen wurde
    write-output ($datei.FullName +" mit Bild ergänzt")
}

Man kopiert das Skript in eine Editor, ändert den Wert der Variable "$hieristdiemusik" auf das eigene Musikverzeichnis und speichert die Datei mit der Erweiterung ".PS1" ab. Diese kann nun auf eigenes Risiko - trotz sorgfältiger Erstellung - in der Powershell Konsole oder über Rechtsklick im Win Explorer gestartet werden.

Natürlich wäre ein Befehl wie "InputBox" den man aus Basic (VBA, VB-Script, etc.) kennt praktisch. Dann müsste man nicht im Skript den Wert der Variable "$hieristdiemusik" anpassen. Diesen Befehl ("CMDLET") gibt es in Powershell nicht. Microsoft hat einen einen Artikel mit vollständigem Beispiel veröffentlicht, wie das in Powershell umgesetzt werden kann. Diesen Code kann man in ein eigenes Modul speichern und bei Bedarf in ein Powershell Skript einbinden.

Im zweiten Beispiel habe ich den Code der InputBox direkt in das Skript kopiert. Das macht es einfacher das Programm zu überblicken. Das nachfolgende Programm holt MP3 Dateien ("Podcast") aus einer Website und speichert sie lokal. Das Programm fragt nach einer URL und holt danach die erreichbaren MP3 Dateien ab. Aktuell getestet und verwendet für die SRF Podcasts. Beispiele für solche URL:

  1. http://pod.drs.ch/wissenschaft_drs_2_mpx.xml
  2. http://pod.drs.ch/country_special_mpx.xml
  3. http://podcasts.srf.ch/fiori_musicali_mpx.xml
  4. http://pod.drs.ch/diskothek_im_zwei_mpx.xml
  5. http://podcasts.srf.ch/100_sekunden_wissen_mpx.xml
  6. http://podcasts.srf.ch/regionaljournal_zh_mpx.xml
  7. http://pod.drs.ch/espresso_mpx.xml

 

#Name:                        MP3 Dateien aus RSS Feed (Podcast) downloaden
#Autor:                       Peter Gyger
#Version:                     0.9
#Datum der letzten Änderung:  11.02.2017


[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "Podcast Download"
$objForm.Size = New-Object System.Drawing.Size(300,200)
$objForm.StartPosition = "CenterScreen"

$objForm.KeyPreview = $True
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter")
    {$x=$objTextBox.Text;$objForm.Close()}})
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape")
    {$objForm.Close()}})

$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"

$OKButton.Add_Click({$script:x=$objTextBox.Text;$objForm.Close()})
$objForm.Controls.Add($OKButton)

$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(150,120)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.Add_Click({$objForm.Close()})
$objForm.Controls.Add($CancelButton)

$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(10,20)
$objLabel.Size = New-Object System.Drawing.Size(280,20)
$objLabel.Text = "Bitte den Link hier eingeben"
$objForm.Controls.Add($objLabel)

$objTextBox = New-Object System.Windows.Forms.TextBox
$objTextBox.Location = New-Object System.Drawing.Size(10,40)
$objTextBox.Size = New-Object System.Drawing.Size(260,20)
$objForm.Controls.Add($objTextBox)

$objForm.Topmost = $True

$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()
#write-host "x is $x"

$fileURL =$x


#prüfen ob eine URL eingegeben wurde. Bsp.: http://pod.drs.ch/jazz_collection_mpx.xml
if (!$fileURL) {exit}

$web = New-Object System.Xml.XmlDocument
$web.Load($fileURL)
$fileslash = $fileURL.LastIndexOf("/") +1
$fileName =$fileURL.substring($fileslash)
$dirname = $fileName.substring(0,$fileName.Length -4)

#Überprüfen ob das Verzeichnis c:\temp\ und Unterverzeichnis mypodcast existiert
If (!(Test-Path c:\temp))
{
    write-host c-temp erstellen
    New-Item c:\temp -ItemType directory
}

If (!(Test-Path c:\temp\mypodcast))
{
    write-host c-temp mypodcast
    New-Item c:\temp\mypodcast -ItemType directory
}
Set-Location c:\temp\mypodcast

#Verzeichnis mit dem Namen des Podcasts erstellen
$dirname = $fileName.substring(0,$fileName.Length -4)

If (!(Test-Path c:\temp\mypodcast\$dirname))
{
    Write-Host neues verzeichnis erstellen
    write-host $dirname
    New-Item c:\temp\mypodcast\$dirname -ItemType directory
}
Set-Location c:\temp\mypodcast\$dirname


# *** Teil 2 *** #
#Dateien aus der Website extrahieren

$max =$web.rss.channel.item.Count
$webclient = New-Object System.Net.WebClient
# load the TagLib# assembly into PowerShelL
[Reflection.Assembly]::LoadFrom("C:\Temp\mypodcast\taglib-sharp.dll")
#kalenderwoche ermitteln
$kw = Get-Date -uFormat %V
$kw = $kw + " - "

$i = 0
do
{
  $fileURL = $web.rss.channel.item[$i].guid
  $mp3name = "c:\temp\mypodcast\$dirname\" +$kw +$web.rss.channel.item[$i].title +".mp3"
   write-host c:\temp\mypodcast\$dirname\$mp3name

  If (!(Test-Path c:\temp\mypodcast\$dirname\$mp3name))
{
    write-host $mp3name
    write-host "Die Datei $mp3name wird erstellt"
    $webclient.DownloadFile($fileURL,$mp3name)
    #$media = [TagLib.File]::Create($mp3name)
    $media = [TagLib.File]::Create($mp3name)

    # set the tags
    #$media.Tag.Genre = "Podcast"
    $media.Tag.Album = $dirname
    $media.Tag.Comment = "Neu"
    $media.Save()
}
  $i++
} while ($i -lt $max)

Get-ChildItem *.mp3
Set-Location c:\temp\mypodcast

 

Eine weiterentwickelte Version nachfolgend. Die Source URL sind im Skript definiert. Das Skript wird über den Taskmanager von Windows regelmässig angestossen und ergänzt die Podcasts um die neuen Folgen

#Name:                        MP3 Dateien aus RSS Feed (Podcast) downloaden
#Autor:                       Peter Gyger
#Version:                     1.2
#Datum der letzten Änderung:  1.05.2017

#Überprüfen ob das Verzeichnis c:\temp\ und Unterverzeichnis mypodcast existiert
If (!(Test-Path c:\temp))
{
    write-host c-temp erstellen
    New-Item c:\temp -ItemType directory
}

If (!(Test-Path c:\temp\mypodcast))
{
    write-host c-temp mypodcast
    New-Item c:\temp\mypodcast -ItemType directory
}
Set-Location c:\temp\mypodcast

# load the TagLib# assembly into PowerShelL
[Reflection.Assembly]::LoadFrom("C:\Temp\mypodcast\taglib-sharp.dll")

 ForEach($Number in 1..20) {
    $dirname = ""
    $rssURL = ""
    Switch ($Number) {
                #DRS / SRF Feeds
        1 {$rssURL ="http://pod.drs.ch/jazz_collection_mpx.xml"
        $dirname = "SRF - jazz_collection"
         }
        2 {$rssURL ="http://pod.drs.ch/a_point_mpx.xml"
            $dirname = "SRF - a_point"
        }
        3 {$rssURL ="http://podcasts.srf.ch/100_sekunden_wissen_mpx.xml"
            $dirname = "SRF - 100_sekunden_wissen"
        }
        4 {$rssURL ="http://podcasts.srf.ch/digital_plus_mpx.xml"
            $dirname = "SRF - digital_plus"
        }
        5 {$rssURL ="http://pod.drs.ch/wissenschaft_drs_2_mpx.xml"
            $dirname = "SRF - wissenschaft_drs_2"
        }
        6 {$rssURL ="http://pod.drs.ch/country_special_mpx.xml"
            $dirname = "SRF - country_special"
        }
        7 {$rssURL ="http://podcasts.srf.ch/fiori_musicali_mpx.xml"
            $dirname = "SRF - fiori_musicali"
        }
        8 {$rssURL ="http://pod.drs.ch/diskothek_im_zwei_mpx.xml"
        $dirname = "SRF - diskothek_im_zwei"
        }
        9 {$rssURL ="http://pod.drs.ch/espresso_mpx.xml"
        $dirname = "SRF - espresso"
         }
        #Heise Feeds
        10 {$rssURL ="https://www.heise.de/ct/uplink/ctuplink.rss"
        $dirname = "ctuplink"
        }
      
        #diverse
        14 {$rssURL ="http://www.br-online.de/podcast/cd-tipp-der-woche/cast.xml"
            $dirname = "BR - Classic aktuell"
        }
    }
   
$web = New-Object System.Xml.XmlDocument
    $web.Load($rssURL)
    $max =$web.rss.channel.item.Count
    $webclient = New-Object System.Net.WebClient

     If (!(Test-Path c:\temp\mypodcast\$dirname))
    {
        Write-Host neues verzeichnis erstellen
        write-host $dirname
        New-Item c:\temp\mypodcast\$dirname -ItemType directory
    }
    Set-Location c:\temp\mypodcast\$dirname
    write-host c:\temp\mypodcast\$dirname

    $i = 0

    do
    {
      $mp3name = ""
      $mp3name =$web.rss.channel.item[$i].title +".mp3"
      #Sonderzeichen die das NTFS Dateisystem nicht akzeptiert ersetzen
      $mp3name = $mp3name.Replace("/","_")
      $mp3name = $mp3name.Replace("\","_")
      $mp3name = $mp3name.Replace("?","_")
      $mp3name = $mp3name.Replace(":","_")
      $mp3name = $mp3name.Replace(""" ","_")
      $mp3name = "c:\temp\mypodcast\$dirname\" +$mp3name
 
      #$mp3name = "c:\temp\mypodcast\$dirname\" +$kw +$fileURL.Substring(35)

      If (!(Test-Path $mp3name))    {
        #mp3 podcast?
        If (!($mp3name.endswith(".mp3")))    {
        write-host "keine MP3 Datei"
        $mp3name
        }
        write-host "Die Datei $mp3name wird erstellt"
        $fileURL = $web.rss.channel.item[$i].guid
        $webclient.DownloadFile($fileURL,$mp3name)
        #$media = [TagLib.File]::Create($mp3name)
        $media = [TagLib.File]::Create($mp3name)
        # set the tags
        #$media.Tag.Genre = "Podcast"
        #$media.Tag.Album = $dirname
        $media.Tag.Comment = "Neu"
        $media.Save()
    }
      $i++
    } while ($i -lt $max)
    }

Die hier vorgestellten Codebeispiele in der hier genannten Version sind "Public Domain CC". Jeder darf sie verwenden und ändern.  Vielleicht entdeckt jemand ein neues, spannendes Hobby?

 

 

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading