using Microsoft.VisualBasic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.DirectoryServices.ActiveDirectory; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Security.Cryptography; namespace PlaylistManager { public partial class frmMain : Form { private DataTable dtReplacePaths = null!; private DataTable dtPLPaths = null!; private DataView dvPLPaths = null!; private System.Text.Encoding Enc = System.Text.Encoding.UTF8; private string settingsfile = Application.StartupPath + @"\settings.json"; private Settings settings = null!; public enum SortType { [Description("Titel")] Title, [Description("Titelnr.")] TitleNo, [Description("Dateiname")] Filename, [Description("Künstler")] Artist } public frmMain() { InitializeComponent(); } private void frmMain_Load(object sender, EventArgs e) { Text += " v." + Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? ""; prepareReplacePath(); settings = Settings.Load(settingsfile); /* TODO ERROR: Skipped IfDirectiveTrivia #If DEBUG Then */ txtList.Text = @"D:\Privat\Mixed"; SFD.FileName = "test.xls"; /* TODO ERROR: Skipped EndIfDirectiveTrivia #End If */ } private void btnPlaylist_Click(object sender, EventArgs e) { if (OFD.ShowDialog() == DialogResult.OK) { string prevPlaylistFolder = GetPlaylistFolderName(txtExtractPlaylist.Text); txtExtractPlaylist.Text = OFD.FileName; if (txtExtractTargetfolder.Text == "" || txtExtractTargetfolder.Text == prevPlaylistFolder) txtExtractTargetfolder.Text = GetPlaylistFolderName(OFD.FileName); } } /// /// Generiert einen Ordnernamen der dem Namen der Playlist entspricht, als Zielordner-Vorschlag /// /// /// private string GetPlaylistFolderName(string playlistfile) { return Path.Combine(Path.GetDirectoryName(playlistfile) ?? "", Path.GetFileNameWithoutExtension(playlistfile)); } private void lblPlaylistOpen_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { OpenFile(txtExtractPlaylist.Text); } private void OpenFile(string datei) { if (File.Exists(datei)) { Process.Start("notepad.exe", datei); } } private void frmMain_FormClosing(object sender, FormClosingEventArgs e) { settings.Save(settingsfile); } private void frmMain_DragEnter(object sender, DragEventArgs e) { if (e.Data == null) return; if (e.Data.GetDataPresent(DataFormats.FileDrop)) { switch (tcMain.SelectedTab?.Name ?? "") { case var @case when @case == (tpExtract.Name ?? ""): { e.Effect = DragDropEffects.Copy; break; } case var case1 when case1 == (tpChangepath.Name ?? ""): { e.Effect = DragDropEffects.Copy; break; } default: { e.Effect = DragDropEffects.None; break; } } } } private void frmMain_DragDrop(object sender, DragEventArgs e) { if (e.Data == null) return; if (e.Data.GetDataPresent(DataFormats.FileDrop)) { string[]? files = (string[]?)e.Data.GetData(DataFormats.FileDrop); if (files == null) return; switch (tcMain.SelectedTab?.Name ?? "") { case var @case when @case == (tpExtract.Name ?? ""): { foreach (string datei in files) { if (datei.EndsWith(".m3u8") | datei.EndsWith(".m3u") | datei.EndsWith("bak")) // beim letzten kein Punkt is absicht, da die backupdateien mit .m3ubak und .m3u8bak enden! { txtExtractPlaylist.Text = datei; break; } } break; } case var case1 when case1 == (tpChangepath.Name ?? ""): { foreach (string datei in files) { if (datei.EndsWith(".m3u8") | datei.EndsWith(".m3u") | datei.EndsWith("bak")) // beim letzten kein Punkt is absicht, da die backupdateien mit .m3ubak und .m3u8bak enden! { lstCPPlaylists.Items.Add(datei); } } readPlaylistpaths(); break; } } } } private void btnOK_Click(object sender, EventArgs e) { switch (tcMain.SelectedTab?.Name ?? "") { case var @case when @case == (tpExtract.Name ?? ""): { ExtractPlaylist(txtExtractPlaylist.Text, txtExtractTargetfolder.Text); break; } case var case1 when case1 == (tpChangepath.Name ?? ""): { ChangePaths(); break; } case var case2 when case2 == (tpList.Name ?? ""): { CreateTracklist(); break; } } } #region Playlist extrahieren private void btnMP3_Click(object sender, EventArgs e) { if (FBD.ShowDialog() == DialogResult.OK) { txtExtractTargetfolder.Text = FBD.SelectedPath; } } private void ExtractPlaylist(string PlaylistFile, string TargetFolder) { if (!TargetFolder.EndsWith("\\")) TargetFolder += "\\"; try { if (!Directory.Exists(TargetFolder)) Directory.CreateDirectory(TargetFolder); } catch (Exception ex) { MessageBox.Show($"Unable to create folder '{TargetFolder}':\r\n{ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } var sr = new StreamReader(PlaylistFile, Enc); string? line; string alternativePath; var frm = new frmList(); while (sr.EndOfStream == false) { line = sr.ReadLine(); if (line is not null & line.Substring(0, 1) != "#") { alternativePath = Path.GetDirectoryName(PlaylistFile) ?? ""; if (alternativePath.LastIndexOf(@"\") < alternativePath.Length - 1) alternativePath += @"\"; alternativePath += line; if (File.Exists(line)) { frm.lstGefunden.Items.Add(line); } else if (File.Exists(alternativePath)) { frm.lstGefunden.Items.Add(alternativePath); } else { frm.lstNichtGefunden.Items.Add(line); } } } sr.Close(); sr = null; int i = 1; if (frm.ShowDialog() == DialogResult.OK) { var frm2 = new frmProgress(); string datei; frm2.prgStatus.Maximum = frm.lstGefunden.Items.Count; frm2.prgStatus.Value = 0; frm2.Show(); Application.DoEvents(); foreach (string itm in frm.lstGefunden.Items) { if (frm2.cancelled == false) { datei = Path.GetFileName(itm); frm2.lblFile.Text = datei; if (chkExtractSortFiles.Checked) { File.Copy(itm, TargetFolder + Strings.Format(i, "000") + "." + datei, true); i += 1; } else { File.Copy(itm, TargetFolder + datei, true); } frm2.prgStatus.PerformStep(); Application.DoEvents(); } else { Application.DoEvents(); break; } } frm2.Close(); } } #endregion #region Pfad ändern private void prepareReplacePath() { dtReplacePaths = new DataTable(); { var withBlock = dtReplacePaths.Columns; withBlock.Add("originalpath", typeof(string)); withBlock.Add("replacepath", typeof(string)); } dgvRep.DataSource = dtReplacePaths; dtPLPaths = new DataTable(); { var withBlock1 = dtPLPaths.Columns; withBlock1.Add("Path", typeof(string)); withBlock1.Add("Length", typeof(int)); withBlock1.Add("Matchcount", typeof(int)); withBlock1.Add("Matchresult", typeof(bool)); } dvPLPaths = new DataView(dtPLPaths); dvPLPaths.Sort = "Matchresult, Matchcount, Length, Path"; dgvFoundPaths.DataSource = dvPLPaths; } private void readPlaylistpaths() { dtPLPaths.Rows.Clear(); DataRow dr; foreach (string datei in lstCPPlaylists.Items) { if (File.Exists(datei)) { var sr = new StreamReader(datei, Enc); string? line; bool lineexists; while (!sr.EndOfStream) { line = sr.ReadLine(); if (line == null) break; if (line.StartsWith("#") == false & line.Trim().Length > 0) { line = Path.GetDirectoryName(line); lineexists = false; foreach (DataRow row in dtPLPaths.Rows) { if ((string)row["Path"] == line) { lineexists = true; break; } } if (lineexists == false) { dr = dtPLPaths.NewRow(); dr["Path"] = line; dr["Length"] = line.Length; dr["Matchcount"] = 0; dr["Matchresult"] = false; dtPLPaths.Rows.Add(dr); } } } sr.Close(); } } checkMatches(); } private void checkMatches() { if (dgvFoundPaths.DataSource is DataView) { dgvFoundPaths.EndEdit(); DataView dv; dv = (DataView)dgvFoundPaths.DataSource; // Matchcount clearen foreach (DataRowView pathrow in dv) { pathrow["Matchcount"] = 0; pathrow["Matchresult"] = false; } foreach (DataRowView pathrow in dv) { foreach (DataRow replrow in dtReplacePaths.Rows) { if (replrow["originalpath"] == DBNull.Value) continue; string origpath = (string)replrow["originalpath"]; string path = (string)pathrow["path"]; if (path.ToLower().StartsWith(origpath.ToLower())) { pathrow["Matchcount"] = (int)pathrow["Matchcount"] + 1; } } } // Matchresult überprüfen // 0 = Keinen Ersetzungspfad gefunden, evtl ist er ja schon korrekt (einer der neuen Pfade?) // 1 = Genau ein Ergebnis gefunden, passt - wird so ersetzt // >1 =Mehr als ein Ersetzergebnis - Ersetzliste kontrollieren foreach (DataRowView row in dv) { switch ((int)row["Matchcount"]) { case 0: { // Neue Pfade überprüfen. Evtl müssen die Pfade ja nicht ersetzt werden, weil es schon Replace-Pfade sind. foreach (DataRow replrow in dtReplacePaths.Rows) { if (replrow["replacepath"] == DBNull.Value) continue; string replpath = (string)replrow["replacepath"]; string path = (string)row["Path"]; if (replpath.Trim().Length > 0) { if (path.ToLower().StartsWith(replpath.ToLower())) { row["Matchresult"] = true; break; } } } break; } // Matchresult wurde oben schon auf false gesetzt, deshalb hier nicht mehr nötig case 1: { row["Matchresult"] = true; break; } default: { row["Matchresult"] = false; break; } } } } } private void dgvRep_CellContentClick(object sender, DataGridViewCellEventArgs e) { DataGridView grd = (DataGridView)sender; if (grd.Columns[e.ColumnIndex] is DataGridViewButtonColumn & e.RowIndex >= 0) { if (FBD.ShowDialog() == DialogResult.OK) { string path = FBD.SelectedPath; if (!path.EndsWith("\\")) path += "\\"; switch (grd.Columns[e.ColumnIndex].Name ?? "") { case var @case when @case == colOriginalPathBrowse.Name: { grd.Rows[e.RowIndex].Cells[colOriginalPath.Name].Value = path; break; } case var case1 when case1 == colReplaceToBrowse.Name: { grd.Rows[e.RowIndex].Cells[colReplaceTo.Name].Value = path; break; } } } } dtReplacePaths.AcceptChanges(); } private void dgvRep_CellValueChanged(object sender, DataGridViewCellEventArgs e) { checkMatches(); } private void ChangePaths() { dtReplacePaths.AcceptChanges(); var notfoundplaylists = new List(); foreach (string playlistfile in lstCPPlaylists.Items) { if (File.Exists(playlistfile)) { // Backup anlegen string backupfile = Path.GetDirectoryName(playlistfile) + @"\" + Path.GetFileNameWithoutExtension(playlistfile) + "_" + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss") + Path.GetExtension(playlistfile) + "bak"; File.Copy(playlistfile, backupfile, true); // Erst alle Einträge einlesen string? line; var lines = new List(); var reader = new StreamReader(playlistfile, Enc); while (reader.EndOfStream == false) { line = reader.ReadLine(); if (line == null) break; char CommentChar = Convert.ToChar("#"); if (line[0] != CommentChar) { // Jeden Replace-Eintrag durchgehen bis der erste passende gefunden wurde foreach (DataRow row in dtReplacePaths.Rows) { if (row["originalpath"] == DBNull.Value) continue; string origpath = (string)row["originalpath"]; string replpath = row["replacepath"] == DBNull.Value ? "" : (string)row["replacepath"]; if (line.ToLower().StartsWith(origpath.ToLower())) { line = line.Replace(origpath, replpath); break; } } } lines.Add(line); } reader.Close(); // Dann alle Einträge reinschreiben var writer = new StreamWriter(playlistfile, false, Enc); foreach (string readline in lines) writer.WriteLine(readline); writer.Close(); } else { notfoundplaylists.Add(playlistfile); } } if (notfoundplaylists.Count > 0) { MessageBox.Show($"Eine oder mehrere Playlistdateien wurden nicht gefunden: {Constants.vbCrLf} {string.Join(Constants.vbCrLf, notfoundplaylists.ToArray())}"); } else { MessageBox.Show("Vorgang erfolgreich abgeschlossen"); } } private void dgvFoundPaths_CellDoubleClick(object sender, DataGridViewCellEventArgs e) { dtReplacePaths.AcceptChanges(); string pathToAdd = (string)dgvFoundPaths.SelectedCells[0].Value; foreach (DataRow row in dtReplacePaths.Rows) { if (row["originalpath"] == DBNull.Value) continue; string origpath = (string)row["originalpath"]; if (pathToAdd.ToLower().StartsWith(origpath.ToLower())) { // Der Pfad, der durch doppelklick hinuzgefügt werden soll, existiert bereits in einer Form in ReplacePaths return; } } var dr = dtReplacePaths.NewRow(); dr["originalpath"] = pathToAdd.Trim(); dtReplacePaths.Rows.Add(dr); } #endregion #region Tracklist erzeugen private void btnList_Click(object sender, EventArgs e) { if (FBD.ShowDialog() == DialogResult.OK) { txtList.Text = FBD.SelectedPath; } } private void CreateTracklist() { SFD.Title = "Neue Tracklist speichern"; SFD.Filter = "Excel-Dateien (*.xls, *.xlsx)|*.xlsx;*.xls|Alle Dateien (*.*)|*.*"; SFD.InitialDirectory = txtList.Text; if (SFD.ShowDialog() == DialogResult.OK) { // Dateien auslesen var mp3list = new List(); foreach (string datei in Directory.GetFiles(txtList.Text, "*.mp3", SearchOption.TopDirectoryOnly)) mp3list.Add(Mp3File.FromFile(datei)); DataTable dtTracklist = new DataTable(); dtTracklist.Columns.Add("Title"); dtTracklist.Columns.Add("TitleNo"); dtTracklist.Columns.Add("Interpret"); dtTracklist.Columns.Add("Filename"); DataRow dr; foreach (Mp3File mp3 in mp3list) { dr = dtTracklist.NewRow(); dr["TitleNo"] = mp3.Track; dr["Title"] = mp3.Title; dr["Interpret"] = mp3.Artist; dr["Filename"] = mp3.Filename; dtTracklist.Rows.Add(dr); } XLSX.Serialize(SFD.FileName, dtTracklist); MessageBox.Show("Vorgang abgeschlossen"); } } private void lstCPPlaylists_DoubleClick(object sender, EventArgs e) { if (lstCPPlaylists.SelectedItem is not null) { OpenFile((string)lstCPPlaylists.SelectedItem); } } private void DateiHinzufügenToolStripMenuItem_Click(object sender, EventArgs e) { if (OFD.ShowDialog() == DialogResult.OK) { lstCPPlaylists.Items.Add(OFD.FileName); readPlaylistpaths(); } } private void AusListeEntfernenToolStripMenuItem_Click(object sender, EventArgs e) { if (lstCPPlaylists.SelectedItems.Count > 0) { foreach (string itm in lstCPPlaylists.SelectedItems) lstCPPlaylists.Items.Remove(itm); readPlaylistpaths(); } } private void DateiÖffnenToolStripMenuItem_Click(object sender, EventArgs e) { if (lstCPPlaylists.SelectedItem is not null) { OpenFile((string)lstCPPlaylists.SelectedItem); } } #endregion } }