659 lines
23 KiB
C#
659 lines
23 KiB
C#
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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generiert einen Ordnernamen der dem Namen der Playlist entspricht, als Zielordner-Vorschlag
|
|
/// </summary>
|
|
/// <param name="playlistfile"></param>
|
|
/// <returns></returns>
|
|
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<string>();
|
|
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<string>();
|
|
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<Mp3File>();
|
|
|
|
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
|
|
|
|
|
|
}
|
|
}
|