From 65b22ceee835c03335583fb2face4b40e81c3d13 Mon Sep 17 00:00:00 2001
From: AiiR <22158489+ImAiiR@users.noreply.github.com>
Date: Fri, 1 Nov 2019 21:47:20 -0400
Subject: [PATCH] Add files via upload
---
QobuzDownloaderX.sln | 22 +
QobuzDownloaderX/App.config | 105 +
QobuzDownloaderX/Form1.Designer.cs | 766 ++++
QobuzDownloaderX/Form1.cs | 3539 +++++++++++++++++
QobuzDownloaderX/Form1.resx | 1070 +++++
QobuzDownloaderX/LoginForm.Designer.cs | 207 +
QobuzDownloaderX/LoginForm.cs | 277 ++
QobuzDownloaderX/LoginForm.resx | 1058 +++++
QobuzDownloaderX/Program.cs | 22 +
QobuzDownloaderX/Properties/AssemblyInfo.cs | 36 +
.../Properties/Resources.Designer.cs | 83 +
QobuzDownloaderX/Properties/Resources.resx | 127 +
.../Properties/Settings.Designer.cs | 386 ++
QobuzDownloaderX/Properties/Settings.settings | 96 +
QobuzDownloaderX/QobuzDownloaderX.csproj | 159 +
QobuzDownloaderX/QobuzDownloaderX.csproj.user | 13 +
QobuzDownloaderX/Resources/Untitled-1.png | Bin 0 -> 893138 bytes
QobuzDownloaderX/Resources/qbdlx.png | Bin 0 -> 26932 bytes
QobuzDownloaderX/Resources/qbdlx_icon.ico | Bin 0 -> 55614 bytes
QobuzDownloaderX/Settings.cs | 28 +
.../DesignTimeResolveAssemblyReferences.cache | Bin 0 -> 2659 bytes
...gnTimeResolveAssemblyReferencesInput.cache | Bin 0 -> 7859 bytes
.../QobuzDownloaderX.LoginForm.resources | Bin 0 -> 56180 bytes
...DownloaderX.Properties.Resources.resources | Bin 0 -> 84185 bytes
...obuzDownloaderX.QobuzDownloaderX.resources | Bin 0 -> 56180 bytes
...buzDownloaderX.csproj.FileListAbsolute.txt | 14 +
...zDownloaderX.csproj.GenerateResource.Cache | Bin 0 -> 1220 bytes
...aderX.csprojResolveAssemblyReference.cache | Bin 0 -> 22777 bytes
.../obj/Debug/QobuzDownloaderX.exe | Bin 0 -> 434176 bytes
.../obj/Debug/QobuzDownloaderX.pdb | Bin 0 -> 185856 bytes
.../QobuzDownloaderX.searchForm.resources | Bin 0 -> 56180 bytes
.../Properties.Resources.Designer.cs.dll | Bin 0 -> 9216 bytes
...gnTimeResolveAssemblyReferencesInput.cache | Bin 0 -> 7863 bytes
.../QobuzDownloaderX.LoginForm.resources | Bin 0 -> 56180 bytes
...DownloaderX.Properties.Resources.resources | Bin 0 -> 84185 bytes
...obuzDownloaderX.QobuzDownloaderX.resources | Bin 0 -> 56180 bytes
...buzDownloaderX.csproj.FileListAbsolute.txt | 14 +
...zDownloaderX.csproj.GenerateResource.Cache | Bin 0 -> 1220 bytes
...aderX.csprojResolveAssemblyReference.cache | Bin 0 -> 10164 bytes
.../obj/Release/QobuzDownloaderX.exe | Bin 0 -> 416768 bytes
.../obj/Release/QobuzDownloaderX.pdb | Bin 0 -> 169472 bytes
.../QobuzDownloaderX.searchForm.resources | Bin 0 -> 56180 bytes
.../Properties.Resources.Designer.cs.dll | Bin 0 -> 9216 bytes
QobuzDownloaderX/packages.config | 4 +
QobuzDownloaderX/searchForm.Designer.cs | 89 +
QobuzDownloaderX/searchForm.cs | 99 +
QobuzDownloaderX/searchForm.resx | 1052 +++++
.../lib/policy.2.0.taglib-sharp.config | 10 +
.../lib/policy.2.0.taglib-sharp.dll | Bin 0 -> 3072 bytes
packages/taglib.2.1.0.0/lib/taglib-sharp.dll | Bin 0 -> 443392 bytes
packages/taglib.2.1.0.0/taglib.2.1.0.0.nupkg | Bin 0 -> 231765 bytes
51 files changed, 9276 insertions(+)
create mode 100644 QobuzDownloaderX.sln
create mode 100644 QobuzDownloaderX/App.config
create mode 100644 QobuzDownloaderX/Form1.Designer.cs
create mode 100644 QobuzDownloaderX/Form1.cs
create mode 100644 QobuzDownloaderX/Form1.resx
create mode 100644 QobuzDownloaderX/LoginForm.Designer.cs
create mode 100644 QobuzDownloaderX/LoginForm.cs
create mode 100644 QobuzDownloaderX/LoginForm.resx
create mode 100644 QobuzDownloaderX/Program.cs
create mode 100644 QobuzDownloaderX/Properties/AssemblyInfo.cs
create mode 100644 QobuzDownloaderX/Properties/Resources.Designer.cs
create mode 100644 QobuzDownloaderX/Properties/Resources.resx
create mode 100644 QobuzDownloaderX/Properties/Settings.Designer.cs
create mode 100644 QobuzDownloaderX/Properties/Settings.settings
create mode 100644 QobuzDownloaderX/QobuzDownloaderX.csproj
create mode 100644 QobuzDownloaderX/QobuzDownloaderX.csproj.user
create mode 100644 QobuzDownloaderX/Resources/Untitled-1.png
create mode 100644 QobuzDownloaderX/Resources/qbdlx.png
create mode 100644 QobuzDownloaderX/Resources/qbdlx_icon.ico
create mode 100644 QobuzDownloaderX/Settings.cs
create mode 100644 QobuzDownloaderX/obj/Debug/DesignTimeResolveAssemblyReferences.cache
create mode 100644 QobuzDownloaderX/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache
create mode 100644 QobuzDownloaderX/obj/Debug/QobuzDownloaderX.LoginForm.resources
create mode 100644 QobuzDownloaderX/obj/Debug/QobuzDownloaderX.Properties.Resources.resources
create mode 100644 QobuzDownloaderX/obj/Debug/QobuzDownloaderX.QobuzDownloaderX.resources
create mode 100644 QobuzDownloaderX/obj/Debug/QobuzDownloaderX.csproj.FileListAbsolute.txt
create mode 100644 QobuzDownloaderX/obj/Debug/QobuzDownloaderX.csproj.GenerateResource.Cache
create mode 100644 QobuzDownloaderX/obj/Debug/QobuzDownloaderX.csprojResolveAssemblyReference.cache
create mode 100644 QobuzDownloaderX/obj/Debug/QobuzDownloaderX.exe
create mode 100644 QobuzDownloaderX/obj/Debug/QobuzDownloaderX.pdb
create mode 100644 QobuzDownloaderX/obj/Debug/QobuzDownloaderX.searchForm.resources
create mode 100644 QobuzDownloaderX/obj/Debug/TempPE/Properties.Resources.Designer.cs.dll
create mode 100644 QobuzDownloaderX/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache
create mode 100644 QobuzDownloaderX/obj/Release/QobuzDownloaderX.LoginForm.resources
create mode 100644 QobuzDownloaderX/obj/Release/QobuzDownloaderX.Properties.Resources.resources
create mode 100644 QobuzDownloaderX/obj/Release/QobuzDownloaderX.QobuzDownloaderX.resources
create mode 100644 QobuzDownloaderX/obj/Release/QobuzDownloaderX.csproj.FileListAbsolute.txt
create mode 100644 QobuzDownloaderX/obj/Release/QobuzDownloaderX.csproj.GenerateResource.Cache
create mode 100644 QobuzDownloaderX/obj/Release/QobuzDownloaderX.csprojResolveAssemblyReference.cache
create mode 100644 QobuzDownloaderX/obj/Release/QobuzDownloaderX.exe
create mode 100644 QobuzDownloaderX/obj/Release/QobuzDownloaderX.pdb
create mode 100644 QobuzDownloaderX/obj/Release/QobuzDownloaderX.searchForm.resources
create mode 100644 QobuzDownloaderX/obj/Release/TempPE/Properties.Resources.Designer.cs.dll
create mode 100644 QobuzDownloaderX/packages.config
create mode 100644 QobuzDownloaderX/searchForm.Designer.cs
create mode 100644 QobuzDownloaderX/searchForm.cs
create mode 100644 QobuzDownloaderX/searchForm.resx
create mode 100644 packages/taglib.2.1.0.0/lib/policy.2.0.taglib-sharp.config
create mode 100644 packages/taglib.2.1.0.0/lib/policy.2.0.taglib-sharp.dll
create mode 100644 packages/taglib.2.1.0.0/lib/taglib-sharp.dll
create mode 100644 packages/taglib.2.1.0.0/taglib.2.1.0.0.nupkg
diff --git a/QobuzDownloaderX.sln b/QobuzDownloaderX.sln
new file mode 100644
index 0000000..b807d9c
--- /dev/null
+++ b/QobuzDownloaderX.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QobuzDownloaderX", "QobuzDownloaderX\QobuzDownloaderX.csproj", "{4CEB979A-035A-4D36-9607-D554BBECABE0}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {4CEB979A-035A-4D36-9607-D554BBECABE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4CEB979A-035A-4D36-9607-D554BBECABE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4CEB979A-035A-4D36-9607-D554BBECABE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4CEB979A-035A-4D36-9607-D554BBECABE0}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/QobuzDownloaderX/App.config b/QobuzDownloaderX/App.config
new file mode 100644
index 0000000..d866ebf
--- /dev/null
+++ b/QobuzDownloaderX/App.config
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ False
+
+
+ True
+
+
+ True
+
+
+
+
+
+ False
+
+
+ False
+
+
+ False
+
+
+ True
+
+
+ 27
+
+
+ .flac
+
+
+
+
diff --git a/QobuzDownloaderX/Form1.Designer.cs b/QobuzDownloaderX/Form1.Designer.cs
new file mode 100644
index 0000000..c0ef47b
--- /dev/null
+++ b/QobuzDownloaderX/Form1.Designer.cs
@@ -0,0 +1,766 @@
+namespace QobuzDownloaderX
+{
+ partial class QobuzDownloaderX
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(QobuzDownloaderX));
+ this.testURLBox = new System.Windows.Forms.TextBox();
+ this.selectFolder = new System.Windows.Forms.Button();
+ this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
+ this.output = new System.Windows.Forms.TextBox();
+ this.downloadBG = new System.ComponentModel.BackgroundWorker();
+ this.openFolderButton = new System.Windows.Forms.Button();
+ this.downloadButton = new System.Windows.Forms.Button();
+ this.albumUrl = new System.Windows.Forms.TextBox();
+ this.imageURLTextbox = new System.Windows.Forms.TextBox();
+ this.verNumLabel = new System.Windows.Forms.Label();
+ this.label1 = new System.Windows.Forms.Label();
+ this.label2 = new System.Windows.Forms.Label();
+ this.albumArtistTextBox = new System.Windows.Forms.TextBox();
+ this.albumTextBox = new System.Windows.Forms.TextBox();
+ this.label3 = new System.Windows.Forms.Label();
+ this.releaseDateTextBox = new System.Windows.Forms.TextBox();
+ this.label4 = new System.Windows.Forms.Label();
+ this.upcTextBox = new System.Windows.Forms.TextBox();
+ this.label5 = new System.Windows.Forms.Label();
+ this.albumArtPicBox = new System.Windows.Forms.PictureBox();
+ this.pictureBox1 = new System.Windows.Forms.PictureBox();
+ this.label6 = new System.Windows.Forms.Label();
+ this.totalTracksTextbox = new System.Windows.Forms.TextBox();
+ this.totalTracksLabel = new System.Windows.Forms.Label();
+ this.getLinkTypeBG = new System.ComponentModel.BackgroundWorker();
+ this.downloadAlbumBG = new System.ComponentModel.BackgroundWorker();
+ this.downloadTrackBG = new System.ComponentModel.BackgroundWorker();
+ this.downloadDiscogBG = new System.ComponentModel.BackgroundWorker();
+ this.qualityTextbox = new System.Windows.Forms.TextBox();
+ this.qualityLabel = new System.Windows.Forms.Label();
+ this.openSearch = new System.Windows.Forms.Button();
+ this.tagsLabel = new System.Windows.Forms.Label();
+ this.albumArtistCheckbox = new System.Windows.Forms.CheckBox();
+ this.artistCheckbox = new System.Windows.Forms.CheckBox();
+ this.trackTitleCheckbox = new System.Windows.Forms.CheckBox();
+ this.trackNumberCheckbox = new System.Windows.Forms.CheckBox();
+ this.trackTotalCheckbox = new System.Windows.Forms.CheckBox();
+ this.discNumberCheckbox = new System.Windows.Forms.CheckBox();
+ this.discTotalCheckbox = new System.Windows.Forms.CheckBox();
+ this.albumCheckbox = new System.Windows.Forms.CheckBox();
+ this.explicitCheckbox = new System.Windows.Forms.CheckBox();
+ this.upcCheckbox = new System.Windows.Forms.CheckBox();
+ this.isrcCheckbox = new System.Windows.Forms.CheckBox();
+ this.copyrightCheckbox = new System.Windows.Forms.CheckBox();
+ this.composerCheckbox = new System.Windows.Forms.CheckBox();
+ this.genreCheckbox = new System.Windows.Forms.CheckBox();
+ this.releaseCheckbox = new System.Windows.Forms.CheckBox();
+ this.commentCheckbox = new System.Windows.Forms.CheckBox();
+ this.commentTextbox = new System.Windows.Forms.TextBox();
+ this.imageCheckbox = new System.Windows.Forms.CheckBox();
+ this.mp3Checkbox = new System.Windows.Forms.CheckBox();
+ this.flacLowCheckbox = new System.Windows.Forms.CheckBox();
+ this.flacMidCheckbox = new System.Windows.Forms.CheckBox();
+ this.flacHighCheckbox = new System.Windows.Forms.CheckBox();
+ this.mp3WarnLabel = new System.Windows.Forms.Label();
+ ((System.ComponentModel.ISupportInitialize)(this.albumArtPicBox)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
+ this.SuspendLayout();
+ //
+ // testURLBox
+ //
+ this.testURLBox.Location = new System.Drawing.Point(946, 394);
+ this.testURLBox.Multiline = true;
+ this.testURLBox.Name = "testURLBox";
+ this.testURLBox.Size = new System.Drawing.Size(390, 20);
+ this.testURLBox.TabIndex = 1;
+ this.testURLBox.Text = "Steamed Qobuz File URL";
+ this.testURLBox.Visible = false;
+ this.testURLBox.WordWrap = false;
+ //
+ // selectFolder
+ //
+ this.selectFolder.Location = new System.Drawing.Point(13, 115);
+ this.selectFolder.Name = "selectFolder";
+ this.selectFolder.Size = new System.Drawing.Size(349, 23);
+ this.selectFolder.TabIndex = 2;
+ this.selectFolder.Text = "Choose Folder";
+ this.selectFolder.UseVisualStyleBackColor = true;
+ this.selectFolder.Click += new System.EventHandler(this.selectFolder_Click);
+ //
+ // output
+ //
+ this.output.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(33)))), ((int)(((byte)(33)))), ((int)(((byte)(33)))));
+ this.output.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.output.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(128)))), ((int)(((byte)(128)))));
+ this.output.Location = new System.Drawing.Point(12, 144);
+ this.output.Multiline = true;
+ this.output.Name = "output";
+ this.output.ReadOnly = true;
+ this.output.RightToLeft = System.Windows.Forms.RightToLeft.No;
+ this.output.Size = new System.Drawing.Size(705, 339);
+ this.output.TabIndex = 3;
+ this.output.Text = "Test String";
+ //
+ // openFolderButton
+ //
+ this.openFolderButton.Location = new System.Drawing.Point(368, 115);
+ this.openFolderButton.Name = "openFolderButton";
+ this.openFolderButton.Size = new System.Drawing.Size(349, 23);
+ this.openFolderButton.TabIndex = 13;
+ this.openFolderButton.Text = "Open Folder";
+ this.openFolderButton.UseVisualStyleBackColor = true;
+ this.openFolderButton.Click += new System.EventHandler(this.openFolderButton_Click);
+ //
+ // downloadButton
+ //
+ this.downloadButton.Location = new System.Drawing.Point(597, 86);
+ this.downloadButton.Name = "downloadButton";
+ this.downloadButton.Size = new System.Drawing.Size(120, 23);
+ this.downloadButton.TabIndex = 17;
+ this.downloadButton.Text = "Download";
+ this.downloadButton.UseVisualStyleBackColor = true;
+ this.downloadButton.Click += new System.EventHandler(this.downloadButton_Click);
+ //
+ // albumUrl
+ //
+ this.albumUrl.Location = new System.Drawing.Point(15, 88);
+ this.albumUrl.Name = "albumUrl";
+ this.albumUrl.Size = new System.Drawing.Size(579, 20);
+ this.albumUrl.TabIndex = 16;
+ this.albumUrl.WordWrap = false;
+ this.albumUrl.KeyDown += new System.Windows.Forms.KeyEventHandler(this.albumUrl_KeyDown);
+ //
+ // imageURLTextbox
+ //
+ this.imageURLTextbox.Location = new System.Drawing.Point(946, 420);
+ this.imageURLTextbox.Multiline = true;
+ this.imageURLTextbox.Name = "imageURLTextbox";
+ this.imageURLTextbox.Size = new System.Drawing.Size(390, 20);
+ this.imageURLTextbox.TabIndex = 31;
+ this.imageURLTextbox.Text = "Release Cover Art URL";
+ this.imageURLTextbox.Visible = false;
+ this.imageURLTextbox.WordWrap = false;
+ //
+ // verNumLabel
+ //
+ this.verNumLabel.Location = new System.Drawing.Point(159, 55);
+ this.verNumLabel.Name = "verNumLabel";
+ this.verNumLabel.Size = new System.Drawing.Size(63, 13);
+ this.verNumLabel.TabIndex = 38;
+ this.verNumLabel.Text = "#.#.#.#";
+ this.verNumLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(801, 213);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(51, 13);
+ this.label1.TabIndex = 40;
+ this.label1.Text = "Cover Art";
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(751, 236);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(62, 13);
+ this.label2.TabIndex = 41;
+ this.label2.Text = "Album Artist";
+ //
+ // albumArtistTextBox
+ //
+ this.albumArtistTextBox.Location = new System.Drawing.Point(754, 252);
+ this.albumArtistTextBox.Name = "albumArtistTextBox";
+ this.albumArtistTextBox.ReadOnly = true;
+ this.albumArtistTextBox.Size = new System.Drawing.Size(150, 20);
+ this.albumArtistTextBox.TabIndex = 42;
+ this.albumArtistTextBox.WordWrap = false;
+ //
+ // albumTextBox
+ //
+ this.albumTextBox.Location = new System.Drawing.Point(754, 294);
+ this.albumTextBox.Name = "albumTextBox";
+ this.albumTextBox.ReadOnly = true;
+ this.albumTextBox.Size = new System.Drawing.Size(150, 20);
+ this.albumTextBox.TabIndex = 44;
+ this.albumTextBox.WordWrap = false;
+ //
+ // label3
+ //
+ this.label3.AutoSize = true;
+ this.label3.Location = new System.Drawing.Point(751, 278);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(36, 13);
+ this.label3.TabIndex = 43;
+ this.label3.Text = "Album";
+ //
+ // releaseDateTextBox
+ //
+ this.releaseDateTextBox.Location = new System.Drawing.Point(754, 463);
+ this.releaseDateTextBox.Name = "releaseDateTextBox";
+ this.releaseDateTextBox.ReadOnly = true;
+ this.releaseDateTextBox.Size = new System.Drawing.Size(150, 20);
+ this.releaseDateTextBox.TabIndex = 46;
+ this.releaseDateTextBox.WordWrap = false;
+ //
+ // label4
+ //
+ this.label4.AutoSize = true;
+ this.label4.Location = new System.Drawing.Point(751, 447);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(72, 13);
+ this.label4.TabIndex = 45;
+ this.label4.Text = "Release Date";
+ //
+ // upcTextBox
+ //
+ this.upcTextBox.Location = new System.Drawing.Point(754, 420);
+ this.upcTextBox.Name = "upcTextBox";
+ this.upcTextBox.ReadOnly = true;
+ this.upcTextBox.Size = new System.Drawing.Size(150, 20);
+ this.upcTextBox.TabIndex = 48;
+ this.upcTextBox.WordWrap = false;
+ //
+ // label5
+ //
+ this.label5.AutoSize = true;
+ this.label5.Location = new System.Drawing.Point(751, 404);
+ this.label5.Name = "label5";
+ this.label5.Size = new System.Drawing.Size(29, 13);
+ this.label5.TabIndex = 47;
+ this.label5.Text = "UPC";
+ //
+ // albumArtPicBox
+ //
+ this.albumArtPicBox.Location = new System.Drawing.Point(754, 57);
+ this.albumArtPicBox.MaximumSize = new System.Drawing.Size(150, 150);
+ this.albumArtPicBox.MinimumSize = new System.Drawing.Size(150, 150);
+ this.albumArtPicBox.Name = "albumArtPicBox";
+ this.albumArtPicBox.Size = new System.Drawing.Size(150, 150);
+ this.albumArtPicBox.TabIndex = 39;
+ this.albumArtPicBox.TabStop = false;
+ //
+ // pictureBox1
+ //
+ this.pictureBox1.Image = global::QobuzDownloaderX.Properties.Resources.qbdlx;
+ this.pictureBox1.Location = new System.Drawing.Point(12, 12);
+ this.pictureBox1.Name = "pictureBox1";
+ this.pictureBox1.Size = new System.Drawing.Size(207, 52);
+ this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
+ this.pictureBox1.TabIndex = 36;
+ this.pictureBox1.TabStop = false;
+ //
+ // label6
+ //
+ this.label6.AutoSize = true;
+ this.label6.Location = new System.Drawing.Point(12, 70);
+ this.label6.Name = "label6";
+ this.label6.Size = new System.Drawing.Size(132, 13);
+ this.label6.TabIndex = 49;
+ this.label6.Text = "Qobuz Album / Track Link";
+ //
+ // totalTracksTextbox
+ //
+ this.totalTracksTextbox.Location = new System.Drawing.Point(754, 378);
+ this.totalTracksTextbox.Name = "totalTracksTextbox";
+ this.totalTracksTextbox.ReadOnly = true;
+ this.totalTracksTextbox.Size = new System.Drawing.Size(150, 20);
+ this.totalTracksTextbox.TabIndex = 56;
+ this.totalTracksTextbox.WordWrap = false;
+ //
+ // totalTracksLabel
+ //
+ this.totalTracksLabel.AutoSize = true;
+ this.totalTracksLabel.Location = new System.Drawing.Point(751, 362);
+ this.totalTracksLabel.Name = "totalTracksLabel";
+ this.totalTracksLabel.Size = new System.Drawing.Size(67, 13);
+ this.totalTracksLabel.TabIndex = 55;
+ this.totalTracksLabel.Text = "Total Tracks";
+ //
+ // getLinkTypeBG
+ //
+ this.getLinkTypeBG.DoWork += new System.ComponentModel.DoWorkEventHandler(this.getLinkTypeBG_DoWork);
+ //
+ // downloadAlbumBG
+ //
+ this.downloadAlbumBG.DoWork += new System.ComponentModel.DoWorkEventHandler(this.downloadAlbumBG_DoWork);
+ //
+ // downloadTrackBG
+ //
+ this.downloadTrackBG.DoWork += new System.ComponentModel.DoWorkEventHandler(this.downloadTrackBG_DoWork);
+ //
+ // downloadDiscogBG
+ //
+ this.downloadDiscogBG.DoWork += new System.ComponentModel.DoWorkEventHandler(this.downloadDiscogBG_DoWork);
+ //
+ // qualityTextbox
+ //
+ this.qualityTextbox.Location = new System.Drawing.Point(754, 336);
+ this.qualityTextbox.Name = "qualityTextbox";
+ this.qualityTextbox.ReadOnly = true;
+ this.qualityTextbox.Size = new System.Drawing.Size(150, 20);
+ this.qualityTextbox.TabIndex = 59;
+ this.qualityTextbox.WordWrap = false;
+ //
+ // qualityLabel
+ //
+ this.qualityLabel.AutoSize = true;
+ this.qualityLabel.Location = new System.Drawing.Point(751, 320);
+ this.qualityLabel.Name = "qualityLabel";
+ this.qualityLabel.Size = new System.Drawing.Size(71, 13);
+ this.qualityLabel.TabIndex = 58;
+ this.qualityLabel.Text = "Album Quality";
+ //
+ // openSearch
+ //
+ this.openSearch.Location = new System.Drawing.Point(597, 57);
+ this.openSearch.Name = "openSearch";
+ this.openSearch.Size = new System.Drawing.Size(120, 23);
+ this.openSearch.TabIndex = 60;
+ this.openSearch.Text = "Open Search";
+ this.openSearch.UseVisualStyleBackColor = true;
+ this.openSearch.Click += new System.EventHandler(this.openSearch_Click);
+ //
+ // tagsLabel
+ //
+ this.tagsLabel.Location = new System.Drawing.Point(12, 501);
+ this.tagsLabel.Name = "tagsLabel";
+ this.tagsLabel.Size = new System.Drawing.Size(914, 23);
+ this.tagsLabel.TabIndex = 61;
+ this.tagsLabel.Text = "🠋 Choose which tags to save 🠋";
+ this.tagsLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ this.tagsLabel.Click += new System.EventHandler(this.tagsLabel_Click);
+ //
+ // albumArtistCheckbox
+ //
+ this.albumArtistCheckbox.AutoSize = true;
+ this.albumArtistCheckbox.Checked = true;
+ this.albumArtistCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.albumArtistCheckbox.Location = new System.Drawing.Point(325, 563);
+ this.albumArtistCheckbox.Name = "albumArtistCheckbox";
+ this.albumArtistCheckbox.Size = new System.Drawing.Size(81, 17);
+ this.albumArtistCheckbox.TabIndex = 62;
+ this.albumArtistCheckbox.Text = "Album Artist";
+ this.albumArtistCheckbox.UseVisualStyleBackColor = true;
+ this.albumArtistCheckbox.CheckedChanged += new System.EventHandler(this.albumArtistCheckbox_CheckedChanged);
+ //
+ // artistCheckbox
+ //
+ this.artistCheckbox.AutoSize = true;
+ this.artistCheckbox.Checked = true;
+ this.artistCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.artistCheckbox.Location = new System.Drawing.Point(325, 609);
+ this.artistCheckbox.Name = "artistCheckbox";
+ this.artistCheckbox.Size = new System.Drawing.Size(80, 17);
+ this.artistCheckbox.TabIndex = 63;
+ this.artistCheckbox.Text = "Track Artist";
+ this.artistCheckbox.UseVisualStyleBackColor = true;
+ this.artistCheckbox.CheckedChanged += new System.EventHandler(this.artistCheckbox_CheckedChanged);
+ //
+ // trackTitleCheckbox
+ //
+ this.trackTitleCheckbox.AutoSize = true;
+ this.trackTitleCheckbox.Checked = true;
+ this.trackTitleCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.trackTitleCheckbox.Location = new System.Drawing.Point(325, 586);
+ this.trackTitleCheckbox.Name = "trackTitleCheckbox";
+ this.trackTitleCheckbox.Size = new System.Drawing.Size(77, 17);
+ this.trackTitleCheckbox.TabIndex = 64;
+ this.trackTitleCheckbox.Text = "Track Title";
+ this.trackTitleCheckbox.UseVisualStyleBackColor = true;
+ this.trackTitleCheckbox.CheckedChanged += new System.EventHandler(this.trackTitleCheckbox_CheckedChanged);
+ //
+ // trackNumberCheckbox
+ //
+ this.trackNumberCheckbox.AutoSize = true;
+ this.trackNumberCheckbox.Checked = true;
+ this.trackNumberCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.trackNumberCheckbox.Location = new System.Drawing.Point(325, 632);
+ this.trackNumberCheckbox.Name = "trackNumberCheckbox";
+ this.trackNumberCheckbox.Size = new System.Drawing.Size(94, 17);
+ this.trackNumberCheckbox.TabIndex = 65;
+ this.trackNumberCheckbox.Text = "Track Number";
+ this.trackNumberCheckbox.UseVisualStyleBackColor = true;
+ this.trackNumberCheckbox.CheckedChanged += new System.EventHandler(this.trackNumberCheckbox_CheckedChanged);
+ //
+ // trackTotalCheckbox
+ //
+ this.trackTotalCheckbox.AutoSize = true;
+ this.trackTotalCheckbox.Checked = true;
+ this.trackTotalCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.trackTotalCheckbox.Location = new System.Drawing.Point(325, 655);
+ this.trackTotalCheckbox.Name = "trackTotalCheckbox";
+ this.trackTotalCheckbox.Size = new System.Drawing.Size(86, 17);
+ this.trackTotalCheckbox.TabIndex = 66;
+ this.trackTotalCheckbox.Text = "Total Tracks";
+ this.trackTotalCheckbox.UseVisualStyleBackColor = true;
+ this.trackTotalCheckbox.CheckedChanged += new System.EventHandler(this.trackTotalCheckbox_CheckedChanged);
+ //
+ // discNumberCheckbox
+ //
+ this.discNumberCheckbox.AutoSize = true;
+ this.discNumberCheckbox.Checked = true;
+ this.discNumberCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.discNumberCheckbox.Location = new System.Drawing.Point(325, 676);
+ this.discNumberCheckbox.Name = "discNumberCheckbox";
+ this.discNumberCheckbox.Size = new System.Drawing.Size(87, 17);
+ this.discNumberCheckbox.TabIndex = 67;
+ this.discNumberCheckbox.Text = "Disc Number";
+ this.discNumberCheckbox.UseVisualStyleBackColor = true;
+ this.discNumberCheckbox.CheckedChanged += new System.EventHandler(this.discNumberCheckbox_CheckedChanged);
+ //
+ // discTotalCheckbox
+ //
+ this.discTotalCheckbox.AutoSize = true;
+ this.discTotalCheckbox.Checked = true;
+ this.discTotalCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.discTotalCheckbox.Location = new System.Drawing.Point(325, 699);
+ this.discTotalCheckbox.Name = "discTotalCheckbox";
+ this.discTotalCheckbox.Size = new System.Drawing.Size(79, 17);
+ this.discTotalCheckbox.TabIndex = 68;
+ this.discTotalCheckbox.Text = "Total Discs";
+ this.discTotalCheckbox.UseVisualStyleBackColor = true;
+ this.discTotalCheckbox.CheckedChanged += new System.EventHandler(this.discTotalCheckbox_CheckedChanged);
+ //
+ // albumCheckbox
+ //
+ this.albumCheckbox.AutoSize = true;
+ this.albumCheckbox.Checked = true;
+ this.albumCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.albumCheckbox.Location = new System.Drawing.Point(325, 540);
+ this.albumCheckbox.Name = "albumCheckbox";
+ this.albumCheckbox.Size = new System.Drawing.Size(78, 17);
+ this.albumCheckbox.TabIndex = 69;
+ this.albumCheckbox.Text = "Album Title";
+ this.albumCheckbox.UseVisualStyleBackColor = true;
+ this.albumCheckbox.CheckedChanged += new System.EventHandler(this.albumCheckbox_CheckedChanged);
+ //
+ // explicitCheckbox
+ //
+ this.explicitCheckbox.AutoSize = true;
+ this.explicitCheckbox.Checked = true;
+ this.explicitCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.explicitCheckbox.Location = new System.Drawing.Point(425, 678);
+ this.explicitCheckbox.Name = "explicitCheckbox";
+ this.explicitCheckbox.Size = new System.Drawing.Size(106, 17);
+ this.explicitCheckbox.TabIndex = 76;
+ this.explicitCheckbox.Text = "Explicit Advisory*";
+ this.explicitCheckbox.UseVisualStyleBackColor = true;
+ this.explicitCheckbox.CheckedChanged += new System.EventHandler(this.explicitCheckbox_CheckedChanged);
+ //
+ // upcCheckbox
+ //
+ this.upcCheckbox.AutoSize = true;
+ this.upcCheckbox.Checked = true;
+ this.upcCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.upcCheckbox.Location = new System.Drawing.Point(425, 655);
+ this.upcCheckbox.Name = "upcCheckbox";
+ this.upcCheckbox.Size = new System.Drawing.Size(52, 17);
+ this.upcCheckbox.TabIndex = 75;
+ this.upcCheckbox.Text = "UPC*";
+ this.upcCheckbox.UseVisualStyleBackColor = true;
+ this.upcCheckbox.CheckedChanged += new System.EventHandler(this.upcCheckbox_CheckedChanged);
+ //
+ // isrcCheckbox
+ //
+ this.isrcCheckbox.AutoSize = true;
+ this.isrcCheckbox.Checked = true;
+ this.isrcCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.isrcCheckbox.Location = new System.Drawing.Point(425, 632);
+ this.isrcCheckbox.Name = "isrcCheckbox";
+ this.isrcCheckbox.Size = new System.Drawing.Size(51, 17);
+ this.isrcCheckbox.TabIndex = 74;
+ this.isrcCheckbox.Text = "ISRC";
+ this.isrcCheckbox.UseVisualStyleBackColor = true;
+ this.isrcCheckbox.CheckedChanged += new System.EventHandler(this.isrcCheckbox_CheckedChanged);
+ //
+ // copyrightCheckbox
+ //
+ this.copyrightCheckbox.AutoSize = true;
+ this.copyrightCheckbox.Checked = true;
+ this.copyrightCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.copyrightCheckbox.Location = new System.Drawing.Point(425, 609);
+ this.copyrightCheckbox.Name = "copyrightCheckbox";
+ this.copyrightCheckbox.Size = new System.Drawing.Size(70, 17);
+ this.copyrightCheckbox.TabIndex = 73;
+ this.copyrightCheckbox.Text = "Copyright";
+ this.copyrightCheckbox.UseVisualStyleBackColor = true;
+ this.copyrightCheckbox.CheckedChanged += new System.EventHandler(this.copyrightCheckbox_CheckedChanged);
+ //
+ // composerCheckbox
+ //
+ this.composerCheckbox.AutoSize = true;
+ this.composerCheckbox.Checked = true;
+ this.composerCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.composerCheckbox.Location = new System.Drawing.Point(425, 586);
+ this.composerCheckbox.Name = "composerCheckbox";
+ this.composerCheckbox.Size = new System.Drawing.Size(73, 17);
+ this.composerCheckbox.TabIndex = 72;
+ this.composerCheckbox.Text = "Composer";
+ this.composerCheckbox.UseVisualStyleBackColor = true;
+ this.composerCheckbox.CheckedChanged += new System.EventHandler(this.composerCheckbox_CheckedChanged);
+ //
+ // genreCheckbox
+ //
+ this.genreCheckbox.AutoSize = true;
+ this.genreCheckbox.Checked = true;
+ this.genreCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.genreCheckbox.Location = new System.Drawing.Point(425, 563);
+ this.genreCheckbox.Name = "genreCheckbox";
+ this.genreCheckbox.Size = new System.Drawing.Size(55, 17);
+ this.genreCheckbox.TabIndex = 71;
+ this.genreCheckbox.Text = "Genre";
+ this.genreCheckbox.UseVisualStyleBackColor = true;
+ this.genreCheckbox.CheckedChanged += new System.EventHandler(this.genreCheckbox_CheckedChanged);
+ //
+ // releaseCheckbox
+ //
+ this.releaseCheckbox.AutoSize = true;
+ this.releaseCheckbox.Checked = true;
+ this.releaseCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.releaseCheckbox.Location = new System.Drawing.Point(425, 540);
+ this.releaseCheckbox.Name = "releaseCheckbox";
+ this.releaseCheckbox.Size = new System.Drawing.Size(91, 17);
+ this.releaseCheckbox.TabIndex = 70;
+ this.releaseCheckbox.Text = "Release Date";
+ this.releaseCheckbox.UseVisualStyleBackColor = true;
+ this.releaseCheckbox.CheckedChanged += new System.EventHandler(this.releaseCheckbox_CheckedChanged);
+ //
+ // commentCheckbox
+ //
+ this.commentCheckbox.AutoSize = true;
+ this.commentCheckbox.Location = new System.Drawing.Point(533, 699);
+ this.commentCheckbox.Name = "commentCheckbox";
+ this.commentCheckbox.Size = new System.Drawing.Size(70, 17);
+ this.commentCheckbox.TabIndex = 78;
+ this.commentCheckbox.Text = "Comment";
+ this.commentCheckbox.UseVisualStyleBackColor = true;
+ this.commentCheckbox.CheckedChanged += new System.EventHandler(this.commentCheckbox_CheckedChanged);
+ //
+ // commentTextbox
+ //
+ this.commentTextbox.Location = new System.Drawing.Point(609, 697);
+ this.commentTextbox.Name = "commentTextbox";
+ this.commentTextbox.Size = new System.Drawing.Size(112, 20);
+ this.commentTextbox.TabIndex = 79;
+ this.commentTextbox.TextChanged += new System.EventHandler(this.commentTextbox_TextChanged);
+ //
+ // imageCheckbox
+ //
+ this.imageCheckbox.AutoSize = true;
+ this.imageCheckbox.Checked = true;
+ this.imageCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.imageCheckbox.Location = new System.Drawing.Point(425, 699);
+ this.imageCheckbox.Name = "imageCheckbox";
+ this.imageCheckbox.Size = new System.Drawing.Size(70, 17);
+ this.imageCheckbox.TabIndex = 80;
+ this.imageCheckbox.Text = "Cover Art";
+ this.imageCheckbox.UseVisualStyleBackColor = true;
+ this.imageCheckbox.CheckedChanged += new System.EventHandler(this.imageCheckbox_CheckedChanged);
+ //
+ // mp3Checkbox
+ //
+ this.mp3Checkbox.AutoSize = true;
+ this.mp3Checkbox.Location = new System.Drawing.Point(243, 61);
+ this.mp3Checkbox.Name = "mp3Checkbox";
+ this.mp3Checkbox.Size = new System.Drawing.Size(69, 17);
+ this.mp3Checkbox.TabIndex = 81;
+ this.mp3Checkbox.Text = "MP3 320";
+ this.mp3Checkbox.UseVisualStyleBackColor = true;
+ this.mp3Checkbox.CheckedChanged += new System.EventHandler(this.mp3Checkbox_CheckedChanged);
+ //
+ // flacLowCheckbox
+ //
+ this.flacLowCheckbox.AutoSize = true;
+ this.flacLowCheckbox.Location = new System.Drawing.Point(318, 61);
+ this.flacLowCheckbox.Name = "flacLowCheckbox";
+ this.flacLowCheckbox.Size = new System.Drawing.Size(93, 17);
+ this.flacLowCheckbox.TabIndex = 82;
+ this.flacLowCheckbox.Text = "FLAC 16/44.1";
+ this.flacLowCheckbox.UseVisualStyleBackColor = true;
+ this.flacLowCheckbox.CheckedChanged += new System.EventHandler(this.flacLowCheckbox_CheckedChanged);
+ //
+ // flacMidCheckbox
+ //
+ this.flacMidCheckbox.AutoSize = true;
+ this.flacMidCheckbox.Location = new System.Drawing.Point(417, 61);
+ this.flacMidCheckbox.Name = "flacMidCheckbox";
+ this.flacMidCheckbox.Size = new System.Drawing.Size(84, 17);
+ this.flacMidCheckbox.TabIndex = 83;
+ this.flacMidCheckbox.Text = "FLAC 24/96";
+ this.flacMidCheckbox.UseVisualStyleBackColor = true;
+ this.flacMidCheckbox.CheckedChanged += new System.EventHandler(this.flacMidCheckbox_CheckedChanged);
+ //
+ // flacHighCheckbox
+ //
+ this.flacHighCheckbox.AutoSize = true;
+ this.flacHighCheckbox.Checked = true;
+ this.flacHighCheckbox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.flacHighCheckbox.Location = new System.Drawing.Point(507, 61);
+ this.flacHighCheckbox.Name = "flacHighCheckbox";
+ this.flacHighCheckbox.Size = new System.Drawing.Size(90, 17);
+ this.flacHighCheckbox.TabIndex = 84;
+ this.flacHighCheckbox.Text = "FLAC 24/192";
+ this.flacHighCheckbox.UseVisualStyleBackColor = true;
+ this.flacHighCheckbox.CheckedChanged += new System.EventHandler(this.flacHighCheckbox_CheckedChanged);
+ //
+ // mp3WarnLabel
+ //
+ this.mp3WarnLabel.AutoSize = true;
+ this.mp3WarnLabel.Location = new System.Drawing.Point(744, 711);
+ this.mp3WarnLabel.Name = "mp3WarnLabel";
+ this.mp3WarnLabel.Size = new System.Drawing.Size(182, 13);
+ this.mp3WarnLabel.TabIndex = 85;
+ this.mp3WarnLabel.Text = "* = Not available on MP3 downloads.";
+ //
+ // QobuzDownloaderX
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(938, 533);
+ this.Controls.Add(this.mp3WarnLabel);
+ this.Controls.Add(this.flacHighCheckbox);
+ this.Controls.Add(this.flacMidCheckbox);
+ this.Controls.Add(this.flacLowCheckbox);
+ this.Controls.Add(this.mp3Checkbox);
+ this.Controls.Add(this.imageCheckbox);
+ this.Controls.Add(this.commentTextbox);
+ this.Controls.Add(this.commentCheckbox);
+ this.Controls.Add(this.explicitCheckbox);
+ this.Controls.Add(this.upcCheckbox);
+ this.Controls.Add(this.isrcCheckbox);
+ this.Controls.Add(this.copyrightCheckbox);
+ this.Controls.Add(this.composerCheckbox);
+ this.Controls.Add(this.genreCheckbox);
+ this.Controls.Add(this.releaseCheckbox);
+ this.Controls.Add(this.albumCheckbox);
+ this.Controls.Add(this.discTotalCheckbox);
+ this.Controls.Add(this.discNumberCheckbox);
+ this.Controls.Add(this.trackTotalCheckbox);
+ this.Controls.Add(this.trackNumberCheckbox);
+ this.Controls.Add(this.trackTitleCheckbox);
+ this.Controls.Add(this.artistCheckbox);
+ this.Controls.Add(this.albumArtistCheckbox);
+ this.Controls.Add(this.tagsLabel);
+ this.Controls.Add(this.openSearch);
+ this.Controls.Add(this.qualityTextbox);
+ this.Controls.Add(this.qualityLabel);
+ this.Controls.Add(this.totalTracksTextbox);
+ this.Controls.Add(this.totalTracksLabel);
+ this.Controls.Add(this.label6);
+ this.Controls.Add(this.upcTextBox);
+ this.Controls.Add(this.label5);
+ this.Controls.Add(this.releaseDateTextBox);
+ this.Controls.Add(this.label4);
+ this.Controls.Add(this.albumTextBox);
+ this.Controls.Add(this.label3);
+ this.Controls.Add(this.albumArtistTextBox);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.albumArtPicBox);
+ this.Controls.Add(this.verNumLabel);
+ this.Controls.Add(this.pictureBox1);
+ this.Controls.Add(this.imageURLTextbox);
+ this.Controls.Add(this.downloadButton);
+ this.Controls.Add(this.albumUrl);
+ this.Controls.Add(this.openFolderButton);
+ this.Controls.Add(this.output);
+ this.Controls.Add(this.selectFolder);
+ this.Controls.Add(this.testURLBox);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.MaximizeBox = false;
+ this.Name = "QobuzDownloaderX";
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+ this.Text = "QobuzDownloaderX";
+ this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.QobuzDownloaderX_FormClosed);
+ this.Load += new System.EventHandler(this.Form1_Load);
+ ((System.ComponentModel.ISupportInitialize)(this.albumArtPicBox)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+ private System.Windows.Forms.TextBox testURLBox;
+ private System.Windows.Forms.Button selectFolder;
+ private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog;
+ private System.Windows.Forms.TextBox output;
+ private System.ComponentModel.BackgroundWorker downloadBG;
+ private System.Windows.Forms.Button openFolderButton;
+ private System.Windows.Forms.Button downloadButton;
+ private System.Windows.Forms.TextBox albumUrl;
+ private System.Windows.Forms.TextBox imageURLTextbox;
+ private System.Windows.Forms.PictureBox pictureBox1;
+ private System.Windows.Forms.Label verNumLabel;
+ private System.Windows.Forms.PictureBox albumArtPicBox;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.TextBox albumArtistTextBox;
+ private System.Windows.Forms.TextBox albumTextBox;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.TextBox releaseDateTextBox;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.TextBox upcTextBox;
+ private System.Windows.Forms.Label label5;
+ private System.Windows.Forms.Label label6;
+ private System.Windows.Forms.TextBox totalTracksTextbox;
+ private System.Windows.Forms.Label totalTracksLabel;
+ private System.ComponentModel.BackgroundWorker getLinkTypeBG;
+ private System.ComponentModel.BackgroundWorker downloadAlbumBG;
+ private System.ComponentModel.BackgroundWorker downloadTrackBG;
+ private System.ComponentModel.BackgroundWorker downloadDiscogBG;
+ private System.Windows.Forms.TextBox qualityTextbox;
+ private System.Windows.Forms.Label qualityLabel;
+ private System.Windows.Forms.Button openSearch;
+ private System.Windows.Forms.Label tagsLabel;
+ private System.Windows.Forms.CheckBox albumArtistCheckbox;
+ private System.Windows.Forms.CheckBox artistCheckbox;
+ private System.Windows.Forms.CheckBox trackTitleCheckbox;
+ private System.Windows.Forms.CheckBox trackNumberCheckbox;
+ private System.Windows.Forms.CheckBox trackTotalCheckbox;
+ private System.Windows.Forms.CheckBox discNumberCheckbox;
+ private System.Windows.Forms.CheckBox discTotalCheckbox;
+ private System.Windows.Forms.CheckBox albumCheckbox;
+ private System.Windows.Forms.CheckBox explicitCheckbox;
+ private System.Windows.Forms.CheckBox upcCheckbox;
+ private System.Windows.Forms.CheckBox isrcCheckbox;
+ private System.Windows.Forms.CheckBox copyrightCheckbox;
+ private System.Windows.Forms.CheckBox composerCheckbox;
+ private System.Windows.Forms.CheckBox genreCheckbox;
+ private System.Windows.Forms.CheckBox releaseCheckbox;
+ private System.Windows.Forms.CheckBox commentCheckbox;
+ private System.Windows.Forms.TextBox commentTextbox;
+ private System.Windows.Forms.CheckBox imageCheckbox;
+ private System.Windows.Forms.CheckBox mp3Checkbox;
+ private System.Windows.Forms.CheckBox flacLowCheckbox;
+ private System.Windows.Forms.CheckBox flacMidCheckbox;
+ private System.Windows.Forms.CheckBox flacHighCheckbox;
+ private System.Windows.Forms.Label mp3WarnLabel;
+ }
+}
+
diff --git a/QobuzDownloaderX/Form1.cs b/QobuzDownloaderX/Form1.cs
new file mode 100644
index 0000000..5083ae5
--- /dev/null
+++ b/QobuzDownloaderX/Form1.cs
@@ -0,0 +1,3539 @@
+using QobuzDownloaderX.Properties;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.IO;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Security.Cryptography;
+using System.Reflection;
+using System.Text.RegularExpressions;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Drawing.Imaging;
+using TagLib;
+using TagLib.Flac;
+using TagLib.Id3v2;
+using System.Globalization;
+using System.Threading;
+
+namespace QobuzDownloaderX
+{
+ public partial class QobuzDownloaderX : Form
+ {
+ public QobuzDownloaderX()
+ {
+ InitializeComponent();
+ }
+
+ public string eMail { get; set; }
+ public string appid { get; set; }
+ public string password { get; set; }
+ public string userAuth { get; set; }
+ public string displayName { get; set; }
+ public string accountType { get; set; }
+ public string appSecret { get; set; }
+ public string albumId { get; set; }
+ public string trackIdString { get; set; }
+ public string formatIdString { get; set; }
+ public string audioFileType { get; set; }
+
+ searchForm searchF = new searchForm();
+
+ private void Form1_Load(object sender, EventArgs e)
+ {
+ // Welcome the user after successful login.
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("Welcome " + displayName + "!\r\n")));
+ output.Invoke(new Action(() => output.AppendText("Qobuz Account Type - " + accountType + "\r\n\r\n")));
+ output.Invoke(new Action(() => output.AppendText("Your user_auth_token has been set for this session!")));
+
+ // Get and display version number.
+ verNumLabel.Text = Assembly.GetExecutingAssembly().GetName().Version.ToString();
+
+ // Set app_id & auth_token for the Search Form
+ searchF.appid = appid;
+ searchF.userAuth = userAuth;
+
+ // Set a placeholder image for Cover Art box.
+ albumArtPicBox.ImageLocation = "https://static.qobuz.com/images/covers/01/00/2013072600001_150.jpg";
+
+ #region Load Saved Settings
+ // Set saved settings to correct places.
+ folderBrowserDialog.SelectedPath = Settings.Default.savedFolder.ToString();
+ albumCheckbox.Checked = Settings.Default.albumTag;
+ albumArtistCheckbox.Checked = Settings.Default.albumArtistTag;
+ artistCheckbox.Checked = Settings.Default.artistTag;
+ commentCheckbox.Checked = Settings.Default.commentTag;
+ commentTextbox.Text = Settings.Default.commentText;
+ composerCheckbox.Checked = Settings.Default.composerTag;
+ copyrightCheckbox.Checked = Settings.Default.copyrightTag;
+ discNumberCheckbox.Checked = Settings.Default.discTag;
+ discTotalCheckbox.Checked = Settings.Default.totalDiscsTag;
+ genreCheckbox.Checked = Settings.Default.genreTag;
+ isrcCheckbox.Checked = Settings.Default.isrcTag;
+ explicitCheckbox.Checked = Settings.Default.explicitTag;
+ trackTitleCheckbox.Checked = Settings.Default.trackTitleTag;
+ trackNumberCheckbox.Checked = Settings.Default.trackTag;
+ trackTotalCheckbox.Checked = Settings.Default.totalTracksTag;
+ upcCheckbox.Checked = Settings.Default.upcTag;
+ releaseCheckbox.Checked = Settings.Default.yearTag;
+ imageCheckbox.Checked = Settings.Default.imageTag;
+ mp3Checkbox.Checked = Settings.Default.quality1;
+ flacLowCheckbox.Checked = Settings.Default.quality2;
+ flacMidCheckbox.Checked = Settings.Default.quality3;
+ flacHighCheckbox.Checked = Settings.Default.quality4;
+ formatIdString = Settings.Default.qualityFormat;
+ audioFileType = Settings.Default.audioType;
+ #endregion
+
+ // Check if there's no selected path saved.
+ if (folderBrowserDialog.SelectedPath == null | folderBrowserDialog.SelectedPath == "")
+ {
+ // If there is NOT a saved path.
+ output.Invoke(new Action(() => output.AppendText("\r\n\r\n")));
+ output.Invoke(new Action(() => output.AppendText("No default path has been set! Remember to Choose a Folder!\r\n")));
+ }
+ else
+ {
+ // If there is a saved path.
+ output.Invoke(new Action(() => output.AppendText("\r\n\r\n")));
+ output.Invoke(new Action(() => output.AppendText("Using the last folder you've selected as your selected path!\r\n")));
+ output.Invoke(new Action(() => output.AppendText("\r\n")));
+ output.Invoke(new Action(() => output.AppendText("Default Folder:\r\n")));
+ output.Invoke(new Action(() => output.AppendText(folderBrowserDialog.SelectedPath + "\r\n")));
+ }
+
+ // Run anything put into the debug events (For Testing)
+ debuggingEvents(sender, e);
+ }
+
+ private void debuggingEvents(object sender, EventArgs e)
+ {
+ #region Debug Events, For Testing
+ // Show app_secret value.
+ //output.Invoke(new Action(() => output.AppendText("\r\n\r\napp_secret = " + appSecret)));
+
+ // Show format_id value.
+ //output.Invoke(new Action(() => output.AppendText("\r\n\r\nformat_id = " + formatIdString)));
+ #endregion
+ }
+
+ static string DecodeEncodedNonAsciiCharacters(string value)
+ {
+ return Regex.Replace(
+ value,
+ @"\\u(?[a-zA-Z0-9]{4})",
+ m => {
+ return ((char)int.Parse(m.Groups["Value"].Value, NumberStyles.HexNumber)).ToString();
+ });
+ }
+
+ static string GetMd5Hash(MD5 md5Hash, string input)
+ {
+
+ // Convert the input string to a byte array and compute the hash.
+ byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
+
+ // Create a new Stringbuilder to collect the bytes and create a string.
+ StringBuilder sBuilder = new StringBuilder();
+
+ // Loop through each byte of the hashed data and format each one as a hexadecimal string.
+ for (int i = 0; i < data.Length; i++)
+ {
+ sBuilder.Append(data[i].ToString("x2"));
+ }
+
+ // Return the hexadecimal string.
+ return sBuilder.ToString();
+ }
+
+ // Verify a hash against a string.
+ static bool VerifyMd5Hash(MD5 md5Hash, string input, string hash)
+ {
+ // Hash the input.
+ string hashOfInput = GetMd5Hash(md5Hash, input);
+
+ // Create a StringComparer an compare the hashes.
+ StringComparer comparer = StringComparer.OrdinalIgnoreCase;
+
+ if (0 == comparer.Compare(hashOfInput, hash))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Create a WebClient named "wc" to be used anywhere.
+ WebClient wc = new WebClient();
+
+ private void openSearch_Click(object sender, EventArgs e)
+ {
+ searchF.ShowDialog();
+ }
+
+ private void downloadButton_Click(object sender, EventArgs e)
+ {
+ getLinkTypeBG.RunWorkerAsync();
+ }
+
+ private void albumUrl_KeyDown(object sender, KeyEventArgs e)
+ {
+ if (e.KeyCode == Keys.Enter)
+ {
+ getLinkTypeBG.RunWorkerAsync();
+ e.Handled = true;
+ e.SuppressKeyPress = true;
+ }
+ }
+
+ private void selectFolder_Click(object sender, EventArgs e)
+ {
+ Thread t = new Thread((ThreadStart)(() => {
+ // Open Folder Browser to select path & Save the selection
+ folderBrowserDialog.ShowDialog();
+ Settings.Default.savedFolder = folderBrowserDialog.SelectedPath;
+ Settings.Default.Save();
+ }));
+
+ // Run your code from a thread that joins the STA Thread
+ t.SetApartmentState(ApartmentState.STA);
+ t.Start();
+ t.Join();
+ }
+
+ private void createURL(object sender, EventArgs e)
+ {
+ // Create unix timestamp for "request_ts=" and hashing to make request signature.
+ Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
+ string time = unixTimestamp.ToString();
+
+ // Generate the string that will be hashed using MD5 (utf-8). Example string - "trackgetFileUrlformat_id27intentstreamtrack_id6891469115724574501b4d2f1aca8d4c8ef4z07984c5aa6712" (example shows a fake app_secret)
+ string md5HashMe = "trackgetFileUrlformat_id" + formatIdString + "intentstreamtrack_id" + trackIdString + time + appSecret;
+
+ // Generate the MD5 hash using the string created above.
+ using (MD5 md5Hash = MD5.Create())
+ {
+ string requestSignature = GetMd5Hash(md5Hash, md5HashMe);
+
+ if (VerifyMd5Hash(md5Hash, md5HashMe, requestSignature))
+ {
+ // If the MD5 hash is verified, proceed to get the streaming URL.
+ WebRequest wrGetFile = WebRequest.Create("https://www.qobuz.com/api.json/0.2/track/getFileUrl?request_ts=" + time + "&request_sig=" + requestSignature + "&track_id=" + trackIdString + "&format_id=" + formatIdString + "&intent=stream&app_id=" + appid + "&user_auth_token=" + userAuth);
+
+ try
+ {
+ // Grab response from API when grabbing the streaming URL.
+ WebResponse ws = wrGetFile.GetResponse();
+ StreamReader sr = new StreamReader(ws.GetResponseStream());
+
+ string getFileRequest = sr.ReadToEnd();
+ string text = getFileRequest;
+
+ // Grab stream URL.
+ var streamUrlLog = Regex.Match(getFileRequest, "url\":\"(?[^\"]+)").Groups;
+ var streamUrl = streamUrlLog[1].Value;
+
+ // Remove backslashes from the stream URL to have a proper URL.
+ string pattern = @"(?[^\\]+)";
+ string input = streamUrl;
+ RegexOptions options = RegexOptions.Multiline;
+
+ // Place proper stream URL into the stream URL textbox.
+ testURLBox.Invoke(new Action(() => testURLBox.Text = String.Empty));
+ foreach (Match m in Regex.Matches(input, pattern, options))
+ {
+ testURLBox.Invoke(new Action(() => testURLBox.AppendText(string.Format("{0}", m.Value))));
+ }
+ }
+ catch (Exception ex)
+ {
+ // If connection to API fails, or something is incorrect, show error info.
+ string getError = ex.ToString();
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("Failed to get streaming URL. Error information below.\r\n\r\n")));
+ output.Invoke(new Action(() => output.AppendText(getError)));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+ }
+ else
+ {
+ // If the hash can't be verified.
+ output.Invoke(new Action(() => output.AppendText("The hash can't be verified. Please retry.\r\n")));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+ }
+ }
+
+ private void openFolderButton_Click(object sender, EventArgs e)
+ {
+ // Open selcted folder
+ if (folderBrowserDialog.SelectedPath == null | folderBrowserDialog.SelectedPath == "")
+ {
+ // If there's no selected path.
+ MessageBox.Show("No path selected!", "ERROR",
+ MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+ else
+ {
+ // If selected path doesn't exist, create it. (Will be ignored if it does)
+ System.IO.Directory.CreateDirectory(folderBrowserDialog.SelectedPath);
+ // Open selcted folder
+ Process.Start(@folderBrowserDialog.SelectedPath);
+ }
+ }
+
+ #region Getting Type of URL
+ private void getLinkTypeBG_DoWork(object sender, DoWorkEventArgs e)
+ {
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = false));
+ // Check if there's no selected path.
+ if (folderBrowserDialog.SelectedPath == null | folderBrowserDialog.SelectedPath == "")
+ {
+ // If there is NOT a saved path.
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("No path has been set! Remember to Choose a Folder!\r\n")));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+
+ string albumLink = albumUrl.Text;
+
+ var albumLinkIdGrab = Regex.Match(albumLink, "https:\\/\\/(?:.*?).qobuz.com\\/(?.*?)\\/(?.*?)$").Groups;
+ var linkType = albumLinkIdGrab[1].Value;
+ var albumLinkId = albumLinkIdGrab[2].Value;
+
+ albumId = albumLinkId;
+
+ if (linkType == "album")
+ {
+ downloadAlbumBG.RunWorkerAsync();
+ }
+ else if (linkType == "track")
+ {
+ downloadTrackBG.RunWorkerAsync();
+ }
+ else if (linkType == "artist")
+ {
+ downloadDiscogBG.RunWorkerAsync();
+ }
+ else if (linkType == "playlist")
+ {
+ // Say what isn't available at the moment.
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("Downloading playlists or artists is not available right now. Maybe in the future. Sorry.")));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+ else
+ {
+ // Say what isn't available at the moment.
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("URL not understood. Is there a typo?")));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+ }
+ #endregion
+
+ #region Downloading Based on URL
+ // For downloading "artist" links [MOSTLY WORKING]
+ private async void downloadDiscogBG_DoWork(object sender, DoWorkEventArgs e)
+ {
+ #region If URL has "artist"
+ string loc = folderBrowserDialog.SelectedPath;
+
+ trackIdString = albumId;
+
+ WebRequest artistwr = WebRequest.Create("https://www.qobuz.com/api.json/0.2/artist/get?artist_id=" + albumId + "&extra=albums%2Cfocus&offset=0&limit=500&sort=release_desc&app_id=" + appid + "&user_auth_token=" + userAuth);
+
+ // Empty output, then say Starting Downloads.
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("Grabbing Album IDs...\r\n\r\n")));
+
+ try
+ {
+ WebResponse artistws = artistwr.GetResponse();
+ StreamReader artistsr = new StreamReader(artistws.GetResponseStream());
+
+ string artistRequest = artistsr.ReadToEnd();
+
+ // Grab all Track IDs listed on the API.
+ string artistAlbumIdspattern = "\"url\":\"(?:.*?)\",\"id\":\"(?.*?)\"";
+ string input = artistRequest;
+ RegexOptions options = RegexOptions.Multiline;
+
+ foreach (Match m in Regex.Matches(input, artistAlbumIdspattern, options))
+ {
+ string albumIdDiscog = string.Format("{0}", m.Groups["albumIds"].Value);
+
+ WebRequest wr = WebRequest.Create("https://www.qobuz.com/api.json/0.2/album/get?album_id=" + albumIdDiscog + "&app_id=" + appid + "&user_auth_token=" + userAuth);
+
+ // Empty output, then say Starting Downloads.
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("Starting Downloads...\r\n\r\n")));
+
+ try
+ {
+ // Set "loc" as the selected path.
+ loc = folderBrowserDialog.SelectedPath;
+
+ WebResponse ws = wr.GetResponse();
+ StreamReader sr = new StreamReader(ws.GetResponseStream());
+
+ string albumRequest = sr.ReadToEnd();
+
+ string text = albumRequest;
+
+ var tracksLog = Regex.Match(albumRequest, "tracks_count\":(?\\d+)").Groups;
+ var tracks = tracksLog[1].Value;
+
+ // Album Name tag
+ var discogAlbumLog = Regex.Match(albumRequest, "\"title\":\"(?.*?)\",\\\"").Groups;
+ var discogAlbum = discogAlbumLog[1].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeDiscogAlbum = discogAlbum;
+ string decodedDiscogAlbum = DecodeEncodedNonAsciiCharacters(unicodeDiscogAlbum);
+ discogAlbum = decodedDiscogAlbum;
+
+ output.Invoke(new Action(() => output.AppendText("Downloading Album - " + discogAlbum + " ......\r\n\r\n")));
+
+ #region Cover Art URL
+ // Grab Cover Art URL
+ var frontCoverLog = Regex.Match(albumRequest, "\"image\":{\"thumbnail\":\"(?[A-Za-z0-9:().,\\\\\\/._\\-']+)").Groups;
+ var frontCover = frontCoverLog[1].Value;
+
+ // Remove backslashes from the stream URL to have a proper URL.
+ string imagepattern = @"(?[^\\]+)";
+ string imageinput = frontCover;
+ RegexOptions imageoptions = RegexOptions.Multiline;
+
+ imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = String.Empty));
+
+ foreach (Match mImg in Regex.Matches(imageinput, imagepattern, imageoptions))
+ {
+ imageURLTextbox.Invoke(new Action(() => imageURLTextbox.AppendText(string.Format("{0}", mImg.Value))));
+ }
+
+ string frontCoverImg = imageURLTextbox.Text;
+ string frontCoverImgBox = frontCoverImg.Replace("_50.jpg", "_150.jpg");
+ frontCoverImg = frontCoverImg.Replace("_50.jpg", "_max.jpg");
+
+ albumArtPicBox.Invoke(new Action(() => albumArtPicBox.ImageLocation = frontCoverImgBox));
+
+ imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = Settings.Default.savedEmail));
+ #endregion
+
+ #region "Goodies" URL (Digital Booklets)
+ // Look for "Goodies" (digital booklet)
+ var goodiesLog = Regex.Match(albumRequest, "\"goodies\":\\[{\"id\":(?.*?),\"original_url\":\"(?.*?)\",\\\"").Groups;
+ var goodies = goodiesLog[2].Value;
+
+ // Remove backslashes from the stream URL to have a proper URL.
+ string bookpattern = @"(?[^\\]+)";
+ string bookinput = goodies;
+ RegexOptions bookoptions = RegexOptions.Multiline;
+
+ imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = String.Empty));
+
+ foreach (Match mBook in Regex.Matches(bookinput, bookpattern, bookoptions))
+ {
+ imageURLTextbox.Invoke(new Action(() => imageURLTextbox.AppendText(string.Format("{0}", mBook.Value))));
+ }
+
+ string goodiesPDF = imageURLTextbox.Text;
+
+ imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = Settings.Default.savedEmail));
+ #endregion
+
+ // Grab sample rate and bit depth for album.
+ var qualityLog = Regex.Match(albumRequest, "\"maximum_sampling_rate\":(?.*?),(?:.*?)\"maximum_bit_depth\":(?.*?),\"duration\"").Groups;
+ var sampleRate = qualityLog[1].Value;
+ var bitDepth = qualityLog[2].Value;
+ var quality = "FLAC (" + bitDepth + "bit/" + sampleRate + "kHz)";
+ var qualityPath = quality.Replace(@"\", "-").Replace(@"/", "-");
+
+ if (formatIdString == "5")
+ {
+ quality = "MP3 320kbps CBR";
+ qualityPath = "MP3";
+ }
+ else if (formatIdString == "6")
+ {
+ quality = "FLAC (16bit/44.1kHz)";
+ qualityPath = "FLAC (16bit-44.1kHz)";
+ }
+ else if (formatIdString == "7")
+ {
+ if (quality == "FLAC (24bit/192kHz)")
+ {
+ quality = "FLAC (24bit/96kHz)";
+ qualityPath = "FLAC (24bit-96kHz)";
+ }
+ }
+
+ // Grab all Track IDs listed on the API.
+ string trackIdspattern = "\"version\":(?:.*?),\"id\":(?.*?),";
+ string trackinput = text;
+ RegexOptions trackoptions = RegexOptions.Multiline;
+
+
+ foreach (Match mtrack in Regex.Matches(trackinput, trackIdspattern, trackoptions))
+ {
+ // Set default value for max length.
+ const int MaxLength = 200;
+
+ //output.Invoke(new Action(() => output.AppendText(string.Format("{0}\r\n", m.Groups["trackId"].Value))));
+ trackIdString = string.Format("{0}", mtrack.Groups["trackId"].Value);
+
+ WebRequest trackwr = WebRequest.Create("https://www.qobuz.com/api.json/0.2/track/get?track_id=" + trackIdString + "&app_id=" + appid + "&user_auth_token=" + userAuth);
+
+ WebResponse trackws = trackwr.GetResponse();
+ StreamReader tracksr = new StreamReader(trackws.GetResponseStream());
+
+ string trackRequest = tracksr.ReadToEnd();
+
+ #region Availability Check (Valid Link?)
+ // Check if available at all.
+ var errorCheckLog = Regex.Match(trackRequest, "\"code\":404,\"message\":\"(?.*?)\\\"").Groups;
+ var errorCheck = errorCheckLog[1].Value;
+
+ if (errorCheck == "No result matching given argument")
+ {
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("ERROR: 404\r\n")));
+ output.Invoke(new Action(() => output.AppendText("Error message is \"No result matching given argument\"\r\n")));
+ output.Invoke(new Action(() => output.AppendText("This could mean either the link is invalid, or isn't available in the region you're downloading from (even if the account is in the correct region). If the latter is true, use a VPN for the region it's available in to download.")));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+ #endregion
+
+ // Display album quality in quality textbox.
+ qualityTextbox.Invoke(new Action(() => qualityTextbox.Text = quality));
+
+ #region Get Information (Tags, Titles, etc.)
+ // Track Number tag
+ var trackNumberLog = Regex.Match(trackRequest, "\"track_number\":(?[0-9]+)").Groups;
+ var trackNumber = trackNumberLog[1].Value;
+
+ // Disc Number tag
+ var discNumberLog = Regex.Match(trackRequest, "\"media_number\":(?.*?),\\\"").Groups;
+ var discNumber = discNumberLog[1].Value;
+
+ // Album Artist tag
+ var albumArtistLog = Regex.Match(trackRequest, "\"artist\":{\"picture\":(?.*?),\"id\"(?.*?),\"albums_count\":(?.*?),\"name\":\"(?.*?)\",\\\"").Groups;
+ var albumArtist = albumArtistLog[4].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeAlbumArtist = albumArtist;
+ string decodedAlbumArtist = DecodeEncodedNonAsciiCharacters(unicodeAlbumArtist);
+ albumArtist = decodedAlbumArtist;
+
+ albumArtist = albumArtist.Replace(@"\\", @"\").Replace(@"\/", @"/");
+ var albumArtistPath = albumArtist.Replace(@"\", "-").Replace(@"/", "-").Replace("\"", "''").Replace(":", ";").Replace("<", "[").Replace(">", "]").Replace("|", "-").Replace("?", "_").Replace("*", "-");
+
+ // Display album artist in text box under cover art.
+ albumArtistTextBox.Invoke(new Action(() => albumArtistTextBox.Text = albumArtist));
+
+ // If name goes over 200 characters, limit it to 200
+ if (albumArtistPath.Length > MaxLength)
+ {
+ albumArtistPath = albumArtistPath.Substring(0, MaxLength);
+ }
+
+ // Track Artist tag
+ var performerNameLog = Regex.Match(trackRequest, "\"performer\":{\"id\":(?.*?),\"name\":\"(?.*?)\"},\\\"").Groups;
+ var performerName = performerNameLog[2].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodePerformerName = performerName;
+ string decodedPerformerName = DecodeEncodedNonAsciiCharacters(unicodePerformerName);
+ performerName = decodedPerformerName;
+
+ performerName = performerName.Replace(@"\\", @"\").Replace(@"\/", @"/");
+ var performerNamePath = performerName.Replace(@"\", "-").Replace(@"/", "-").Replace("\"", "''").Replace(":", ";").Replace("<", "[").Replace(">", "]").Replace("|", "-").Replace("?", "_").Replace("*", "-");
+
+ // If name goes over 200 characters, limit it to 200
+ if (performerNamePath.Length > MaxLength)
+ {
+ performerNamePath = performerNamePath.Substring(0, MaxLength);
+ }
+
+ // Track Composer tag
+ var composerNameLog = Regex.Match(trackRequest, "\"composer\":{\"id\":(?.*?),\"name\":\"(?.*?)\"},\\\"").Groups;
+ var composerName = composerNameLog[2].Value;
+
+ // Track Explicitness
+ var advisoryLog = Regex.Match(trackRequest, "\"performers\":(?:.*?)\"parental_warning\":(?.*?),").Groups;
+ var advisory = advisoryLog[1].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeComposerName = composerName;
+ string decodedComposerName = DecodeEncodedNonAsciiCharacters(unicodeComposerName);
+ composerName = decodedComposerName;
+
+ composerName = composerName.Replace(@"\\", @"\").Replace(@"\/", @"/");
+
+ // Album Name tag
+ var albumNameLog = Regex.Match(trackRequest, "\"title\":\"(?.*?)\",\\\"").Groups;
+ var albumName = albumNameLog[1].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeAlbumName = albumName;
+ string decodedAlbumName = DecodeEncodedNonAsciiCharacters(unicodeAlbumName);
+ albumName = decodedAlbumName;
+
+ albumName = albumName.Replace(@"\\", @"\").Replace(@"\/", @"/");
+ var albumNamePath = albumName.Replace(@"\", "-").Replace(@"/", "-").Replace("\"", "''").Replace(":", ";").Replace("<", "[").Replace(">", "]").Replace("|", "-").Replace("?", "_").Replace("*", "-");
+
+ // Display album name in text box under cover art.
+ albumTextBox.Invoke(new Action(() => albumTextBox.Text = albumName));
+
+ // If name goes over 200 characters, limit it to 200
+ if (albumNamePath.Length > MaxLength)
+ {
+ albumNamePath = albumNamePath.Substring(0, MaxLength);
+ }
+
+ // Track Name tag
+ var trackNameLog = Regex.Match(trackRequest, "\"version\":(?.*?),\"id\":(?.*?),\"maximum_bit_depth\":(?.*?),\"title\":\"(?.*?)\",\\\"").Groups;
+ var trackName = trackNameLog[4].Value;
+ trackName = trackName.Trim(); // Remove spaces from end of track name
+
+ // For converting unicode characters to ASCII
+ string unicodeTrackName = trackName;
+ string decodedTrackName = DecodeEncodedNonAsciiCharacters(unicodeTrackName);
+ trackName = decodedTrackName;
+
+ trackName = trackName.Replace(@"\\", @"\").Replace(@"\/", @"/");
+ var trackNamePath = trackName.Replace(@"\", "-").Replace(@"/", "-").Replace("\"", "''").Replace(":", ";").Replace("<", "[").Replace(">", "]").Replace("|", "-").Replace("?", "_").Replace("*", "-");
+
+ // If name goes over 200 characters, limit it to 200
+ if (trackNamePath.Length > MaxLength)
+ {
+ trackNamePath = trackNamePath.Substring(0, MaxLength);
+ }
+
+ // Version Name tag
+ var versionNameLog = Regex.Match(trackRequest, "\"version\":\"(?.*?)\",\\\"").Groups;
+ var versionName = versionNameLog[1].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeVersionName = versionName;
+ string decodedVersionName = DecodeEncodedNonAsciiCharacters(unicodeVersionName);
+ versionName = decodedVersionName;
+
+ versionName = versionName.Replace(@"\\", @"\").Replace(@"\/", @"/");
+ var versionNamePath = versionName.Replace(@"\", "-").Replace(@"/", "-").Replace("\"", "''").Replace(":", ";").Replace("<", "[").Replace(">", "]").Replace("|", "-").Replace("?", "_").Replace("*", "-");
+
+ // Genre tag
+ var genreLog = Regex.Match(trackRequest, "\"genre\":{\"id\":(?.*?),\"color\":\"(?.*?)\",\"name\":\"(?.*?)\",\\\"").Groups;
+ var genre = genreLog[3].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeGenre = genre;
+ string decodedGenre = DecodeEncodedNonAsciiCharacters(unicodeGenre);
+ genre = decodedGenre;
+
+ // Release Date tag, grabs the available "stream" date
+ var releaseDateLog = Regex.Match(trackRequest, "\"release_date_stream\":\"(?.*?)\",\\\"").Groups;
+ var releaseDate = releaseDateLog[1].Value;
+
+ // Display release date in text box under cover art.
+ releaseDateTextBox.Invoke(new Action(() => releaseDateTextBox.Text = releaseDate));
+
+ // Copyright tag
+ var copyrightLog = Regex.Match(trackRequest, "\"copyright\":\"(?.*?)\"copyright\":\"(?.*?)\\\"").Groups;
+ var copyright = copyrightLog[2].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeCopyright = copyright;
+ string decodedCopyright = DecodeEncodedNonAsciiCharacters(unicodeCopyright);
+ copyright = decodedCopyright;
+
+ copyright = copyright.Replace(@"\\", @"\").Replace(@"\/", @"/").Replace(@"\u2117", @"℗");
+
+ // UPC tag
+ var upcLog = Regex.Match(trackRequest, "\"upc\":\"(?.*?)\",\\\"").Groups;
+ var upc = upcLog[1].Value;
+
+ // Display UPC in text box under cover art.
+ upcTextBox.Invoke(new Action(() => upcTextBox.Text = upc));
+
+ // ISRC tag
+ var isrcLog = Regex.Match(trackRequest, "\"isrc\":\"(?.*?)\",\\\"").Groups;
+ var isrc = isrcLog[1].Value;
+
+ // Total Tracks tag
+ var trackTotalLog = Regex.Match(trackRequest, "\"tracks_count\":(?[0-9]+)").Groups;
+ var trackTotal = trackTotalLog[1].Value;
+
+ // Display Total Tracks in text box under cover art.
+ totalTracksTextbox.Invoke(new Action(() => totalTracksTextbox.Text = trackTotal));
+
+ // Total Discs tag
+ var discTotalLog = Regex.Match(trackRequest, "\"media_count\":(?[0-9]+)").Groups;
+ var discTotal = discTotalLog[1].Value;
+ #endregion
+
+ #region Filename Number Padding
+ // Set default padding length
+ var paddingLength = 2;
+
+ // Prepare track number padding in filename.
+ string paddingLog = trackTotal.Length.ToString();
+ if (paddingLog == "1")
+ {
+ paddingLength = 2;
+ }
+ else
+ {
+ paddingLength = trackTotal.Length;
+ }
+ #endregion
+
+ #region Create Directories
+ System.IO.Directory.CreateDirectory(loc + "\\" + albumArtistPath);
+ System.IO.Directory.CreateDirectory(loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]");
+ System.IO.Directory.CreateDirectory(loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath);
+
+ string discogPath = loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath;
+ #endregion
+
+ #region Availability Check (Streamable?)
+ // Check if available for streaming.
+ var streamCheckLog = Regex.Match(trackRequest, "\"track_number\":(?.*?)\"streamable\":(?.*?),\"").Groups;
+ var streamCheck = streamCheckLog[2].Value;
+
+ if (streamCheck != "true")
+ {
+ output.Invoke(new Action(() => output.AppendText("Track " + trackNumber + " \"" + trackName + "\" is not available for streaming. Skipping track...\r\n")));
+ System.Threading.Thread.Sleep(800);
+ continue;
+ }
+ #endregion
+
+ #region Check if File Exists
+ // Check if there is a version name.
+ if (versionName == null | versionName == "")
+ {
+ if (System.IO.File.Exists(discogPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + audioFileType))
+ {
+ output.Invoke(new Action(() => output.AppendText("File for \"" + trackNumber.PadLeft(paddingLength, '0') + " " + trackName + "\" already exists. Skipping.\r\n")));
+ System.Threading.Thread.Sleep(800);
+ continue;
+ }
+ }
+ else
+ {
+ if (System.IO.File.Exists(discogPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + " (" + versionNamePath + ")" + audioFileType))
+ {
+ output.Invoke(new Action(() => output.AppendText("File for \"" + trackNumber.PadLeft(paddingLength, '0') + " " + trackName + " (" + versionName + ")" + "\" already exists. Skipping.\r\n")));
+ System.Threading.Thread.Sleep(800);
+ continue;
+ }
+ }
+ #endregion
+
+ // Close web request and create streaming URL.
+ trackwr.Abort();
+ createURL(sender, e);
+
+ try
+ {
+ #region Downloading
+ // Check if there is a version name.
+ if (versionName == null | versionName == "")
+ {
+ output.Invoke(new Action(() => output.AppendText("Downloading - " + trackNumber.PadLeft(paddingLength, '0') + " - " + trackName + " ......")));
+ }
+ else
+ {
+ output.Invoke(new Action(() => output.AppendText("Downloading - " + trackNumber.PadLeft(paddingLength, '0') + " - " + trackName + " (" + versionName + ")" + " ......")));
+ }
+ // Being download process.
+ var client = new HttpClient();
+ // Run through TLS to allow secure connection.
+ ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
+ // Set "range" header to nearly unlimited.
+ client.DefaultRequestHeaders.Range = new RangeHeaderValue(0, 999999999999);
+ // Set user-agent to Firefox.
+ client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0");
+ // Set referer URL to album ID.
+ client.DefaultRequestHeaders.Add("Referer", "https://play.qobuz.com/album/" + albumIdDiscog);
+ // Download the URL in the "Streamed URL" Textbox (Will most likely be replaced).
+ using (var stream = await client.GetStreamAsync(testURLBox.Text))
+
+ // Save single track in selected path.
+ if (versionName == null | versionName == "")
+ {
+ // If there is NOT a version name.
+ using (var output = System.IO.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + audioFileType))
+ {
+ await stream.CopyToAsync(output);
+ }
+ }
+ else
+ {
+ // If there is a version name.
+ using (var output = System.IO.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + " (" + versionNamePath + ")" + audioFileType))
+ {
+ await stream.CopyToAsync(output);
+ }
+ }
+ #endregion
+
+ #region Cover Art Saving
+ if (System.IO.File.Exists(loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg"))
+ {
+ // Skip, don't re-download.
+ }
+ else
+ {
+ if (imageCheckbox.Checked == true)
+ {
+ // Save cover art to selected path (Currently happens every time a track is downloaded).
+ using (WebClient imgClient = new WebClient())
+ {
+ // Download max quality Cover Art to "Cover.jpg" file in chosen path.
+ imgClient.DownloadFile(new Uri(frontCoverImg), loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg");
+ }
+ }
+ }
+ #endregion
+
+ #region Tagging
+ // Check if audio file type is FLAC or MP3
+ if (audioFileType == ".mp3")
+ {
+ #region MP3 Tagging (Needs Work)
+ // Select the downloaded file to prepare for tagging.
+ // Check if there's a version name or not
+ if (versionName == null | versionName == "")
+ {
+ // If there is NOT a version name.
+ var tfile = TagLib.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + audioFileType);
+ // For custom / troublesome tags.
+ TagLib.Id3v2.Tag t = (TagLib.Id3v2.Tag)tfile.GetTag(TagLib.TagTypes.Id3v2);
+
+
+ // Saving cover art to file(s)
+ if (imageCheckbox.Checked == true)
+ {
+ // Define cover art to use for MP3 file(s)
+ TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame();
+ pic.TextEncoding = TagLib.StringType.Latin1;
+ pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg;
+ pic.Type = TagLib.PictureType.FrontCover;
+ pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg");
+
+ // Save cover art to MP3 file.
+ tfile.Tag.Pictures = new TagLib.IPicture[1] { pic };
+ tfile.Save();
+ }
+
+ // Track Title tag
+ if (trackTitleCheckbox.Checked == true)
+ {
+ tfile.Tag.Title = trackName;
+ }
+
+ // Album Title tag
+ if (albumCheckbox.Checked == true)
+ {
+ tfile.Tag.Album = albumName;
+ }
+
+ // Album Artits tag
+ if (albumArtistCheckbox.Checked == true)
+ {
+ tfile.Tag.AlbumArtists = new string[] { albumArtist };
+ }
+
+ // Track Artist tag
+ if (artistCheckbox.Checked == true)
+ {
+ tfile.Tag.Performers = new string[] { performerName };
+ }
+
+ // Composer tag
+ if (composerCheckbox.Checked == true)
+ {
+ tfile.Tag.Composers = new string[] { composerName };
+ }
+
+ // Release Date tag
+ if (releaseCheckbox.Checked == true)
+ {
+ releaseDate = releaseDate.Substring(0, 4);
+ tfile.Tag.Year = UInt32.Parse(releaseDate);
+ }
+
+ // Genre tag
+ if (genreCheckbox.Checked == true)
+ {
+ tfile.Tag.Genres = new string[] { genre };
+ }
+
+ // Track Number tag
+ if (trackNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Track = UInt32.Parse(trackNumber);
+ }
+
+ // Disc Number tag
+ if (discNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Disc = UInt32.Parse(discNumber);
+ }
+
+ // Total Discs tag
+ if (discTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.DiscCount = UInt32.Parse(discTotal);
+ }
+
+ // Total Tracks tag
+ if (trackTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.TrackCount = UInt32.Parse(trackTotal);
+ }
+
+ // Comment tag
+ if (commentCheckbox.Checked == true)
+ {
+ tfile.Tag.Comment = commentTextbox.Text;
+ }
+
+ // Copyright tag
+ if (copyrightCheckbox.Checked == true)
+ {
+ tfile.Tag.Copyright = copyright;
+ }
+ // UPC tag
+ if (upcCheckbox.Checked == true)
+ {
+ // Not available on MP3 at the moment
+ }
+
+ // ISRC tag
+ if (isrcCheckbox.Checked == true)
+ {
+ TagLib.Id3v2.Tag tag = (TagLib.Id3v2.Tag)tfile.GetTag(TagTypes.Id3v2, true);
+ tag.SetTextFrame("TSRC", isrc);
+ }
+
+ // Explicit tag
+ if (explicitCheckbox.Checked == true)
+ {
+ // Not available on MP3 at the moment
+ }
+
+ // Save all selected tags to file
+ tfile.Save();
+ }
+ else
+ {
+ // If there is a version name.
+ var tfile = TagLib.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + " (" + versionNamePath + ")" + audioFileType);
+ // For custom / troublesome tags.
+ TagLib.Id3v2.Tag t = (TagLib.Id3v2.Tag)tfile.GetTag(TagLib.TagTypes.Id3v2);
+
+
+ // Saving cover art to file(s)
+ if (imageCheckbox.Checked == true)
+ {
+ // Define cover art to use for FLAC file(s)
+ TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame();
+ pic.TextEncoding = TagLib.StringType.Latin1;
+ pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg;
+ pic.Type = TagLib.PictureType.FrontCover;
+ pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg");
+
+ // Save cover art to FLAC file.
+ tfile.Tag.Pictures = new TagLib.IPicture[1] { pic };
+ tfile.Save();
+ }
+
+ // Track Title tag
+ if (trackTitleCheckbox.Checked == true)
+ {
+ tfile.Tag.Title = trackName + " (" + versionName + ")";
+ }
+
+ // Album Title tag
+ if (albumCheckbox.Checked == true)
+ {
+ tfile.Tag.Album = albumName;
+ }
+
+ // Album Artits tag
+ if (albumArtistCheckbox.Checked == true)
+ {
+ tfile.Tag.AlbumArtists = new string[] { albumArtist };
+ }
+
+ // Track Artist tag
+ if (artistCheckbox.Checked == true)
+ {
+ tfile.Tag.Performers = new string[] { performerName };
+ }
+
+ // Composer tag
+ if (composerCheckbox.Checked == true)
+ {
+ tfile.Tag.Composers = new string[] { composerName };
+ }
+
+ // Release Date tag
+ if (releaseCheckbox.Checked == true)
+ {
+ releaseDate = releaseDate.Substring(0, 4);
+ tfile.Tag.Year = UInt32.Parse(releaseDate);
+ }
+
+ // Genre tag
+ if (genreCheckbox.Checked == true)
+ {
+ tfile.Tag.Genres = new string[] { genre };
+ }
+
+ // Track Number tag
+ if (trackNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Track = UInt32.Parse(trackNumber);
+ }
+
+ // Disc Number tag
+ if (discNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Disc = UInt32.Parse(discNumber);
+ }
+
+ // Total Discs tag
+ if (discTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.DiscCount = UInt32.Parse(discTotal);
+ }
+
+ // Total Tracks tag
+ if (trackTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.TrackCount = UInt32.Parse(trackTotal);
+ }
+
+ // Comment tag
+ if (commentCheckbox.Checked == true)
+ {
+ tfile.Tag.Comment = commentTextbox.Text;
+ }
+
+ // Copyright tag
+ if (copyrightCheckbox.Checked == true)
+ {
+ tfile.Tag.Copyright = copyright;
+ }
+ // UPC tag
+ if (upcCheckbox.Checked == true)
+ {
+ // Not available on MP3 at the moment
+ }
+
+ // ISRC tag
+ if (isrcCheckbox.Checked == true)
+ {
+ TagLib.Id3v2.Tag tag = (TagLib.Id3v2.Tag)tfile.GetTag(TagTypes.Id3v2, true);
+ tag.SetTextFrame("TSRC", isrc);
+ }
+
+ // Explicit tag
+ if (explicitCheckbox.Checked == true)
+ {
+ // Not available on MP3 at the moment
+ }
+
+ // Save all selected tags to file
+ tfile.Save();
+ }
+ #endregion
+ }
+ else
+ {
+ #region FLAC Tagging
+ // Select the downloaded file to prepare for tagging.
+ // Check if there's a version name or not
+ if (versionName == null | versionName == "")
+ {
+ // If there is NOT a version name.
+ var tfile = TagLib.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + audioFileType);
+ // For custom / troublesome tags.
+ var custom = (TagLib.Ogg.XiphComment)tfile.GetTag(TagLib.TagTypes.Xiph);
+
+
+ // Saving cover art to file(s)
+ if (imageCheckbox.Checked == true)
+ {
+ // Define cover art to use for FLAC file(s)
+ TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame();
+ pic.TextEncoding = TagLib.StringType.Latin1;
+ pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg;
+ pic.Type = TagLib.PictureType.FrontCover;
+ pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg");
+
+ // Save cover art to FLAC file.
+ tfile.Tag.Pictures = new TagLib.IPicture[1] { pic };
+ tfile.Save();
+ }
+
+ // Track Title tag
+ if (trackTitleCheckbox.Checked == true)
+ {
+ tfile.Tag.Title = trackName;
+ }
+
+ // Album Title tag
+ if (albumCheckbox.Checked == true)
+ {
+ tfile.Tag.Album = albumName;
+ }
+
+ // Album Artits tag
+ if (albumArtistCheckbox.Checked == true)
+ {
+ custom.SetField("ALBUMARTIST", new string[] { albumArtist });
+ }
+
+ // Track Artist tag
+ if (artistCheckbox.Checked == true)
+ {
+ custom.SetField("ARTIST", new string[] { performerName });
+ }
+
+ // Composer tag
+ if (composerCheckbox.Checked == true)
+ {
+ custom.SetField("COMPOSER", new string[] { composerName });
+ }
+
+ // Release Date tag
+ if (releaseCheckbox.Checked == true)
+ {
+ custom.SetField("YEAR", new string[] { releaseDate });
+ }
+
+ // Genre tag
+ if (genreCheckbox.Checked == true)
+ {
+ custom.SetField("GENRE", new string[] { genre });
+ }
+
+ // Track Number tag
+ if (trackNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Track = UInt32.Parse(trackNumber);
+ }
+
+ // Disc Number tag
+ if (discNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Disc = UInt32.Parse(discNumber);
+ }
+
+ // Total Discs tag
+ if (discTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.DiscCount = UInt32.Parse(discTotal);
+ }
+
+ // Total Tracks tag
+ if (trackTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.TrackCount = UInt32.Parse(trackTotal);
+ }
+
+ // Comment tag
+ if (commentCheckbox.Checked == true)
+ {
+ custom.SetField("COMMENT", new string[] { commentTextbox.Text });
+ }
+
+ // Copyright tag
+ if (copyrightCheckbox.Checked == true)
+ {
+ custom.SetField("COPYRIGHT", new string[] { copyright });
+ }
+ // UPC tag
+ if (upcCheckbox.Checked == true)
+ {
+ custom.SetField("UPC", new string[] { upc });
+ }
+
+ // ISRC tag
+ if (isrcCheckbox.Checked == true)
+ {
+ custom.SetField("ISRC", new string[] { isrc });
+ }
+
+ // Explicit tag
+ if (explicitCheckbox.Checked == true)
+ {
+ if (advisory == "false") { custom.SetField("ITUNESADVISORY", new string[] { "0" }); } else { custom.SetField("ITUNESADVISORY", new string[] { "1" }); }
+ }
+
+ // Save all selected tags to file
+ tfile.Save();
+ }
+ else
+ {
+ // If there is a version name.
+ var tfile = TagLib.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + " (" + versionNamePath + ")" + audioFileType);
+ // For custom / troublesome tags.
+ var custom = (TagLib.Ogg.XiphComment)tfile.GetTag(TagLib.TagTypes.Xiph);
+
+
+ // Saving cover art to file(s)
+ if (imageCheckbox.Checked == true)
+ {
+ // Define cover art to use for FLAC file(s)
+ TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame();
+ pic.TextEncoding = TagLib.StringType.Latin1;
+ pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg;
+ pic.Type = TagLib.PictureType.FrontCover;
+ pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg");
+
+ // Save cover art to FLAC file.
+ tfile.Tag.Pictures = new TagLib.IPicture[1] { pic };
+ tfile.Save();
+ }
+
+ // Track Title tag
+ if (trackTitleCheckbox.Checked == true)
+ {
+ tfile.Tag.Title = trackName + " (" + versionName + ")";
+ }
+
+ // Album Title tag
+ if (albumCheckbox.Checked == true)
+ {
+ tfile.Tag.Album = albumName;
+ }
+
+ // Album Artits tag
+ if (albumArtistCheckbox.Checked == true)
+ {
+ custom.SetField("ALBUMARTIST", new string[] { albumArtist });
+ }
+
+ // Track Artist tag
+ if (artistCheckbox.Checked == true)
+ {
+ custom.SetField("ARTIST", new string[] { performerName });
+ }
+
+ // Composer tag
+ if (composerCheckbox.Checked == true)
+ {
+ custom.SetField("COMPOSER", new string[] { composerName });
+ }
+
+ // Release Date tag
+ if (releaseCheckbox.Checked == true)
+ {
+ custom.SetField("YEAR", new string[] { releaseDate });
+ }
+
+ // Genre tag
+ if (genreCheckbox.Checked == true)
+ {
+ custom.SetField("GENRE", new string[] { genre });
+ }
+
+ // Track Number tag
+ if (trackNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Track = UInt32.Parse(trackNumber);
+ }
+
+ // Disc Number tag
+ if (discNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Disc = UInt32.Parse(discNumber);
+ }
+
+ // Total Discs tag
+ if (discTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.DiscCount = UInt32.Parse(discTotal);
+ }
+
+ // Total Tracks tag
+ if (trackTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.TrackCount = UInt32.Parse(trackTotal);
+ }
+
+ // Comment tag
+ if (commentCheckbox.Checked == true)
+ {
+ custom.SetField("COMMENT", new string[] { commentTextbox.Text });
+ }
+
+ // Copyright tag
+ if (copyrightCheckbox.Checked == true)
+ {
+ custom.SetField("COPYRIGHT", new string[] { copyright });
+ }
+ // UPC tag
+ if (upcCheckbox.Checked == true)
+ {
+ custom.SetField("UPC", new string[] { upc });
+ }
+
+ // ISRC tag
+ if (isrcCheckbox.Checked == true)
+ {
+ custom.SetField("ISRC", new string[] { isrc });
+ }
+
+ // Explicit tag
+ if (explicitCheckbox.Checked == true)
+ {
+ if (advisory == "false") { custom.SetField("ITUNESADVISORY", new string[] { "0" }); } else { custom.SetField("ITUNESADVISORY", new string[] { "1" }); }
+ }
+
+ // Save all selected tags to file
+ tfile.Save();
+ }
+ #endregion
+ }
+ #endregion
+
+ #region Digital Booklet
+ // If a booklet was found, save it.
+ if (goodiesPDF == null | goodiesPDF == "")
+ {
+ // No need to download something that doesn't exist.
+ }
+ else
+ {
+ if (System.IO.File.Exists(loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Digital Booklet.pdf"))
+ {
+ // Skip, don't re-download.
+ }
+ else
+ {
+ // Save digital booklet to selected path
+ output.Invoke(new Action(() => output.AppendText("\r\nGoodies found, downloading...")));
+ using (WebClient bookClient = new WebClient())
+ {
+ // Download max quality Cover Art to "Cover.jpg" file in chosen path.
+ bookClient.DownloadFile(new Uri(goodiesPDF), loc + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Digital Booklet.pdf");
+ }
+ }
+ }
+ #endregion
+ }
+ catch (Exception downloadError)
+ {
+ // If there is an issue trying to, or during the download, show error info.
+ string error = downloadError.ToString();
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("Track Download ERROR. Information below.\r\n\r\n")));
+ output.Invoke(new Action(() => output.AppendText(error)));
+ output.Invoke(new Action(() => output.AppendText("\r\n\r\nIf some tracks aren't available for streaming on the album you're trying to download, try to manually download the available tracks individually.")));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+
+ // Say when a track is done downloading, then wait for the next track / end.
+ output.Invoke(new Action(() => output.AppendText("Track Download Done!\r\n")));
+ System.Threading.Thread.Sleep(800);
+ }
+
+ // Say that downloading is completed.
+ output.Invoke(new Action(() => output.AppendText("\r\n\r\n")));
+ output.Invoke(new Action(() => output.AppendText("Downloading job completed! All downloaded files will be located in your chosen path.")));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ }
+ catch (Exception ex)
+ {
+ string error = ex.ToString();
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("Failed to download (First Phase). Error information below.\r\n\r\n")));
+ output.Invoke(new Action(() => output.AppendText(error)));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+ }
+ }
+ catch (Exception downloadError)
+ {
+ // If there is an issue trying to, or during the download, show error info.
+ string error = downloadError.ToString();
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("Artist Download ERROR. Information below.\r\n\r\n")));
+ output.Invoke(new Action(() => output.AppendText(error)));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+ #endregion
+ }
+
+ // For downloading "album" links
+ private async void downloadAlbumBG_DoWork(object sender, DoWorkEventArgs e)
+ {
+ #region If URL has "album"
+ WebRequest albumWR = WebRequest.Create("https://www.qobuz.com/api.json/0.2/album/get?album_id=" + albumId + "&app_id=" + appid + "&user_auth_token=" + userAuth);
+
+ // Empty output, then say Starting Downloads.
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("Starting Downloads...\r\n\r\n")));
+
+ try
+ {
+ // Set "loc" as the selected path.
+ String loc = folderBrowserDialog.SelectedPath;
+
+ WebResponse albumWS = albumWR.GetResponse();
+ StreamReader albumSR = new StreamReader(albumWS.GetResponseStream());
+
+ string albumRequest = albumSR.ReadToEnd();
+
+ string text = albumRequest;
+
+ #region Cover Art URL
+ // Grab Cover Art URL
+ var frontCoverLog = Regex.Match(albumRequest, "\"image\":{\"thumbnail\":\"(?[A-Za-z0-9:().,\\\\\\/._\\-']+)").Groups;
+ var frontCover = frontCoverLog[1].Value;
+
+ // Remove backslashes from the stream URL to have a proper URL.
+ string imagepattern = @"(?[^\\]+)";
+ string imageinput = frontCover;
+ RegexOptions imageoptions = RegexOptions.Multiline;
+
+ imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = String.Empty));
+
+ foreach (Match mImg in Regex.Matches(imageinput, imagepattern, imageoptions))
+ {
+ imageURLTextbox.Invoke(new Action(() => imageURLTextbox.AppendText(string.Format("{0}", mImg.Value))));
+ }
+
+ string frontCoverImg = imageURLTextbox.Text;
+ string frontCoverImgBox = frontCoverImg.Replace("_50.jpg", "_150.jpg");
+ frontCoverImg = frontCoverImg.Replace("_50.jpg", "_max.jpg");
+
+ albumArtPicBox.Invoke(new Action(() => albumArtPicBox.ImageLocation = frontCoverImgBox));
+
+ imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = Settings.Default.savedEmail));
+ #endregion
+
+ #region "Goodies" URL (Digital Booklets)
+ // Look for "Goodies" (digital booklet)
+ var goodiesLog = Regex.Match(albumRequest, "\"goodies\":\\[{\"id\":(?.*?),\"original_url\":\"(?.*?)\",\\\"").Groups;
+ var goodies = goodiesLog[2].Value;
+
+ // Remove backslashes from the stream URL to have a proper URL.
+ string bookpattern = @"(?[^\\]+)";
+ string bookinput = goodies;
+ RegexOptions bookoptions = RegexOptions.Multiline;
+
+ imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = String.Empty));
+
+ foreach (Match mBook in Regex.Matches(bookinput, bookpattern, bookoptions))
+ {
+ imageURLTextbox.Invoke(new Action(() => imageURLTextbox.AppendText(string.Format("{0}", mBook.Value))));
+ }
+
+ string goodiesPDF = imageURLTextbox.Text;
+
+ imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = Settings.Default.savedEmail));
+ #endregion
+
+ // Grab sample rate and bit depth for album.
+ var qualityLog = Regex.Match(albumRequest, "\"maximum_sampling_rate\":(?.*?),(?:.*?)\"maximum_bit_depth\":(?.*?),\"duration\"").Groups;
+ var sampleRate = qualityLog[1].Value;
+ var bitDepth = qualityLog[2].Value;
+ var quality = "FLAC (" + bitDepth + "bit/" + sampleRate + "kHz)";
+ var qualityPath = quality.Replace(@"\", "-").Replace(@"/", "-");
+
+ if (formatIdString == "5")
+ {
+ quality = "MP3 320kbps CBR";
+ qualityPath = "MP3";
+ }
+ else if (formatIdString == "6")
+ {
+ quality = "FLAC (16bit/44.1kHz)";
+ qualityPath = "FLAC (16bit-44.1kHz)";
+ }
+ else if (formatIdString == "7")
+ {
+ if (quality == "FLAC (24bit/192kHz)")
+ {
+ quality = "FLAC (24bit/96kHz)";
+ qualityPath = "FLAC (24bit-96kHz)";
+ }
+ }
+
+ // Grab all Track IDs listed on the API.
+ string trackIdspattern = "\"version\":(?:.*?),\"id\":(?.*?),";
+ string input = text;
+ RegexOptions options = RegexOptions.Multiline;
+
+
+ foreach (Match m in Regex.Matches(input, trackIdspattern, options))
+ {
+ // Set default value for max length.
+ const int MaxLength = 200;
+
+ // Grab matches for Track IDs
+ trackIdString = string.Format("{0}", m.Groups["trackId"].Value);
+
+ WebRequest trackwr = WebRequest.Create("https://www.qobuz.com/api.json/0.2/track/get?track_id=" + trackIdString + "&app_id=" + appid + "&user_auth_token=" + userAuth);
+
+ WebResponse trackws = trackwr.GetResponse();
+ StreamReader tracksr = new StreamReader(trackws.GetResponseStream());
+
+ string trackRequest = tracksr.ReadToEnd();
+
+ #region Availability Check (Valid Link?)
+ // Check if available at all.
+ var errorCheckLog = Regex.Match(trackRequest, "\"code\":404,\"message\":\"(?.*?)\\\"").Groups;
+ var errorCheck = errorCheckLog[1].Value;
+
+ if (errorCheck == "No result matching given argument")
+ {
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("ERROR: 404\r\n")));
+ output.Invoke(new Action(() => output.AppendText("Error message is \"No result matching given argument\"\r\n")));
+ output.Invoke(new Action(() => output.AppendText("This could mean either the link is invalid, or isn't available in the region you're downloading from (even if the account is in the correct region). If the latter is true, use a VPN for the region it's available in to download.")));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+ #endregion
+
+ // Display album quality in quality textbox.
+ qualityTextbox.Invoke(new Action(() => qualityTextbox.Text = quality));
+
+ #region Get Information (Tags, Titles, etc.)
+ // Track Number tag
+ var trackNumberLog = Regex.Match(trackRequest, "\"track_number\":(?[0-9]+)").Groups;
+ var trackNumber = trackNumberLog[1].Value;
+
+ // Total Tracks tag
+ var tracksLog = Regex.Match(albumRequest, "tracks_count\":(?\\d+)").Groups;
+ var tracks = tracksLog[1].Value;
+
+ // Disc Number tag
+ var discNumberLog = Regex.Match(trackRequest, "\"media_number\":(?.*?),\\\"").Groups;
+ var discNumber = discNumberLog[1].Value;
+
+ // Album Artist tag
+ var albumArtistLog = Regex.Match(trackRequest, "\"artist\":{\"picture\":(?.*?),\"id\"(?.*?),\"albums_count\":(?.*?),\"name\":\"(?.*?)\",\\\"").Groups;
+ var albumArtist = albumArtistLog[4].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeAlbumArtist = albumArtist;
+ string decodedAlbumArtist = DecodeEncodedNonAsciiCharacters(unicodeAlbumArtist);
+ albumArtist = decodedAlbumArtist;
+
+ albumArtist = albumArtist.Replace(@"\\", @"\").Replace(@"\/", @"/");
+ var albumArtistPath = albumArtist.Replace(@"\", "-").Replace(@"/", "-").Replace("\"", "''").Replace(":", ";").Replace("<", "[").Replace(">", "]").Replace("|", "-").Replace("?", "_").Replace("*", "-");
+
+ // Display album artist in text box under cover art.
+ albumArtistTextBox.Invoke(new Action(() => albumArtistTextBox.Text = albumArtist));
+
+ // If name goes over 200 characters, limit it to 200
+ if (albumArtistPath.Length > MaxLength)
+ {
+ albumArtistPath = albumArtistPath.Substring(0, MaxLength);
+ }
+
+ // Track Artist tag
+ var performerNameLog = Regex.Match(trackRequest, "\"performer\":{\"id\":(?.*?),\"name\":\"(?.*?)\"},\\\"").Groups;
+ var performerName = performerNameLog[2].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodePerformerName = performerName;
+ string decodedPerformerName = DecodeEncodedNonAsciiCharacters(unicodePerformerName);
+ performerName = decodedPerformerName;
+
+ performerName = performerName.Replace(@"\\", @"\").Replace(@"\/", @"/");
+ var performerNamePath = performerName.Replace(@"\", "-").Replace(@"/", "-").Replace("\"", "''").Replace(":", ";").Replace("<", "[").Replace(">", "]").Replace("|", "-").Replace("?", "_").Replace("*", "-");
+
+ // If name goes over 200 characters, limit it to 200
+ if (performerNamePath.Length > MaxLength)
+ {
+ performerNamePath = performerNamePath.Substring(0, MaxLength);
+ }
+
+ // Track Composer tag
+ var composerNameLog = Regex.Match(trackRequest, "\"composer\":{\"id\":(?.*?),\"name\":\"(?.*?)\"},\\\"").Groups;
+ var composerName = composerNameLog[2].Value;
+
+ // Track Explicitness
+ var advisoryLog = Regex.Match(trackRequest, "\"performers\":(?:.*?)\"parental_warning\":(?.*?),").Groups;
+ var advisory = advisoryLog[1].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeComposerName = composerName;
+ string decodedComposerName = DecodeEncodedNonAsciiCharacters(unicodeComposerName);
+ composerName = decodedComposerName;
+
+ composerName = composerName.Replace(@"\\", @"\").Replace(@"\/", @"/");
+
+ // Album Name tag
+ var albumNameLog = Regex.Match(trackRequest, "\"title\":\"(?.*?)\",\\\"").Groups;
+ var albumName = albumNameLog[1].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeAlbumName = albumName;
+ string decodedAlbumName = DecodeEncodedNonAsciiCharacters(unicodeAlbumName);
+ albumName = decodedAlbumName;
+
+ albumName = albumName.Replace(@"\\", @"\").Replace(@"\/", @"/");
+ var albumNamePath = albumName.Replace(@"\", "-").Replace(@"/", "-").Replace("\"", "''").Replace(":", ";").Replace("<", "[").Replace(">", "]").Replace("|", "-").Replace("?", "_").Replace("*", "-");
+
+ // Display album name in text box under cover art.
+ albumTextBox.Invoke(new Action(() => albumTextBox.Text = albumName));
+
+ // If name goes over 200 characters, limit it to 200
+ if (albumNamePath.Length > MaxLength)
+ {
+ albumNamePath = albumNamePath.Substring(0, MaxLength);
+ }
+
+ // Track Name tag
+ var trackNameLog = Regex.Match(trackRequest, "\"version\":(?.*?),\"id\":(?.*?),\"maximum_bit_depth\":(?.*?),\"title\":\"(?.*?)\",\\\"").Groups;
+ var trackName = trackNameLog[4].Value;
+ trackName = trackName.Trim(); // Remove spaces from end of track name
+
+ // For converting unicode characters to ASCII
+ string unicodeTrackName = trackName;
+ string decodedTrackName = DecodeEncodedNonAsciiCharacters(unicodeTrackName);
+ trackName = decodedTrackName;
+
+ trackName = trackName.Replace(@"\\", @"\").Replace(@"\/", @"/");
+ var trackNamePath = trackName.Replace(@"\", "-").Replace(@"/", "-").Replace("\"", "''").Replace(":", ";").Replace("<", "[").Replace(">", "]").Replace("|", "-").Replace("?", "_").Replace("*", "-");
+
+ // If name goes over 200 characters, limit it to 200
+ if (trackNamePath.Length > MaxLength)
+ {
+ trackNamePath = trackNamePath.Substring(0, MaxLength);
+ }
+
+ // Version Name tag
+ var versionNameLog = Regex.Match(trackRequest, "\"version\":\"(?.*?)\",\\\"").Groups;
+ var versionName = versionNameLog[1].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeVersionName = versionName;
+ string decodedVersionName = DecodeEncodedNonAsciiCharacters(unicodeVersionName);
+ versionName = decodedVersionName;
+
+ versionName = versionName.Replace(@"\\", @"\").Replace(@"\/", @"/");
+ var versionNamePath = versionName.Replace(@"\", "-").Replace(@"/", "-").Replace("\"", "''").Replace(":", ";").Replace("<", "[").Replace(">", "]").Replace("|", "-").Replace("?", "_").Replace("*", "-");
+
+ // Genre tag
+ var genreLog = Regex.Match(trackRequest, "\"genre\":{\"id\":(?.*?),\"color\":\"(?.*?)\",\"name\":\"(?.*?)\",\\\"").Groups;
+ var genre = genreLog[3].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeGenre = genre;
+ string decodedGenre = DecodeEncodedNonAsciiCharacters(unicodeGenre);
+ genre = decodedGenre;
+
+ // Release Date tag, grabs the available "stream" date
+ var releaseDateLog = Regex.Match(trackRequest, "\"release_date_stream\":\"(?.*?)\",\\\"").Groups;
+ var releaseDate = releaseDateLog[1].Value;
+
+ // Display release date in text box under cover art.
+ releaseDateTextBox.Invoke(new Action(() => releaseDateTextBox.Text = releaseDate));
+
+ // Copyright tag
+ var copyrightLog = Regex.Match(trackRequest, "\"copyright\":\"(?.*?)\"copyright\":\"(?.*?)\\\"").Groups;
+ var copyright = copyrightLog[2].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeCopyright = copyright;
+ string decodedCopyright = DecodeEncodedNonAsciiCharacters(unicodeCopyright);
+ copyright = decodedCopyright;
+
+ copyright = copyright.Replace(@"\\", @"\").Replace(@"\/", @"/").Replace(@"\u2117", @"℗");
+
+ // UPC tag
+ var upcLog = Regex.Match(trackRequest, "\"upc\":\"(?.*?)\",\\\"").Groups;
+ var upc = upcLog[1].Value;
+
+ // Display UPC in text box under cover art.
+ upcTextBox.Invoke(new Action(() => upcTextBox.Text = upc));
+
+ // ISRC tag
+ var isrcLog = Regex.Match(trackRequest, "\"isrc\":\"(?.*?)\",\\\"").Groups;
+ var isrc = isrcLog[1].Value;
+
+ // Total Tracks tag
+ var trackTotalLog = Regex.Match(trackRequest, "\"tracks_count\":(?[0-9]+)").Groups;
+ var trackTotal = trackTotalLog[1].Value;
+
+ // Display Total Tracks in text box under cover art.
+ totalTracksTextbox.Invoke(new Action(() => totalTracksTextbox.Text = trackTotal));
+
+ // Total Discs tag
+ var discTotalLog = Regex.Match(trackRequest, "\"media_count\":(?[0-9]+)").Groups;
+ var discTotal = discTotalLog[1].Value;
+ #endregion
+
+ #region Filename Number Padding
+ // Set default padding length
+ var paddingLength = 2;
+
+ // Prepare track number padding in filename.
+ string paddingLog = trackTotal.Length.ToString();
+ if (paddingLog == "1")
+ {
+ paddingLength = 2;
+ }
+ else
+ {
+ paddingLength = trackTotal.Length;
+ }
+ #endregion
+
+ #region Create Directories
+ System.IO.Directory.CreateDirectory(loc + "\\" + albumArtistPath);
+ System.IO.Directory.CreateDirectory(loc + "\\" + albumArtistPath + "\\" + albumNamePath);
+ System.IO.Directory.CreateDirectory(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath);
+
+ string albumPath = loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath;
+ #endregion
+
+ #region Availability Check (Streamable?)
+ // Check if available for streaming.
+ var streamCheckLog = Regex.Match(trackRequest, "\"track_number\":(?.*?)\"streamable\":(?.*?),\"").Groups;
+ var streamCheck = streamCheckLog[2].Value;
+
+ if (streamCheck != "true")
+ {
+ output.Invoke(new Action(() => output.AppendText("Track " + trackNumber + " \"" + trackName + "\" is not available for streaming. Skipping track...\r\n")));
+ System.Threading.Thread.Sleep(800);
+ continue;
+ }
+ #endregion
+
+ #region Check if File Exists
+ // Check if there is a version name.
+ if (versionName == null | versionName == "")
+ {
+ if (System.IO.File.Exists(albumPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + audioFileType))
+ {
+ output.Invoke(new Action(() => output.AppendText("File for \"" + trackNumber.PadLeft(paddingLength, '0') + " " + trackName + "\" already exists. Skipping.\r\n")));
+ System.Threading.Thread.Sleep(800);
+ continue;
+ }
+ }
+ else
+ {
+ if (System.IO.File.Exists(albumPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + " (" + versionNamePath + ")" + audioFileType))
+ {
+ output.Invoke(new Action(() => output.AppendText("File for \"" + trackNumber.PadLeft(paddingLength, '0') + " " + trackName + " (" + versionName + ")" + "\" already exists. Skipping.\r\n")));
+ System.Threading.Thread.Sleep(800);
+ continue;
+ }
+ }
+ #endregion
+
+ // Close web request and create streaming URL.
+ trackwr.Abort();
+ createURL(sender, e);
+
+ try
+ {
+ #region Downloading
+ // Check if there is a version name.
+ if (versionName == null | versionName == "")
+ {
+ output.Invoke(new Action(() => output.AppendText("Downloading - " + trackNumber.PadLeft(paddingLength, '0') + " - " + trackName + " ......")));
+ }
+ else
+ {
+ output.Invoke(new Action(() => output.AppendText("Downloading - " + trackNumber.PadLeft(paddingLength, '0') + " - " + trackName + " (" + versionName + ")" + " ......")));
+ }
+
+ // Being download process.
+ var client = new HttpClient();
+ // Run through TLS to allow secure connection.
+ ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
+ // Set "range" header to nearly unlimited.
+ client.DefaultRequestHeaders.Range = new RangeHeaderValue(0, 999999999999);
+ // Set user-agent to Firefox.
+ client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0");
+ // Set referer URL to album ID.
+ client.DefaultRequestHeaders.Add("Referer", "https://play.qobuz.com/album/" + albumId);
+ // Download the URL in the "Streamed URL" Textbox (Will most likely be replaced).
+ using (var stream = await client.GetStreamAsync(testURLBox.Text))
+
+ // Save single track in selected path.
+ if (versionName == null | versionName == "")
+ {
+ // If there is NOT a version name.
+ using (var output = System.IO.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + audioFileType))
+ {
+ await stream.CopyToAsync(output);
+ }
+ }
+ else
+ {
+ // If there is a version name.
+ using (var output = System.IO.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + " (" + versionNamePath + ")" + audioFileType))
+ {
+ await stream.CopyToAsync(output);
+ }
+ }
+ #endregion
+
+ #region Cover Art Saving
+ if (System.IO.File.Exists(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + "Cover.jpg"))
+ {
+ // Skip, don't re-download.
+ }
+ else
+ {
+ // Save cover art to selected path (Currently happens every time a track is downloaded).
+ using (WebClient imgClient = new WebClient())
+ {
+ // Download max quality Cover Art to "Cover.jpg" file in chosen path.
+ imgClient.DownloadFile(new Uri(frontCoverImg), loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + "Cover.jpg");
+ }
+ }
+ #endregion
+
+ #region Tagging
+ // Check if audio file type is FLAC or MP3
+ if (audioFileType == ".mp3")
+ {
+ #region MP3 Tagging (Needs Work)
+ // Select the downloaded file to prepare for tagging.
+ // Check if there's a version name or not
+ if (versionName == null | versionName == "")
+ {
+ // If there is NOT a version name.
+ var tfile = TagLib.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + audioFileType);
+ // For custom / troublesome tags.
+ TagLib.Id3v2.Tag t = (TagLib.Id3v2.Tag)tfile.GetTag(TagLib.TagTypes.Id3v2);
+
+
+ // Saving cover art to file(s)
+ if (imageCheckbox.Checked == true)
+ {
+ // Define cover art to use for MP3 file(s)
+ TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame();
+ pic.TextEncoding = TagLib.StringType.Latin1;
+ pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg;
+ pic.Type = TagLib.PictureType.FrontCover;
+ pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + "Cover.jpg");
+
+ // Save cover art to MP3 file.
+ tfile.Tag.Pictures = new TagLib.IPicture[1] { pic };
+ tfile.Save();
+ }
+
+ // Track Title tag
+ if (trackTitleCheckbox.Checked == true)
+ {
+ tfile.Tag.Title = trackName;
+ }
+
+ // Album Title tag
+ if (albumCheckbox.Checked == true)
+ {
+ tfile.Tag.Album = albumName;
+ }
+
+ // Album Artits tag
+ if (albumArtistCheckbox.Checked == true)
+ {
+ tfile.Tag.AlbumArtists = new string[] { albumArtist };
+ }
+
+ // Track Artist tag
+ if (artistCheckbox.Checked == true)
+ {
+ tfile.Tag.Performers = new string[] { performerName };
+ }
+
+ // Composer tag
+ if (composerCheckbox.Checked == true)
+ {
+ tfile.Tag.Composers = new string[] { composerName };
+ }
+
+ // Release Date tag
+ if (releaseCheckbox.Checked == true)
+ {
+ releaseDate = releaseDate.Substring(0, 4);
+ tfile.Tag.Year = UInt32.Parse(releaseDate);
+ }
+
+ // Genre tag
+ if (genreCheckbox.Checked == true)
+ {
+ tfile.Tag.Genres = new string[] { genre };
+ }
+
+ // Track Number tag
+ if (trackNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Track = UInt32.Parse(trackNumber);
+ }
+
+ // Disc Number tag
+ if (discNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Disc = UInt32.Parse(discNumber);
+ }
+
+ // Total Discs tag
+ if (discTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.DiscCount = UInt32.Parse(discTotal);
+ }
+
+ // Total Tracks tag
+ if (trackTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.TrackCount = UInt32.Parse(trackTotal);
+ }
+
+ // Comment tag
+ if (commentCheckbox.Checked == true)
+ {
+ tfile.Tag.Comment = commentTextbox.Text;
+ }
+
+ // Copyright tag
+ if (copyrightCheckbox.Checked == true)
+ {
+ tfile.Tag.Copyright = copyright;
+ }
+ // UPC tag
+ if (upcCheckbox.Checked == true)
+ {
+ // Not available on MP3 at the moment
+ }
+
+ // ISRC tag
+ if (isrcCheckbox.Checked == true)
+ {
+ TagLib.Id3v2.Tag tag = (TagLib.Id3v2.Tag)tfile.GetTag(TagTypes.Id3v2, true);
+ tag.SetTextFrame("TSRC", isrc);
+ }
+
+ // Explicit tag
+ if (explicitCheckbox.Checked == true)
+ {
+ // Not available on MP3 at the moment
+ }
+
+ // Save all selected tags to file
+ tfile.Save();
+ }
+ else
+ {
+ // If there is a version name.
+ var tfile = TagLib.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + " (" + versionNamePath + ")" + audioFileType);
+ // For custom / troublesome tags.
+ TagLib.Id3v2.Tag t = (TagLib.Id3v2.Tag)tfile.GetTag(TagLib.TagTypes.Id3v2);
+
+
+ // Saving cover art to file(s)
+ if (imageCheckbox.Checked == true)
+ {
+ // Define cover art to use for FLAC file(s)
+ TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame();
+ pic.TextEncoding = TagLib.StringType.Latin1;
+ pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg;
+ pic.Type = TagLib.PictureType.FrontCover;
+ pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + "Cover.jpg");
+
+ // Save cover art to FLAC file.
+ tfile.Tag.Pictures = new TagLib.IPicture[1] { pic };
+ tfile.Save();
+ }
+
+ // Track Title tag
+ if (trackTitleCheckbox.Checked == true)
+ {
+ tfile.Tag.Title = trackName + " (" + versionName + ")";
+ }
+
+ // Album Title tag
+ if (albumCheckbox.Checked == true)
+ {
+ tfile.Tag.Album = albumName;
+ }
+
+ // Album Artits tag
+ if (albumArtistCheckbox.Checked == true)
+ {
+ tfile.Tag.AlbumArtists = new string[] { albumArtist };
+ }
+
+ // Track Artist tag
+ if (artistCheckbox.Checked == true)
+ {
+ tfile.Tag.Performers = new string[] { performerName };
+ }
+
+ // Composer tag
+ if (composerCheckbox.Checked == true)
+ {
+ tfile.Tag.Composers = new string[] { composerName };
+ }
+
+ // Release Date tag
+ if (releaseCheckbox.Checked == true)
+ {
+ releaseDate = releaseDate.Substring(0, 4);
+ tfile.Tag.Year = UInt32.Parse(releaseDate);
+ }
+
+ // Genre tag
+ if (genreCheckbox.Checked == true)
+ {
+ tfile.Tag.Genres = new string[] { genre };
+ }
+
+ // Track Number tag
+ if (trackNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Track = UInt32.Parse(trackNumber);
+ }
+
+ // Disc Number tag
+ if (discNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Disc = UInt32.Parse(discNumber);
+ }
+
+ // Total Discs tag
+ if (discTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.DiscCount = UInt32.Parse(discTotal);
+ }
+
+ // Total Tracks tag
+ if (trackTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.TrackCount = UInt32.Parse(trackTotal);
+ }
+
+ // Comment tag
+ if (commentCheckbox.Checked == true)
+ {
+ tfile.Tag.Comment = commentTextbox.Text;
+ }
+
+ // Copyright tag
+ if (copyrightCheckbox.Checked == true)
+ {
+ tfile.Tag.Copyright = copyright;
+ }
+ // UPC tag
+ if (upcCheckbox.Checked == true)
+ {
+ // Not available on MP3 at the moment
+ }
+
+ // ISRC tag
+ if (isrcCheckbox.Checked == true)
+ {
+ TagLib.Id3v2.Tag tag = (TagLib.Id3v2.Tag)tfile.GetTag(TagTypes.Id3v2, true);
+ tag.SetTextFrame("TSRC", isrc);
+ }
+
+ // Explicit tag
+ if (explicitCheckbox.Checked == true)
+ {
+ // Not available on MP3 at the moment
+ }
+
+ // Save all selected tags to file
+ tfile.Save();
+ }
+ #endregion
+ }
+ else
+ {
+ #region FLAC Tagging
+ // Select the downloaded file to prepare for tagging.
+ // Check if there's a version name or not
+ if (versionName == null | versionName == "")
+ {
+ // If there is NOT a version name.
+ var tfile = TagLib.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + audioFileType);
+ // For custom / troublesome tags.
+ var custom = (TagLib.Ogg.XiphComment)tfile.GetTag(TagLib.TagTypes.Xiph);
+
+
+ // Saving cover art to file(s)
+ if (imageCheckbox.Checked == true)
+ {
+ // Define cover art to use for FLAC file(s)
+ TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame();
+ pic.TextEncoding = TagLib.StringType.Latin1;
+ pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg;
+ pic.Type = TagLib.PictureType.FrontCover;
+ pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + "Cover.jpg");
+
+ // Save cover art to FLAC file.
+ tfile.Tag.Pictures = new TagLib.IPicture[1] { pic };
+ tfile.Save();
+ }
+
+ // Track Title tag
+ if (trackTitleCheckbox.Checked == true)
+ {
+ tfile.Tag.Title = trackName;
+ }
+
+ // Album Title tag
+ if (albumCheckbox.Checked == true)
+ {
+ tfile.Tag.Album = albumName;
+ }
+
+ // Album Artits tag
+ if (albumArtistCheckbox.Checked == true)
+ {
+ custom.SetField("ALBUMARTIST", new string[] { albumArtist });
+ }
+
+ // Track Artist tag
+ if (artistCheckbox.Checked == true)
+ {
+ custom.SetField("ARTIST", new string[] { performerName });
+ }
+
+ // Composer tag
+ if (composerCheckbox.Checked == true)
+ {
+ custom.SetField("COMPOSER", new string[] { composerName });
+ }
+
+ // Release Date tag
+ if (releaseCheckbox.Checked == true)
+ {
+ custom.SetField("YEAR", new string[] { releaseDate });
+ }
+
+ // Genre tag
+ if (genreCheckbox.Checked == true)
+ {
+ custom.SetField("GENRE", new string[] { genre });
+ }
+
+ // Track Number tag
+ if (trackNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Track = UInt32.Parse(trackNumber);
+ }
+
+ // Disc Number tag
+ if (discNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Disc = UInt32.Parse(discNumber);
+ }
+
+ // Total Discs tag
+ if (discTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.DiscCount = UInt32.Parse(discTotal);
+ }
+
+ // Total Tracks tag
+ if (trackTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.TrackCount = UInt32.Parse(trackTotal);
+ }
+
+ // Comment tag
+ if (commentCheckbox.Checked == true)
+ {
+ custom.SetField("COMMENT", new string[] { commentTextbox.Text });
+ }
+
+ // Copyright tag
+ if (copyrightCheckbox.Checked == true)
+ {
+ custom.SetField("COPYRIGHT", new string[] { copyright });
+ }
+ // UPC tag
+ if (upcCheckbox.Checked == true)
+ {
+ custom.SetField("UPC", new string[] { upc });
+ }
+
+ // ISRC tag
+ if (isrcCheckbox.Checked == true)
+ {
+ custom.SetField("ISRC", new string[] { isrc });
+ }
+
+ // Explicit tag
+ if (explicitCheckbox.Checked == true)
+ {
+ if (advisory == "false") { custom.SetField("ITUNESADVISORY", new string[] { "0" }); } else { custom.SetField("ITUNESADVISORY", new string[] { "1" }); }
+ }
+
+ // Save all selected tags to file
+ tfile.Save();
+ }
+ else
+ {
+ // If there is a version name.
+ var tfile = TagLib.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + " (" + versionNamePath + ")" + audioFileType);
+ // For custom / troublesome tags.
+ var custom = (TagLib.Ogg.XiphComment)tfile.GetTag(TagLib.TagTypes.Xiph);
+
+
+ // Saving cover art to file(s)
+ if (imageCheckbox.Checked == true)
+ {
+ // Define cover art to use for FLAC file(s)
+ TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame();
+ pic.TextEncoding = TagLib.StringType.Latin1;
+ pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg;
+ pic.Type = TagLib.PictureType.FrontCover;
+ pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + "Cover.jpg");
+
+ // Save cover art to FLAC file.
+ tfile.Tag.Pictures = new TagLib.IPicture[1] { pic };
+ tfile.Save();
+ }
+
+ // Track Title tag
+ if (trackTitleCheckbox.Checked == true)
+ {
+ tfile.Tag.Title = trackName + " (" + versionName + ")";
+ }
+
+ // Album Title tag
+ if (albumCheckbox.Checked == true)
+ {
+ tfile.Tag.Album = albumName;
+ }
+
+ // Album Artits tag
+ if (albumArtistCheckbox.Checked == true)
+ {
+ custom.SetField("ALBUMARTIST", new string[] { albumArtist });
+ }
+
+ // Track Artist tag
+ if (artistCheckbox.Checked == true)
+ {
+ custom.SetField("ARTIST", new string[] { performerName });
+ }
+
+ // Composer tag
+ if (composerCheckbox.Checked == true)
+ {
+ custom.SetField("COMPOSER", new string[] { composerName });
+ }
+
+ // Release Date tag
+ if (releaseCheckbox.Checked == true)
+ {
+ custom.SetField("YEAR", new string[] { releaseDate });
+ }
+
+ // Genre tag
+ if (genreCheckbox.Checked == true)
+ {
+ custom.SetField("GENRE", new string[] { genre });
+ }
+
+ // Track Number tag
+ if (trackNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Track = UInt32.Parse(trackNumber);
+ }
+
+ // Disc Number tag
+ if (discNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Disc = UInt32.Parse(discNumber);
+ }
+
+ // Total Discs tag
+ if (discTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.DiscCount = UInt32.Parse(discTotal);
+ }
+
+ // Total Tracks tag
+ if (trackTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.TrackCount = UInt32.Parse(trackTotal);
+ }
+
+ // Comment tag
+ if (commentCheckbox.Checked == true)
+ {
+ custom.SetField("COMMENT", new string[] { commentTextbox.Text });
+ }
+
+ // Copyright tag
+ if (copyrightCheckbox.Checked == true)
+ {
+ custom.SetField("COPYRIGHT", new string[] { copyright });
+ }
+ // UPC tag
+ if (upcCheckbox.Checked == true)
+ {
+ custom.SetField("UPC", new string[] { upc });
+ }
+
+ // ISRC tag
+ if (isrcCheckbox.Checked == true)
+ {
+ custom.SetField("ISRC", new string[] { isrc });
+ }
+
+ // Explicit tag
+ if (explicitCheckbox.Checked == true)
+ {
+ if (advisory == "false") { custom.SetField("ITUNESADVISORY", new string[] { "0" }); } else { custom.SetField("ITUNESADVISORY", new string[] { "1" }); }
+ }
+
+ // Save all selected tags to file
+ tfile.Save();
+ }
+ #endregion
+ }
+ #endregion
+
+ #region Digital Booklet
+ // If a booklet was found, save it.
+ if (goodiesPDF == null | goodiesPDF == "")
+ {
+ // No need to download something that doesn't exist.
+ }
+ else
+ {
+ if (System.IO.File.Exists(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + "Digital Booklet.pdf"))
+ {
+ // Skip, don't re-download.
+ }
+ else
+ {
+ if (trackNumber == trackTotal)
+ {
+ // Save digital booklet to selected path
+ output.Invoke(new Action(() => output.AppendText("Goodies found, downloading...")));
+ using (WebClient bookClient = new WebClient())
+ {
+ // Download max quality Cover Art to "Cover.jpg" file in chosen path.
+ bookClient.DownloadFile(new Uri(goodiesPDF), loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + "Digital Booklet.pdf");
+ }
+ }
+ else
+ {
+ // Skip, don't download until final track.
+ }
+ }
+ }
+ #endregion
+ }
+ catch (Exception downloadError)
+ {
+ // If there is an issue trying to, or during the download, show error info.
+ string error = downloadError.ToString();
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("Track Download ERROR. Information below.\r\n\r\n")));
+ output.Invoke(new Action(() => output.AppendText(error)));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+
+ // Say when a track is done downloading, then wait for the next track / end.
+ output.Invoke(new Action(() => output.AppendText("Track Download Done!\r\n")));
+ System.Threading.Thread.Sleep(800);
+ }
+
+ // Say that downloading is completed.
+ output.Invoke(new Action(() => output.AppendText("\r\n\r\n")));
+ output.Invoke(new Action(() => output.AppendText("Downloading job completed! All downloaded files will be located in your chosen path.")));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ }
+ catch (Exception ex)
+ {
+ string error = ex.ToString();
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("Failed to download (First Phase). Error information below.\r\n\r\n")));
+ output.Invoke(new Action(() => output.AppendText(error)));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+ #endregion
+ }
+
+ // For downloading "track" links
+ private async void downloadTrackBG_DoWork(object sender, DoWorkEventArgs e)
+ {
+ #region If URL has "track"
+ // Set default value for max length.
+ const int MaxLength = 200;
+
+ // Set "loc" as the selected path.
+ String loc = folderBrowserDialog.SelectedPath;
+
+ // Set Track ID to the ID in the provided Qobuz link.
+ trackIdString = albumId;
+
+ WebRequest trackwr = WebRequest.Create("https://www.qobuz.com/api.json/0.2/track/get?track_id=" + albumId + "&app_id=" + appid + "&user_auth_token=" + userAuth);
+
+ // Empty output, then say Starting Downloads.
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("Starting Downloads...\r\n\r\n")));
+
+ WebResponse trackws = trackwr.GetResponse();
+ StreamReader tracksr = new StreamReader(trackws.GetResponseStream());
+
+ string trackRequest = tracksr.ReadToEnd();
+
+ // Grab sample rate and bit depth for album track is from.
+ var qualityLog = Regex.Match(trackRequest, "\"maximum_sampling_rate\":(?.*?),(?:.*?)\"maximum_bit_depth\":(?.*?),\"duration\"").Groups;
+ var sampleRate = qualityLog[1].Value;
+ var bitDepth = qualityLog[2].Value;
+ var quality = "FLAC (" + bitDepth + "bit/" + sampleRate + "kHz)";
+ var qualityPath = quality.Replace(@"\", "-").Replace(@"/", "-");
+
+ if (formatIdString == "5")
+ {
+ quality = "MP3 320kbps CBR";
+ qualityPath = "MP3";
+ }
+ else if (formatIdString == "6")
+ {
+ quality = "FLAC (16bit/44.1kHz)";
+ qualityPath = "FLAC (16bit-44.1kHz)";
+ }
+ else if (formatIdString == "7")
+ {
+ if (quality == "FLAC (24bit/192kHz)")
+ {
+ quality = "FLAC (24bit/96kHz)";
+ qualityPath = "FLAC (24bit-96kHz)";
+ }
+ }
+
+ #region Cover Art URL
+ // Grab Cover Art URL
+ var frontCoverLog = Regex.Match(trackRequest, "\"image\":{\"thumbnail\":\"(?[A-Za-z0-9:().,\\\\\\/._\\-']+)").Groups;
+ var frontCover = frontCoverLog[1].Value;
+
+ // Remove backslashes from the stream URL to have a proper URL.
+ string imagepattern = @"(?[^\\]+)";
+ string imageinput = frontCover;
+ RegexOptions imageoptions = RegexOptions.Multiline;
+
+ imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = String.Empty));
+
+ foreach (Match mImg in Regex.Matches(imageinput, imagepattern, imageoptions))
+ {
+ imageURLTextbox.Invoke(new Action(() => imageURLTextbox.AppendText(string.Format("{0}", mImg.Value))));
+ }
+
+ string frontCoverImg = imageURLTextbox.Text;
+ string frontCoverImgBox = frontCoverImg.Replace("_50.jpg", "_150.jpg");
+ frontCoverImg = frontCoverImg.Replace("_50.jpg", "_max.jpg");
+
+ albumArtPicBox.Invoke(new Action(() => albumArtPicBox.ImageLocation = frontCoverImgBox));
+
+ imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = Settings.Default.savedEmail));
+ #endregion
+
+ #region Availability Check (Valid Link?)
+ // Check if available at all.
+ var errorCheckLog = Regex.Match(trackRequest, "\"code\":404,\"message\":\"(?.*?)\\\"").Groups;
+ var errorCheck = errorCheckLog[1].Value;
+
+ if (errorCheck == "No result matching given argument")
+ {
+ output.Invoke(new Action(() => output.Text = String.Empty));
+ output.Invoke(new Action(() => output.AppendText("ERROR: 404\r\n")));
+ output.Invoke(new Action(() => output.AppendText("Error message is \"No result matching given argument\"\r\n")));
+ output.Invoke(new Action(() => output.AppendText("This could mean either the link is invalid, or isn't available in the region you're downloading from (even if the account is in the correct region). If the latter is true, use a VPN for the region it's available in to download.")));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+ #endregion
+
+ // Display album quality in quality textbox.
+ qualityTextbox.Invoke(new Action(() => qualityTextbox.Text = quality));
+
+ #region Get Information (Tags, Titles, etc.)
+ // Track Number tag
+ var trackNumberLog = Regex.Match(trackRequest, "\"track_number\":(?[0-9]+)").Groups;
+ var trackNumber = trackNumberLog[1].Value;
+
+ // Disc Number tag
+ var discNumberLog = Regex.Match(trackRequest, "\"media_number\":(?.*?),\\\"").Groups;
+ var discNumber = discNumberLog[1].Value;
+
+ // Album Artist tag
+ var albumArtistLog = Regex.Match(trackRequest, "\"artist\":{\"picture\":(?.*?),\"id\"(?.*?),\"albums_count\":(?.*?),\"name\":\"(?.*?)\",\\\"").Groups;
+ var albumArtist = albumArtistLog[4].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeAlbumArtist = albumArtist;
+ string decodedAlbumArtist = DecodeEncodedNonAsciiCharacters(unicodeAlbumArtist);
+ albumArtist = decodedAlbumArtist;
+
+ albumArtist = albumArtist.Replace(@"\\", @"\").Replace(@"\/", @"/");
+ var albumArtistPath = albumArtist.Replace(@"\", "-").Replace(@"/", "-").Replace("\"", "''").Replace(":", ";").Replace("<", "[").Replace(">", "]").Replace("|", "-").Replace("?", "_").Replace("*", "-");
+
+ // Display album artist in text box under cover art.
+ albumArtistTextBox.Invoke(new Action(() => albumArtistTextBox.Text = albumArtist));
+
+ // If name goes over 200 characters, limit it to 200
+ if (albumArtistPath.Length > MaxLength)
+ {
+ albumArtistPath = albumArtistPath.Substring(0, MaxLength);
+ }
+
+ // Track Artist tag
+ var performerNameLog = Regex.Match(trackRequest, "\"performer\":{\"id\":(?.*?),\"name\":\"(?.*?)\"},\\\"").Groups;
+ var performerName = performerNameLog[2].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodePerformerName = performerName;
+ string decodedPerformerName = DecodeEncodedNonAsciiCharacters(unicodePerformerName);
+ performerName = decodedPerformerName;
+
+ performerName = performerName.Replace(@"\\", @"\").Replace(@"\/", @"/");
+ var performerNamePath = performerName.Replace(@"\", "-").Replace(@"/", "-").Replace("\"", "''").Replace(":", ";").Replace("<", "[").Replace(">", "]").Replace("|", "-").Replace("?", "_").Replace("*", "-");
+
+ // If name goes over 200 characters, limit it to 200
+ if (performerNamePath.Length > MaxLength)
+ {
+ performerNamePath = performerNamePath.Substring(0, MaxLength);
+ }
+
+ // Track Composer tag
+ var composerNameLog = Regex.Match(trackRequest, "\"composer\":{\"id\":(?.*?),\"name\":\"(?.*?)\"},\\\"").Groups;
+ var composerName = composerNameLog[2].Value;
+
+ // Track Explicitness
+ var advisoryLog = Regex.Match(trackRequest, "\"performers\":(?:.*?)\"parental_warning\":(?.*?),").Groups;
+ var advisory = advisoryLog[1].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeComposerName = composerName;
+ string decodedComposerName = DecodeEncodedNonAsciiCharacters(unicodeComposerName);
+ composerName = decodedComposerName;
+
+ composerName = composerName.Replace(@"\\", @"\").Replace(@"\/", @"/");
+
+ // Album Name tag
+ var albumNameLog = Regex.Match(trackRequest, "\"title\":\"(?.*?)\",\\\"").Groups;
+ var albumName = albumNameLog[1].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeAlbumName = albumName;
+ string decodedAlbumName = DecodeEncodedNonAsciiCharacters(unicodeAlbumName);
+ albumName = decodedAlbumName;
+
+ albumName = albumName.Replace(@"\\", @"\").Replace(@"\/", @"/");
+ var albumNamePath = albumName.Replace(@"\", "-").Replace(@"/", "-").Replace("\"", "''").Replace(":", ";").Replace("<", "[").Replace(">", "]").Replace("|", "-").Replace("?", "_").Replace("*", "-");
+
+ // Display album name in text box under cover art.
+ albumTextBox.Invoke(new Action(() => albumTextBox.Text = albumName));
+
+ // If name goes over 200 characters, limit it to 200
+ if (albumNamePath.Length > MaxLength)
+ {
+ albumNamePath = albumNamePath.Substring(0, MaxLength);
+ }
+
+ // Track Name tag
+ var trackNameLog = Regex.Match(trackRequest, "\"version\":(?.*?),\"id\":(?.*?),\"maximum_bit_depth\":(?.*?),\"title\":\"(?.*?)\",\\\"").Groups;
+ var trackName = trackNameLog[4].Value;
+ trackName = trackName.Trim(); // Remove spaces from end of track name
+
+ // For converting unicode characters to ASCII
+ string unicodeTrackName = trackName;
+ string decodedTrackName = DecodeEncodedNonAsciiCharacters(unicodeTrackName);
+ trackName = decodedTrackName;
+
+ trackName = trackName.Replace(@"\\", @"\").Replace(@"\/", @"/");
+ var trackNamePath = trackName.Replace(@"\", "-").Replace(@"/", "-").Replace("\"", "''").Replace(":", ";").Replace("<", "[").Replace(">", "]").Replace("|", "-").Replace("?", "_").Replace("*", "-");
+
+ // If name goes over 200 characters, limit it to 200
+ if (trackNamePath.Length > MaxLength)
+ {
+ trackNamePath = trackNamePath.Substring(0, MaxLength);
+ }
+
+ // Version Name tag
+ var versionNameLog = Regex.Match(trackRequest, "\"version\":\"(?.*?)\",\\\"").Groups;
+ var versionName = versionNameLog[1].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeVersionName = versionName;
+ string decodedVersionName = DecodeEncodedNonAsciiCharacters(unicodeVersionName);
+ versionName = decodedVersionName;
+
+ versionName = versionName.Replace(@"\\", @"\").Replace(@"\/", @"/");
+ var versionNamePath = versionName.Replace(@"\", "-").Replace(@"/", "-").Replace("\"", "''").Replace(":", ";").Replace("<", "[").Replace(">", "]").Replace("|", "-").Replace("?", "_").Replace("*", "-");
+
+ // Genre tag
+ var genreLog = Regex.Match(trackRequest, "\"genre\":{\"id\":(?.*?),\"color\":\"(?.*?)\",\"name\":\"(?.*?)\",\\\"").Groups;
+ var genre = genreLog[3].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeGenre = genre;
+ string decodedGenre = DecodeEncodedNonAsciiCharacters(unicodeGenre);
+ genre = decodedGenre;
+
+ // Release Date tag, grabs the available "stream" date
+ var releaseDateLog = Regex.Match(trackRequest, "\"release_date_stream\":\"(?.*?)\",\\\"").Groups;
+ var releaseDate = releaseDateLog[1].Value;
+
+ // Display release date in text box under cover art.
+ releaseDateTextBox.Invoke(new Action(() => releaseDateTextBox.Text = releaseDate));
+
+ // Copyright tag
+ var copyrightLog = Regex.Match(trackRequest, "\"copyright\":\"(?.*?)\"copyright\":\"(?.*?)\\\"").Groups;
+ var copyright = copyrightLog[2].Value;
+
+ // For converting unicode characters to ASCII
+ string unicodeCopyright = copyright;
+ string decodedCopyright = DecodeEncodedNonAsciiCharacters(unicodeCopyright);
+ copyright = decodedCopyright;
+
+ copyright = copyright.Replace(@"\\", @"\").Replace(@"\/", @"/").Replace(@"\u2117", @"℗");
+
+ // UPC tag
+ var upcLog = Regex.Match(trackRequest, "\"upc\":\"(?.*?)\",\\\"").Groups;
+ var upc = upcLog[1].Value;
+
+ // Display UPC in text box under cover art.
+ upcTextBox.Invoke(new Action(() => upcTextBox.Text = upc));
+
+ // ISRC tag
+ var isrcLog = Regex.Match(trackRequest, "\"isrc\":\"(?.*?)\",\\\"").Groups;
+ var isrc = isrcLog[1].Value;
+
+ // Total Tracks tag
+ var trackTotalLog = Regex.Match(trackRequest, "\"tracks_count\":(?[0-9]+)").Groups;
+ var trackTotal = trackTotalLog[1].Value;
+
+ // Total Discs tag
+ var discTotalLog = Regex.Match(trackRequest, "\"media_count\":(?[0-9]+)").Groups;
+ var discTotal = discTotalLog[1].Value;
+ #endregion
+
+ #region Filename Number Padding
+ // Set default padding length
+ var paddingLength = 2;
+
+ // Prepare track number padding in filename.
+ string paddingLog = trackTotal.Length.ToString();
+ if (paddingLog == "1")
+ {
+ paddingLength = 2;
+ }
+ else
+ {
+ paddingLength = trackTotal.Length;
+ }
+ #endregion
+
+ #region Create Directories
+ System.IO.Directory.CreateDirectory(loc + "\\" + albumArtistPath);
+ System.IO.Directory.CreateDirectory(loc + "\\" + albumArtistPath + "\\" + albumNamePath);
+ System.IO.Directory.CreateDirectory(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath);
+
+ string trackPath = loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath;
+ #endregion
+
+ #region Availability Check (Streamable?)
+ // Check if available for streaming.
+ var streamCheckLog = Regex.Match(trackRequest, "\"track_number\":(?.*?)\"streamable\":(?.*?),\"").Groups;
+ var streamCheck = streamCheckLog[2].Value;
+
+ if (streamCheck != "true")
+ {
+ output.Invoke(new Action(() => output.AppendText("Track is not available for streaming. Unable to download.\r\n")));
+ System.Threading.Thread.Sleep(800);
+ return;
+ }
+ #endregion
+
+ #region Check if File Exists
+ // Check if there is a version name.
+ if (versionName == null | versionName == "")
+ {
+ if (System.IO.File.Exists(trackPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + audioFileType))
+ {
+ output.Invoke(new Action(() => output.AppendText("File for \"" + trackNumber.PadLeft(paddingLength, '0') + " " + trackName + "\" already exists. Skipping.\r\n")));
+ System.Threading.Thread.Sleep(800);
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+ }
+ else
+ {
+ if (System.IO.File.Exists(trackPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + " (" + versionNamePath + ")" + audioFileType))
+ {
+ output.Invoke(new Action(() => output.AppendText("File for \"" + trackNumber.PadLeft(paddingLength, '0') + " " + trackName + " (" + versionName + ")" + "\" already exists. Skipping.\r\n")));
+ System.Threading.Thread.Sleep(800);
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+ }
+ #endregion
+
+ // Close web request and create streaming URL.
+ trackwr.Abort();
+ createURL(sender, e);
+
+ try
+ {
+
+ #region Downloading
+ // Check if there is a version name.
+ if (versionName == null | versionName == "")
+ {
+ output.Invoke(new Action(() => output.AppendText("Downloading - " + trackNumber.PadLeft(paddingLength, '0') + " - " + trackName + " ......")));
+ }
+ else
+ {
+ output.Invoke(new Action(() => output.AppendText("Downloading - " + trackNumber.PadLeft(paddingLength, '0') + " - " + trackName + " (" + versionName + ")" + " ......")));
+ }
+ // Being download process.
+ var client = new HttpClient();
+ // Run through TLS to allow secure connection.
+ ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
+ // Set "range" header to nearly unlimited.
+ client.DefaultRequestHeaders.Range = new RangeHeaderValue(0, 999999999999);
+ // Set user-agent to Firefox.
+ client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0");
+ // Set referer URL to album ID.
+ client.DefaultRequestHeaders.Add("Referer", "https://play.qobuz.com/album/" + albumId);
+ // Download the URL in the "Streamed URL" Textbox (Will most likely be replaced).
+ using (var stream = await client.GetStreamAsync(testURLBox.Text))
+
+ // Save single track in selected path.
+ if (versionName == null | versionName == "")
+ {
+ // If there is NOT a version name.
+ using (var output = System.IO.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + audioFileType))
+ {
+ await stream.CopyToAsync(output);
+ }
+ }
+ else
+ {
+ // If there is a version name.
+ using (var output = System.IO.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + " (" + versionNamePath + ")" + audioFileType))
+ {
+ await stream.CopyToAsync(output);
+ }
+ }
+ #endregion
+
+ #region Cover Art Saving
+ if (System.IO.File.Exists(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + "Cover.jpg"))
+ {
+ // Skip, don't re-download.
+ }
+ else
+ {
+ // Save cover art to selected path (Currently happens every time a track is downloaded).
+ using (WebClient imgClient = new WebClient())
+ {
+ // Download max quality Cover Art to "Cover.jpg" file in chosen path.
+ imgClient.DownloadFile(new Uri(frontCoverImg), loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + "Cover.jpg");
+ }
+ }
+ #endregion
+
+ #region Tagging
+ // Check if audio file type is FLAC or MP3
+ if (audioFileType == ".mp3")
+ {
+ #region MP3 Tagging (Needs Work)
+ // Select the downloaded file to prepare for tagging.
+ // Check if there's a version name or not
+ if (versionName == null | versionName == "")
+ {
+ // If there is NOT a version name.
+ var tfile = TagLib.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + audioFileType);
+ // For custom / troublesome tags.
+ TagLib.Id3v2.Tag t = (TagLib.Id3v2.Tag)tfile.GetTag(TagLib.TagTypes.Id3v2);
+
+
+ // Saving cover art to file(s)
+ if (imageCheckbox.Checked == true)
+ {
+ // Define cover art to use for MP3 file(s)
+ TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame();
+ pic.TextEncoding = TagLib.StringType.Latin1;
+ pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg;
+ pic.Type = TagLib.PictureType.FrontCover;
+ pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + "Cover.jpg");
+
+ // Save cover art to MP3 file.
+ tfile.Tag.Pictures = new TagLib.IPicture[1] { pic };
+ tfile.Save();
+ }
+
+ // Track Title tag
+ if (trackTitleCheckbox.Checked == true)
+ {
+ tfile.Tag.Title = trackName;
+ }
+
+ // Album Title tag
+ if (albumCheckbox.Checked == true)
+ {
+ tfile.Tag.Album = albumName;
+ }
+
+ // Album Artits tag
+ if (albumArtistCheckbox.Checked == true)
+ {
+ tfile.Tag.AlbumArtists = new string[] { albumArtist };
+ }
+
+ // Track Artist tag
+ if (artistCheckbox.Checked == true)
+ {
+ tfile.Tag.Performers = new string[] { performerName };
+ }
+
+ // Composer tag
+ if (composerCheckbox.Checked == true)
+ {
+ tfile.Tag.Composers = new string[] { composerName };
+ }
+
+ // Release Date tag
+ if (releaseCheckbox.Checked == true)
+ {
+ releaseDate = releaseDate.Substring(0, 4);
+ tfile.Tag.Year = UInt32.Parse(releaseDate);
+ }
+
+ // Genre tag
+ if (genreCheckbox.Checked == true)
+ {
+ tfile.Tag.Genres = new string[] { genre };
+ }
+
+ // Track Number tag
+ if (trackNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Track = UInt32.Parse(trackNumber);
+ }
+
+ // Disc Number tag
+ if (discNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Disc = UInt32.Parse(discNumber);
+ }
+
+ // Total Discs tag
+ if (discTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.DiscCount = UInt32.Parse(discTotal);
+ }
+
+ // Total Tracks tag
+ if (trackTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.TrackCount = UInt32.Parse(trackTotal);
+ }
+
+ // Comment tag
+ if (commentCheckbox.Checked == true)
+ {
+ tfile.Tag.Comment = commentTextbox.Text;
+ }
+
+ // Copyright tag
+ if (copyrightCheckbox.Checked == true)
+ {
+ tfile.Tag.Copyright = copyright;
+ }
+ // UPC tag
+ if (upcCheckbox.Checked == true)
+ {
+ // Not available on MP3 at the moment
+ }
+
+ // ISRC tag
+ if (isrcCheckbox.Checked == true)
+ {
+ TagLib.Id3v2.Tag tag = (TagLib.Id3v2.Tag)tfile.GetTag(TagTypes.Id3v2, true);
+ tag.SetTextFrame("TSRC", isrc);
+ }
+
+ // Explicit tag
+ if (explicitCheckbox.Checked == true)
+ {
+ // Not available on MP3 at the moment
+ }
+
+ // Save all selected tags to file
+ tfile.Save();
+ }
+ else
+ {
+ // If there is a version name.
+ var tfile = TagLib.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + " (" + versionNamePath + ")" + audioFileType);
+ // For custom / troublesome tags.
+ TagLib.Id3v2.Tag t = (TagLib.Id3v2.Tag)tfile.GetTag(TagLib.TagTypes.Id3v2);
+
+
+ // Saving cover art to file(s)
+ if (imageCheckbox.Checked == true)
+ {
+ // Define cover art to use for FLAC file(s)
+ TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame();
+ pic.TextEncoding = TagLib.StringType.Latin1;
+ pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg;
+ pic.Type = TagLib.PictureType.FrontCover;
+ pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + "Cover.jpg");
+
+ // Save cover art to FLAC file.
+ tfile.Tag.Pictures = new TagLib.IPicture[1] { pic };
+ tfile.Save();
+ }
+
+ // Track Title tag
+ if (trackTitleCheckbox.Checked == true)
+ {
+ tfile.Tag.Title = trackName + " (" + versionName + ")";
+ }
+
+ // Album Title tag
+ if (albumCheckbox.Checked == true)
+ {
+ tfile.Tag.Album = albumName;
+ }
+
+ // Album Artits tag
+ if (albumArtistCheckbox.Checked == true)
+ {
+ tfile.Tag.AlbumArtists = new string[] { albumArtist };
+ }
+
+ // Track Artist tag
+ if (artistCheckbox.Checked == true)
+ {
+ tfile.Tag.Performers = new string[] { performerName };
+ }
+
+ // Composer tag
+ if (composerCheckbox.Checked == true)
+ {
+ tfile.Tag.Composers = new string[] { composerName };
+ }
+
+ // Release Date tag
+ if (releaseCheckbox.Checked == true)
+ {
+ releaseDate = releaseDate.Substring(0, 4);
+ tfile.Tag.Year = UInt32.Parse(releaseDate);
+ }
+
+ // Genre tag
+ if (genreCheckbox.Checked == true)
+ {
+ tfile.Tag.Genres = new string[] { genre };
+ }
+
+ // Track Number tag
+ if (trackNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Track = UInt32.Parse(trackNumber);
+ }
+
+ // Disc Number tag
+ if (discNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Disc = UInt32.Parse(discNumber);
+ }
+
+ // Total Discs tag
+ if (discTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.DiscCount = UInt32.Parse(discTotal);
+ }
+
+ // Total Tracks tag
+ if (trackTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.TrackCount = UInt32.Parse(trackTotal);
+ }
+
+ // Comment tag
+ if (commentCheckbox.Checked == true)
+ {
+ tfile.Tag.Comment = commentTextbox.Text;
+ }
+
+ // Copyright tag
+ if (copyrightCheckbox.Checked == true)
+ {
+ tfile.Tag.Copyright = copyright;
+ }
+ // UPC tag
+ if (upcCheckbox.Checked == true)
+ {
+ // Not available on MP3 at the moment
+ }
+
+ // ISRC tag
+ if (isrcCheckbox.Checked == true)
+ {
+ TagLib.Id3v2.Tag tag = (TagLib.Id3v2.Tag)tfile.GetTag(TagTypes.Id3v2, true);
+ tag.SetTextFrame("TSRC", isrc);
+ }
+
+ // Explicit tag
+ if (explicitCheckbox.Checked == true)
+ {
+ // Not available on MP3 at the moment
+ }
+
+ // Save all selected tags to file
+ tfile.Save();
+ }
+ #endregion
+ }
+ else
+ {
+ #region FLAC Tagging
+ // Select the downloaded file to prepare for tagging.
+ // Check if there's a version name or not
+ if (versionName == null | versionName == "")
+ {
+ // If there is NOT a version name.
+ var tfile = TagLib.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + audioFileType);
+ // For custom / troublesome tags.
+ var custom = (TagLib.Ogg.XiphComment)tfile.GetTag(TagLib.TagTypes.Xiph);
+
+
+ // Saving cover art to file(s)
+ if (imageCheckbox.Checked == true)
+ {
+ // Define cover art to use for FLAC file(s)
+ TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame();
+ pic.TextEncoding = TagLib.StringType.Latin1;
+ pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg;
+ pic.Type = TagLib.PictureType.FrontCover;
+ pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + "Cover.jpg");
+
+ // Save cover art to FLAC file.
+ tfile.Tag.Pictures = new TagLib.IPicture[1] { pic };
+ tfile.Save();
+ }
+
+ // Track Title tag
+ if (trackTitleCheckbox.Checked == true)
+ {
+ tfile.Tag.Title = trackName;
+ }
+
+ // Album Title tag
+ if (albumCheckbox.Checked == true)
+ {
+ tfile.Tag.Album = albumName;
+ }
+
+ // Album Artits tag
+ if (albumArtistCheckbox.Checked == true)
+ {
+ custom.SetField("ALBUMARTIST", new string[] { albumArtist });
+ }
+
+ // Track Artist tag
+ if (artistCheckbox.Checked == true)
+ {
+ custom.SetField("ARTIST", new string[] { performerName });
+ }
+
+ // Composer tag
+ if (composerCheckbox.Checked == true)
+ {
+ custom.SetField("COMPOSER", new string[] { composerName });
+ }
+
+ // Release Date tag
+ if (releaseCheckbox.Checked == true)
+ {
+ custom.SetField("YEAR", new string[] { releaseDate });
+ }
+
+ // Genre tag
+ if (genreCheckbox.Checked == true)
+ {
+ custom.SetField("GENRE", new string[] { genre });
+ }
+
+ // Track Number tag
+ if (trackNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Track = UInt32.Parse(trackNumber);
+ }
+
+ // Disc Number tag
+ if (discNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Disc = UInt32.Parse(discNumber);
+ }
+
+ // Total Discs tag
+ if (discTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.DiscCount = UInt32.Parse(discTotal);
+ }
+
+ // Total Tracks tag
+ if (trackTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.TrackCount = UInt32.Parse(trackTotal);
+ }
+
+ // Comment tag
+ if (commentCheckbox.Checked == true)
+ {
+ custom.SetField("COMMENT", new string[] { commentTextbox.Text });
+ }
+
+ // Copyright tag
+ if (copyrightCheckbox.Checked == true)
+ {
+ custom.SetField("COPYRIGHT", new string[] { copyright });
+ }
+ // UPC tag
+ if (upcCheckbox.Checked == true)
+ {
+ custom.SetField("UPC", new string[] { upc });
+ }
+
+ // ISRC tag
+ if (isrcCheckbox.Checked == true)
+ {
+ custom.SetField("ISRC", new string[] { isrc });
+ }
+
+ // Explicit tag
+ if (explicitCheckbox.Checked == true)
+ {
+ if (advisory == "false") { custom.SetField("ITUNESADVISORY", new string[] { "0" }); } else { custom.SetField("ITUNESADVISORY", new string[] { "1" }); }
+ }
+
+ // Save all selected tags to file
+ tfile.Save();
+ }
+ else
+ {
+ // If there is a version name.
+ var tfile = TagLib.File.Create(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath + " (" + versionNamePath + ")" + audioFileType);
+ // For custom / troublesome tags.
+ var custom = (TagLib.Ogg.XiphComment)tfile.GetTag(TagLib.TagTypes.Xiph);
+
+
+ // Saving cover art to file(s)
+ if (imageCheckbox.Checked == true)
+ {
+ // Define cover art to use for FLAC file(s)
+ TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame();
+ pic.TextEncoding = TagLib.StringType.Latin1;
+ pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg;
+ pic.Type = TagLib.PictureType.FrontCover;
+ pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + albumArtistPath + "\\" + albumNamePath + "\\" + qualityPath + "\\" + "Cover.jpg");
+
+ // Save cover art to FLAC file.
+ tfile.Tag.Pictures = new TagLib.IPicture[1] { pic };
+ tfile.Save();
+ }
+
+ // Track Title tag
+ if (trackTitleCheckbox.Checked == true)
+ {
+ tfile.Tag.Title = trackName + " (" + versionName + ")";
+ }
+
+ // Album Title tag
+ if (albumCheckbox.Checked == true)
+ {
+ tfile.Tag.Album = albumName;
+ }
+
+ // Album Artits tag
+ if (albumArtistCheckbox.Checked == true)
+ {
+ custom.SetField("ALBUMARTIST", new string[] { albumArtist });
+ }
+
+ // Track Artist tag
+ if (artistCheckbox.Checked == true)
+ {
+ custom.SetField("ARTIST", new string[] { performerName });
+ }
+
+ // Composer tag
+ if (composerCheckbox.Checked == true)
+ {
+ custom.SetField("COMPOSER", new string[] { composerName });
+ }
+
+ // Release Date tag
+ if (releaseCheckbox.Checked == true)
+ {
+ custom.SetField("YEAR", new string[] { releaseDate });
+ }
+
+ // Genre tag
+ if (genreCheckbox.Checked == true)
+ {
+ custom.SetField("GENRE", new string[] { genre });
+ }
+
+ // Track Number tag
+ if (trackNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Track = UInt32.Parse(trackNumber);
+ }
+
+ // Disc Number tag
+ if (discNumberCheckbox.Checked == true)
+ {
+ tfile.Tag.Disc = UInt32.Parse(discNumber);
+ }
+
+ // Total Discs tag
+ if (discTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.DiscCount = UInt32.Parse(discTotal);
+ }
+
+ // Total Tracks tag
+ if (trackTotalCheckbox.Checked == true)
+ {
+ tfile.Tag.TrackCount = UInt32.Parse(trackTotal);
+ }
+
+ // Comment tag
+ if (commentCheckbox.Checked == true)
+ {
+ custom.SetField("COMMENT", new string[] { commentTextbox.Text });
+ }
+
+ // Copyright tag
+ if (copyrightCheckbox.Checked == true)
+ {
+ custom.SetField("COPYRIGHT", new string[] { copyright });
+ }
+ // UPC tag
+ if (upcCheckbox.Checked == true)
+ {
+ custom.SetField("UPC", new string[] { upc });
+ }
+
+ // ISRC tag
+ if (isrcCheckbox.Checked == true)
+ {
+ custom.SetField("ISRC", new string[] { isrc });
+ }
+
+ // Explicit tag
+ if (explicitCheckbox.Checked == true)
+ {
+ if (advisory == "false") { custom.SetField("ITUNESADVISORY", new string[] { "0" }); } else { custom.SetField("ITUNESADVISORY", new string[] { "1" }); }
+ }
+
+ // Save all selected tags to file
+ tfile.Save();
+ }
+ #endregion
+ }
+ #endregion
+ }
+ catch (Exception downloadError)
+ {
+ // If there is an issue trying to, or during the download, show error info.
+ string error = downloadError.ToString();
+ output.Invoke(new Action(() => output.AppendText("Track Download ERROR. Information below.\r\n\r\n")));
+ output.Invoke(new Action(() => output.AppendText(error)));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ return;
+ }
+
+ // Say that downloading is completed.
+ output.Invoke(new Action(() => output.AppendText("Track Download Done!\r\n\r\n")));
+ output.Invoke(new Action(() => output.AppendText("File will be located in your selected path.")));
+ downloadButton.Invoke(new Action(() => downloadButton.Enabled = true));
+ #endregion
+ }
+ #endregion
+
+ #region Tagging Options
+ private void tagsLabel_Click(object sender, EventArgs e)
+ {
+ if (this.Height == 572)
+ {
+ //New Height
+ this.Height = 772;
+ tagsLabel.Text = "🠉 Choose which tags to save 🠉";
+ }
+ else if (this.Height == 772)
+ {
+ //New Height
+ this.Height = 572;
+ tagsLabel.Text = "🠋 Choose which tags to save 🠋";
+ }
+
+ }
+
+ private void albumCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.albumTag = albumCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void albumArtistCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.albumArtistTag = albumArtistCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void trackTitleCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.trackTitleTag = trackTitleCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void artistCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.artistTag = artistCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void trackNumberCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.trackTag = trackTitleCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void trackTotalCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.totalTracksTag = trackTotalCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void discNumberCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.discTag = discNumberCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void discTotalCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.totalDiscsTag = discTotalCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void releaseCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.yearTag = releaseCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void genreCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.genreTag = genreCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void composerCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.composerTag = composerCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void copyrightCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.copyrightTag = copyrightCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void isrcCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.isrcTag = isrcCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void upcCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.upcTag = upcCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void explicitCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.explicitTag = explicitCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void commentCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.commentTag = commentCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void imageCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.imageTag = imageCheckbox.Checked;
+ Settings.Default.Save();
+ }
+
+ private void commentTextbox_TextChanged(object sender, EventArgs e)
+ {
+ Settings.Default.commentText = commentTextbox.Text;
+ Settings.Default.Save();
+ }
+ #endregion
+
+ #region Quality Options
+ private void flacHighCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.quality4 = flacHighCheckbox.Checked;
+ Settings.Default.Save();
+
+ if (flacHighCheckbox.Checked == true)
+ {
+ formatIdString = "27";
+ audioFileType = ".flac";
+ Settings.Default.qualityFormat = formatIdString;
+ Settings.Default.audioType = audioFileType;
+ downloadButton.Enabled = true;
+ flacMidCheckbox.Checked = false;
+ flacLowCheckbox.Checked = false;
+ mp3Checkbox.Checked = false;
+ }
+ else
+ {
+ if (flacMidCheckbox.Checked == false & flacLowCheckbox.Checked == false & mp3Checkbox.Checked == false)
+ {
+ downloadButton.Enabled = false;
+ }
+ }
+ }
+
+ private void flacMidCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.quality3 = flacMidCheckbox.Checked;
+ Settings.Default.Save();
+
+ if (flacMidCheckbox.Checked == true)
+ {
+ formatIdString = "7";
+ audioFileType = ".flac";
+ Settings.Default.qualityFormat = formatIdString;
+ Settings.Default.audioType = audioFileType;
+ downloadButton.Enabled = true;
+ flacHighCheckbox.Checked = false;
+ flacLowCheckbox.Checked = false;
+ mp3Checkbox.Checked = false;
+ }
+ else
+ {
+ if (flacHighCheckbox.Checked == false & flacLowCheckbox.Checked == false & mp3Checkbox.Checked == false)
+ {
+ downloadButton.Enabled = false;
+ }
+ }
+ }
+
+ private void flacLowCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.quality2 = flacLowCheckbox.Checked;
+ Settings.Default.Save();
+
+ if (flacLowCheckbox.Checked == true)
+ {
+ formatIdString = "6";
+ audioFileType = ".flac";
+ Settings.Default.qualityFormat = formatIdString;
+ Settings.Default.audioType = audioFileType;
+ downloadButton.Enabled = true;
+ flacHighCheckbox.Checked = false;
+ flacMidCheckbox.Checked = false;
+ mp3Checkbox.Checked = false;
+ }
+ else
+ {
+ if (flacHighCheckbox.Checked == false & flacMidCheckbox.Checked == false & mp3Checkbox.Checked == false)
+ {
+ downloadButton.Enabled = false;
+ }
+ }
+ }
+
+ private void mp3Checkbox_CheckedChanged(object sender, EventArgs e)
+ {
+ Settings.Default.quality1 = mp3Checkbox.Checked;
+ Settings.Default.Save();
+
+ if (mp3Checkbox.Checked == true)
+ {
+ formatIdString = "5";
+ audioFileType = ".mp3";
+ Settings.Default.qualityFormat = formatIdString;
+ Settings.Default.audioType = audioFileType;
+ downloadButton.Enabled = true;
+ flacHighCheckbox.Checked = false;
+ flacMidCheckbox.Checked = false;
+ flacLowCheckbox.Checked = false;
+ }
+ else
+ {
+ if (flacHighCheckbox.Checked == false & flacMidCheckbox.Checked == false & flacLowCheckbox.Checked == false)
+ {
+ downloadButton.Enabled = false;
+ }
+ }
+ }
+ #endregion
+
+ private void QobuzDownloaderX_FormClosed(object sender, FormClosedEventArgs e)
+ {
+ Application.Exit();
+ }
+ }
+}
diff --git a/QobuzDownloaderX/Form1.resx b/QobuzDownloaderX/Form1.resx
new file mode 100644
index 0000000..cadd161
--- /dev/null
+++ b/QobuzDownloaderX/Form1.resx
@@ -0,0 +1,1070 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 13, 13
+
+
+ 176, 13
+
+
+ 297, 13
+
+
+ 430, 13
+
+
+ 587, 13
+
+
+ 737, 13
+
+
+
+
+ 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
+ AP8UFBT/tra2/////////////////////////////Pz8/4SEhP8DAwP/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8NDQ3/wMDA///////e3t7/IyMj8wAAAE4AAAC2ampq////////////Y2Nj/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/1tbW//6+vr///////7+/v/q6ur/8fHx////////////4uLi/yoqKv8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wEBAf+cnJz//////+/v7/84ODj8AAAAbAoKCsl5eXn///////r6+v9PT0//AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/jo6O////////////29vb/zo6Ov9gYGD/9fX1///////7+/v/VFRU/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/4mJif//////9fX1/0VFRf4AAAB8CwsLynp6ev//////+fn5/05O
+ Tv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP+RkZH////////////X19f/Li4u/1ZWVv/09PT///////v7
+ +/9VVVX/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/iYmJ///////19fX/RUVF/gAAAHwBAQG5bW1t////
+ ///+/v7/YGBg/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/2FhYf/7+/v///////7+/v/h4eH/6urq////
+ ////////5eXl/y4uLv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP+bm5v//////+/v7/85OTn8AAAAbQAA
+ AJlRUVH/+vr6//////+FhYX/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/GBgY/8DAwP//////////////
+ //////////////////+Pj4//BAQE/wAAAP8AAAD/AAAA/wAAAP8AAAD/DAwM/76+vv//////39/f/yQk
+ JPMAAABPAAAAay0tLfvn5+f//////7u7u/8MDAz/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/MTEx/7u7
+ u//5+fn////////////x8fH/mJiY/xcXF/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8sLCz/5eXl////
+ //+8vLz/Dg4O4AAAACsAAAA2DQ0N5rq6uv//////7e3t/zs7O/8AAAD/AAAA/wAAAP8AAAD/AQEB/w4O
+ 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
+ ///////////////////9/f3/9fX1/+rq6v/c3Nz/zc3N/7y8vP+rq6v/mZmZ/4WFhf9nZ2f/Nzc3/w4O
+ Dv8AAAD8AAAA9AoKCv5/f3//9PT0/////////////////5+fn/8LCwv/AAAA6woKClwAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAGgAAAJwAAAD4JSUl/52dnf/09PT/////////////////////////
+ ///8/Pz/7u7u/9XV1f+4uLj/pKSk/5qamv+bm5v/o6Oj/7CwsP+7u7v/vr6+/7Ozs/+fn5//iIiI/3Jy
+ cv9aWlr/RkZG/y8vL/8PDw//CwsL/39/f//09PT////////////+/v7/rKys/x4eHv8AAADtAAAAaQAA
+ AAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbAAAAqQAAAP07Ozv/x8fH////////////////////
+ ////////8fHx/7y8vP93d3f/Pz8//xsbG/8NDQ3/BwcH/wQEBP8FBQX/CAgI/w8PD/8fHx//Pj4+/2Ji
+ Yv97e3v/eXl5/2JiYv9KSkr/OTk5/ycnJ/8dHR3/gYGB//T09P////////////7+/v+srKz/HR0d/wAA
+ AO0AAABpAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMAAACiAAAA/kZGRv/W1tb/////////
+ //////////////T09P+vr6//TU1N/xAQEP8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wICAv8SEhL/MjIy/0VFRf8+Pj7/LCws/yEhIf+EhIT/9fX1/////////////v7+/6ys
+ rP8dHR3/AAAA7QAAAGoAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAIYAAAD7Pz8//9jY
+ 2P//////////////////////1NTU/2BgYP8ODg7/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wsLC/8dHR3/JSUl/4eHh//19fX/////////
+ ////////rq6u/xwcHP8AAADsAAAAaQAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAA
+ APAqKir/y8vL//////////////////39/f+1tbX/MDAw/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8LCwv/goKC//X1
+ 9f/////////////////+/v7/kZGR/wcHB/8AAADOAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAmAAAA0BAQEP+oqKj//////////////////f39/6Ojo/8bGxv/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/woK
+ Cv9+fn7/9PT0////////////////////////////8fHx/1xcXP8AAAD7AAAAfgAAAAMAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAQAAACKAAAA/mtra//4+Pj/////////////////ra2t/xkZGf8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/CgoK/35+fv/09PT////////////9/f3/+fn5/////////////////9LS0v8oKCj/AAAA4gAA
+ ADcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADUAAADiJycn/9XV1f/////////////////Ly8v/KCgo/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8KCgr/fn5+//T09P////////////7+/v+srKz/fX19//Ly8v//////////////
+ //+Ojo7/BQUF/wAAAJoAAAAHAAAAAAAAAAAAAAAAAAAAAwAAAI0CAgL/goKC//7+/v///////////+7u
+ 7v9QUFD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wICAv9wcHD/9PT0/////////////v7+/62trf8dHR3/CQkJ/5yc
+ nP/////////////////k5OT/Nzc3/wAAAOYAAAA3AAAAAAAAAAAAAAAAAAAAIwAAANciIiL/1dXV////
+ /////////////5ubm/8ICAj/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/xAQEP+/v7/////////////+/v7/rq6u/x4e
+ Hv8AAAD/AAAA/y8vL//b29v/////////////////jo6O/wMDA/8AAACGAAAAAQAAAAAAAAAAAAAAYAAA
+ APlmZmb/+vr6////////////5ubm/zg4OP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AQEB/wUFBf8EBAT/AAAA/wAAAP8AAAD/AAAA/wYGBv+Tk5P//f39//z8
+ /P+tra3/Hh4e/wAAAP8AAAD/AAAA/wICAv+Dg4P//v7+////////////19fX/yIiIv8AAADMAAAAGAAA
+ AAAAAAAHAAAAoAoKCv+srKz/////////////////pKSk/wgICP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/xISEv9OTk7/h4eH/5+fn/+ZmZn/c3Nz/zIyMv8GBgb/AAAA/wAA
+ AP8aGhr/a2tr/2tra/8aGhr/AAAA/wAAAP8AAAD/AAAA/wAAAP8wMDD/4+Pj////////////+Pj4/1xc
+ XP8AAADxAAAARwAAAAAAAAAdAAAA0SQkJP/e3t7////////////39/f/WVlZ/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8BAQH/Ozs7/7W1tf/z8/P//////////////////f39/+Pj
+ 4/+FhYX/FhYW/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8JCQn/qKio////
+ /////////////5iYmP8EBAT/AAAAewAAAAAAAABCAAAA605OTv/09PT////////////d3d3/JCQk/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP9BQUH/2NjY////////////////////
+ ///////////////////7+/v/oqKi/xQUFP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/ampq//z8/P///////////8fHx/8TExP/AAAApwAAAAkAAABnAAAA9nR0dP//////////////
+ //+1tbX/DQ0N/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/x0dHf/FxcX/////////
+ ////////////////////////////////////////+/v7/3t7e/8CAgL/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/PDw8/+3t7f///////////+Xl5f8pKSn/AAAAyAAAABYGBgaEAgIC/ZKS
+ kv////////////////+SkpL/AgIC/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/2xs
+ bP/7+/v//////////////////////////////////////////////////////9jY2P8lJSX/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/Hh4e/9ra2v////////////Dw8P9DQ0P/AAAA3gAA
+ ACYUFBScBwcH/6Wlpf////////////////94eHj/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/CgoK/62trf//////////////////////3Nzc/4qKiv+mpqb/9vb2//////////////////j4
+ +P9bW1v/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/EhIS/8bGxv////////////b2
+ 9v9VVVX/AAAA6AAAADYcHBypCgoK/6+vr/////////////39/f9qamr/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/FBQU/83Nzf/////////////////4+Pj/ZWVl/wAAAP8RERH/tLS0////
+ //////////////////98fHz/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/Dw8P/7u7
+ u/////////////n5+f9fX1//AAAA6wAAAD4dHR2qCgoK/7CwsP////////////39/f9qamr/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/FRUV/87Ozv/////////////////39/f/XFxc/wAA
+ AP8MDAz/ra2t//////////////////////9+fn7/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/Dw8P/7u7u/////////////n5+f9fX1//AAAA6wAAAD4WFhafCAgI/6enp///////////////
+ //91dXX/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/DAwM/7Ozs///////////////
+ ////////0NDQ/3Fxcf+QkJD/8vLy//////////////////n5+f9gYGD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/EhIS/8bGxv////////////b29v9WVlb/AAAA6AAAADYJCQmJAwMD/peX
+ l/////////////////+NjY3/AQEB/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/3Z2
+ dv/9/f3///////////////////////39/f/+/v7//////////////////////9/f3/8rKyv/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/HR0d/9nZ2f////////////Dw8P9ERET/AAAA3gAA
+ ACcAAABsAAAA+Hp6ev////////////////+urq7/CgoK/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/yUlJf/Q0ND//////////////////////////////////////////////////v7+/4iI
+ iP8EBAT/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/OTk5/+3t7f///////////+bm
+ 5v8rKyv/AAAAyQAAABcAAABJAAAA7lVVVf/29vb////////////X19f/Hh4e/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP9SUlL/5eXl////////////////////////////////////
+ ////////tbW1/x0dHf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/ZmZm//v7
+ +////////////8nJyf8UFBT/AAAAqQAAAAoAAAAiAAAA1ysrK//j4+P////////////09PT/T09P/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wEBAf8DAwP/TU1N/8nJyf/6+vr/////////
+ /////////////+/v7/+bm5v/ISEh/wAAAP8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8HBwf/oqKi/////////////////5ycnP8FBQX/AAAAfgAAAAAAAAAKAAAAqQ0NDf+1tbX/////////
+ ////////mJiY/wUFBf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AgIC/w4ODv8WFhb/CAgI/x0d
+ Hf9kZGT/nZ2d/7W1tf+vr6//ioqK/0VFRf8MDAz/Dg4O/xcXF/8ICAj/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8qKir/3t7e////////////+fn5/2FhYf8AAADzAAAASgAAAAAAAAAAAAAAawAA
+ APxxcXH//f39////////////39/f/y8vL/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8BAQH/DAwM/x4e
+ Hv8zMzP/PDw8/ysrK/8UFBT/EBAQ/xQUFP8TExP/Dw8P/x0dHf81NTX/PDw8/ysrK/8XFxf/BgYG/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP94eHj//f39////////////3Nzc/ycnJ/8AAADQAAAAGwAA
+ AAAAAAAAAAAAKwAAAN8qKir/3d3d/////////////////42Njf8EBAT/AAAA/wAAAP8AAAD/AAAA/wEB
+ Af8KCgr/Ghoa/ywsLP8+Pj7/VFRU/2lpaf90dHT/eXl5/35+fv98fHz/d3d3/3Fxcf9hYWH/S0tL/zc3
+ N/8lJSX/ExMT/wUFBf8AAAD/AAAA/wAAAP8AAAD/AAAA/yYmJv/T09P/////////////////mJiY/wUF
+ Bf8AAACMAAAAAgAAAAAAAAAAAAAABgAAAJkEBAT/j4+P/////////////////+fn5/9DQ0P/AAAA/wAA
+ AP8AAAD/AQEB/wkJCf8XFxf/JiYm/zc3N/9JSUn/W1tb/29vb/+Ghob/n5+f/7W1tf+urq7/lJSU/3x8
+ fP9nZ2f/U1NT/0FBQf8xMTH/ICAg/xEREf8EBAT/AAAA/wAAAP8AAAD/BgYG/4yMjP/+/v7/////////
+ ///r6+v/QUFB/wAAAOoAAAA9AAAAAAAAAAAAAAAAAAAAAAAAAD8AAADqMDAw/93d3f//////////////
+ //+/v7//Hh4e/wAAAP8BAQH/BwcH/xQUFP8iIiL/MTEx/0BAQP9RUVH/YmJi/3V1df+JiYn/np6e/7Gx
+ sf+rq6v/lZWV/4GBgf9tbW3/W1tb/0pKSv86Ojr/Kysr/x0dHf8PDw//BAQE/wAAAP8AAAD/VVVV/+3t
+ 7f////////////////+dnZ3/CAgI/wAAAKQAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAcAAACYAgIC/3p6
+ ev/7+/v////////////9/f3/m5ub/xAQEP8CAgL/ERER/x8fH/8sLCz/Ojo6/0lJSf9YWFj/aWlp/3p6
+ ev+NjY3/oKCg/7Kysv+srKz/mJiY/4WFhf9zc3P/YmJi/1JSUv9DQ0P/NDQ0/ycnJ/8aGhr/CgoK/wAA
+ AP86Ojr/1tbW/////////////////9zc3P8yMjL/AAAA6AAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAvAAAA2RcXF/+3t7f/////////////////+fn5/4+Pj/8QEBD/BwcH/yMjI/82Njb/QkJC/1BQ
+ UP9fX1//bm5u/35+fv+Pj4//oqKi/7Kysv+tra3/mpqa/4iIiP94eHj/aGho/1lZWf9KSkr/PT09/zAw
+ MP8YGBj/AgIC/zc3N//MzMz/////////////////9vb2/25ubv8BAQH+AAAAjAAAAAUAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAABAAAAaAAAAPU2Njb/19fX//////////////////n5+f+dnZ3/Hx8f/wcH
+ B/8nJyf/RkZG/1hYWP9lZWX/c3Nz/4KCgv+SkpL/o6Oj/7Kysv+tra3/nJyc/4uLi/98fHz/bW1t/2Bg
+ YP9SUlL/PDw8/xgYGP8GBgb/S0tL/9LS0v/////////////////+/v7/mpqa/w0NDf8AAADGAAAAIQAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAJcAAAD9T09P/+Tk5P//////////////
+ ///9/f3/wsLC/0dHR/8JCQn/FxcX/0BAQP9iYmL/eHh4/4iIiP+Xl5f/p6en/7S0tP+wsLD/oKCg/5GR
+ kf+CgoL/cHBw/1VVVf8uLi7/CwsL/xgYGP98fHz/5+fn//////////////////////+ysrL/HBwc/wAA
+ AOMAAABFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAACzAgIC/1lZ
+ Wf/k5OT//////////////////////+rq6v+VlZX/NjY2/wwMDP8VFRX/NjY2/1paWv94eHj/kJCQ/6Cg
+ oP+bm5v/h4eH/21tbf9LS0v/Jycn/w0NDf8WFhb/Wlpa/8DAwP/5+fn//////////////////v7+/7W1
+ tf8kJCT/AAAA7wAAAGUAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAnAAAAvAICAv9OTk7/1dXV///////////////////////+/v7/5eXl/6Wlpf9dXV3/KSkp/xUV
+ Ff8RERH/FBQU/xkZGf8XFxf/EhIS/xISEv8ZGRn/PDw8/3p6ev/ExMT/9fX1////////////////////
+ ///4+Pj/oqKi/x8fH/8AAADwAAAAcgAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAJwAAALIAAAD9NDQ0/7S0tP/5+fn/////////////////////////
+ ///4+Pj/4uLi/7+/v/+goKD/jY2N/4KCgv+FhYX/k5OT/6ysrP/Pz8//7u7u//39/f//////////////
+ /////////////+fn5/97e3v/EBAQ/wAAAOkAAABrAAAABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoAAACTAAAA9BUVFf91dXX/2tra//39
+ /f//////////////////////////////////////////////////////////////////////////////
+ ///////////////////19fX/s7Oz/0JCQv8FBQX/AAAA0gAAAFAAAAAEAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAYwAA
+ ANUCAgL+Kioq/4WFhf/X19f/+vr6////////////////////////////////////////////////////
+ ////////////////////////8PDw/7e3t/9aWlr/EBAQ/wAAAPMAAACjAAAALQAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAQAAACoAAACPAAAA5AMDA/4jIyP/ZGRk/6enp//Y2Nj/8fHx//v7+///////////////
+ //////////////7+/v/39/f/6enp/8bGxv+Li4v/RUVF/w8PD/8AAAD3AAAAwQAAAFkAAAAMAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAANgAAAIsAAADWAAAA9wgICP8fHx//RERE/2Vl
+ Zf+BgYH/k5OT/5qamv+YmJj/jY2N/3Z2dv9YWFj/NDQ0/xMTE/8DAwP9AAAA7AAAALUAAABfAAAAFwAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAgAAAAWgAA
+ AJYAAADGAAAA5QAAAPEBAQH4BQUF/AcHB/0HBwf9BAQE+gAAAPUAAADsAAAA2QAAALEAAAB6AAAAOwAA
+ AA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAUCAgIWDg4OMxUVFVQYGBhsGxsbfCAgIIQeHh6CGRkZdRcXF2ITExNFCAgIJAAA
+ AA0AAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAD//4AD/48AAP/8AAB/BwAA//AAAB4DAAD/4AAABAEAAP+AAAAAAAAA/wAAAAAA
+ AAD+AAAAAAAAAPwAAAAAAQAA+AAAAAADAADwAAAAAAcAAPAAAAAADwAA4AAAAAAHAADAAAAAAAcAAMAA
+ AAAAAwAAgAAAAAADAACAAAAAAAEAAIAAAAAAAQAAAAAAAAABAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAABAAAAAAAAAAEAAIAAAAAAAQAAgAAAAAABAACAAAAAAAMAAMAAAAAAAwAAwAAAAAAH
+ AADgAAAAAAcAAOAAAAAADwAA8AAAAAAfAAD4AAAAAB8AAPwAAAAAPwAA/gAAAAB/AAD/AAAAAP8AAP+A
+ AAAD/wAA/8AAAAf/AAD/8AAAH/8AAP/8AAB//wAA//+AAf//AAAoAAAAYAAAAMAAAAABACAAAAAAAACQ
+ AAAAAAAAAAAAAAAAAAAAAAAAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAswAA
+ AHUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAA
+ 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
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAKgAAAD/AAAA/wAAAP8AAAD/e3t7/0lJ
+ Sf8AAAD/AAAA/wAAAP8AAAD/AAAAZQAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADkAAACwAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/xYW
+ Fv9TU1P/l5eX/9HR0f/29vb/////////////////////////////////////////////////////////
+ /////////////////////////v7+//b29v/i4uL/wMDA/42Njf9RUVH/Gxsb/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAC5AAAAQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAApwAA
+ AP8AAAD/AAAA/wAAAP9/f3////////Pz8/9AQED/AAAA/wAAAP8AAAD/AAAA/wAAAGUAAAAAAAAAAAAA
+ AACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiAAAAnwAAAP0AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wwMDP9TU1P/q6ur/+zs7P//////////////////////////////////////////////
+ //////////////////////////////7+/v/7+/v/+Pj4//X19f/x8fH/7Ozs/+fn5//j4+P/4eHh/+Dg
+ 4P/Y2Nj/v7+//42Njf9KSkr/ERER/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAKsAAAArAAAAAAAA
+ AAAAAAAAAAAAAAAAAAQAAACnAAAA/wAAAP8AAAD/AAAA/39/f//////////////////x8fH/QEBA/wAA
+ AP8AAAD/AAAA/wAAAP8AAABlAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAA
+ AHEAAADtAAAA/wAAAP8AAAD/AAAA/wAAAP8gICD/goKC/93d3f//////////////////////////////
+ /////////////////////////////////////////////////////////v7+//z8/P/5+fn/9vb2//Ly
+ 8v/t7e3/6Ojo/+Li4v/c3Nz/1tbW/8/Pz//Hx8f/wcHB/7+/v/+4uLj/mpqa/19fX/8eHh7/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD0AAAAfgAAAAgAAAAAAAAABAAAAKcAAAD/AAAA/wAAAP8AAAD/f39/////
+ ////////////////////////8fHx/0BAQP8AAAD/AAAA/wAAAP8AAAD/AAAAZAAAAACysrIAv7+/AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAArAAAAvgAAAP8AAAD/AAAA/wAAAP8AAAD/IyMj/5OTk//x8fH/////////
+ ////////////////////////////////////////////////////////////////////////////////
+ /////////f39//r6+v/39/f/8/Pz/+/v7//q6ur/5OTk/97e3v/Y2Nj/0dHR/8nJyf/BwcH/ubm5/7Cw
+ sP+np6f/oKCg/5ycnP+Kior/V1dX/xsbG/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAMoAAAA+AAAAoQAA
+ AP8AAAD/AAAA/wAAAP9+fn7///////////////////////////////////////Hx8f9FRUX/AQEB/wAA
+ AP8AAAD/AAAA/wAAAGaysrIDv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGEAAADwAAAA/wAAAP8AAAD/AAAA/xIS
+ Ev+FhYX/8fHx////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////9/f3/+/v7//j4+P/09PT/8PDw/+vr6//m5ub/4ODg/9ra
+ 2v/T09P/y8vL/8TExP+7u7v/s7Oz/6qqqv+goKD/lpaW/4uLi/+CgoL/fHx8/2tra/8+Pj7/DQ0N/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/35+fv//////////////////////////////
+ ///////////////////U1NT/CQkJ/wAAAP8AAAD/AAAA/wAAAPGysrIcv7+/AAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAlQAA
+ AP8AAAD/AAAA/wAAAP8AAAD/WFhY/93d3f//////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////7+/v/8/Pz/+fn5//b2
+ 9v/x8fH/7e3t/+jo6P/i4uL/29vb/9XV1f/Ozs7/xsbG/76+vv+1tbX/rKys/6Ojo/+ZmZn/jo6O/4SE
+ hP94eHj/bW1t/2JiYv9aWlr/R0dH/yEhIf8CAgL/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/fn5+////
+ /////////////////////////////////////////////+Pj4/8vLy//AAAA/wAAAP8AAAD/AAAA9AAA
+ AEaysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAABYAAAC7AAAA/wAAAP8AAAD/AAAA/xkZGf+np6f/////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////39/f/7+/v/9/f3//Dw8P/n5+f/3Nzc/9HR0f/IyMj/wMDA/7i4
+ uP+vr6//pqam/5ycnP+RkZH/h4eH/3x8fP9wcHD/ZGRk/1hYWP9MTEz/RERE/z8/P/8qKir/CgoK/wAA
+ AP8AAAD/AAAA/wAAAP9+fn7/////////////////////////////////////////////////4+Pj/ysr
+ K/8AAAD/AAAA/wAAAP8AAAD0AAAARgAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIgAAANIAAAD/AAAA/wAAAP8AAAD/R0dH/+Dg
+ 4P//////////////////////////////////////////////////////////////////////////////
+ /////////////+np6f/Gxsb/oKCg/39/f/9lZWX/UlJS/0ZGRv9DQ0P/Q0ND/01NTf9aWlr/b29v/4mJ
+ if+kpKT/vb29/8zMzP/Ozs7/w8PD/7W1tf+oqKj/n5+f/5WVlf+Kior/f39//3R0dP9oaGj/XFxc/09P
+ T/9FRUX/PT09/zU1Nf8vLy//JiYm/w8PD/8AAAD/AAAA/319ff//////////////////////////////
+ ///////////////////j4+P/Kysr/wAAAP8AAAD/AAAA/wAAAPQAAABGAAAAAAAAAACysrIAv7+/AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAA3gAA
+ AP8AAAD/AAAA/wAAAP92dnb//f39////////////////////////////////////////////////////
+ ////////////////////////9PT0/7y8vP93d3f/Ozs7/xISEv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/CwsL/ycnJ/9RUVH/fn5+/6CgoP+qqqr/n5+f/46O
+ jv+CgoL/d3d3/2xsbP9fX1//U1NT/0hISP8/Pz//ODg4/y8vL/8nJyf/ICAg/xcXF/8AAAD/fX19////
+ /////////////////////////////////////////////+Pj4/8rKyv/AAAA/wAAAP8AAAD/AAAA9AAA
+ AEYAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAACYAAADgAAAA/wAAAP8AAAD/BAQE/5qamv//////////////////////////////
+ /////////////////////////////////////////////8nJyf9ubm7/ISEh/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/w8PD/86Ojr/a2tr/4aGhv+BgYH/cHBw/2NjY/9WVlb/SkpK/0JCQv86Ojr/MjIy/yoq
+ Kv8iIiL/GBgY/wMDA/+Dg4P/////////////////////////////////////////////////4+Pj/yws
+ LP8AAAD/AAAA/wAAAP8AAAD1AAAARwAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGwAAANoAAAD/AAAA/wAAAP8KCgr/r6+v////
+ //////////////////////////////////////////////////////////////////+xsbH/RERE/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/xkZGf9ISEj/ZWVl/19f
+ X/9OTk7/RERE/zw8PP80NDT/LCws/yQkJP8aGhr/BgYG/4SEhP//////////////////////////////
+ ///////////////////j4+P/LCws/wAAAP8AAAD/AAAA/wAAAPUAAABHAAAAAAAAAAAAAAAAAAAAAAAA
+ AACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANAAAAygAA
+ AP8AAAD/AAAA/wsLC/+4uLj/////////////////////////////////////////////////////////
+ ////////urq6/z4+Pv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/EBAQ/zY2Nv9JSUn/QUFB/zY2Nv8uLi7/Jycn/xwcHP8ICAj/hISE////
+ /////////////////////////////////////////////+Tk5P8sLCz/AAAA/wAAAP8AAAD/AAAA9QAA
+ AEcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAACrAAAA/wAAAP8AAAD/BwcH/7W1tf//////////////////////////////
+ /////////////////////////////+Hh4f9bW1v/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8SEhL/MDAw/zQ0
+ NP8pKSn/Hx8f/wsLC/+FhYX/////////////////////////////////////////////////5OTk/yws
+ LP8AAAD/AAAA/wAAAP8AAAD1AAAASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHsAAAD/AAAA/wAAAP8AAAD/paWl////
+ ////////////////////////////////////////////////////////o6Oj/xcXF/8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AgIC/xkZGf8jIyP/Dg4O/4eHh///////////////////////////////
+ ///////////////////Z2dn/Kysr/wAAAP8AAAD/AAAA/wAAAOwAAABIAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQQAA
+ AP0AAAD/AAAA/wAAAP+Ghob///////////////////////////////////////////////////////f3
+ 9/9oaGj/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/iIiI////
+ //////////////////////////////////////////////////+ysrL/AAAA/wAAAP8AAAD/AAAA/wAA
+ AHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAARAAAA3gAAAP8AAAD/AAAA/1lZWf//////////////////////////////
+ ////////////////////////4uLi/z4+Pv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP96enr/////////////////////////////////////////////////////////
+ ////////gICA/wAAAP8AAAD/AAAA/wAAAOAAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACaAAAA/wAAAP8AAAD/KCgo//Hx
+ 8f/////////////////////////////////////////////////U1NT/IyMj/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/3t7e///////////////////////////////
+ /////////////////////////////////////////////0hISP8AAAD/AAAA/wAAAP8AAACsAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AEEAAAD/AAAA/wAAAP8FBQX/xsbG/////////////////////////////////////////////////9LS
+ 0v8aGhr/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/e3t7////
+ /////////////////////////////////////////////////////////////////////////////+Pj
+ 4/8VFRX/AAAA/wAAAP8AAAD/AAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAM8AAAD/AAAA/wAAAP95eXn/////////////////////////
+ ////////////////////////29vb/x0dHf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP96enr/////////////////////////////////////////////////////////
+ //////////////////////////////////+kpKT/AAAA/wAAAP8AAAD/AAAA3gAAAAwAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZgAAAP8AAAD/AAAA/ycn
+ J//29vb////////////////////////////////////////////t7e3/Kysr/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/3p6ev//////////////////////////////
+ ////////////////////////////////////////////////////////////////////////SkpK/wAA
+ AP8AAAD/AAAA/wAAAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAA
+ AAAAAAANAAAA4gAAAP8AAAD/AAAA/7Kysv////////////////////////////////////////////7+
+ /v9LS0v/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/enp6////
+ /////////////////////////////////////////////+Li4v9bW1v/7Ozs////////////////////
+ ////////////////////////19fX/wkJCf8AAAD/AAAA/wAAAO4AAAAYAAAAAAAAAAAAAAAAAAAAAAAA
+ AACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAABwAAAA/wAAAP8AAAD/RERE////////////////////
+ /////////////////////////////4ODg/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP96enr/////////////////////////////////////////////////5eXl/y4u
+ Lv8AAAD/WFhY/////////////////////////////////////////////////3Fxcf8AAAD/AAAA/wAA
+ AP8AAACHAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAoAAADfAAAA/wAA
+ AP8BAQH/xcXF////////////////////////////////////////////x8fH/wQEBP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/3h4eP//////////////////////////////
+ ///////////////////l5eX/Li4u/wAAAP8AAAD/AAAA/5+fn///////////////////////////////
+ /////////////+fn5/8RERH/AAAA/wAAAP8AAADtAAAAFAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAA
+ AAAAAAAAAAAAAAAAAFsAAAD/AAAA/wAAAP9HR0f/////////////////////////////////////////
+ ///5+fn/MDAw/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/Q0ND////
+ /////////////////////////////////////////////+Xl5f8uLi7/AAAA/wAAAP8AAAD/AAAA/xMT
+ E//l5eX///////////////////////////////////////////93d3f/AAAA/wAAAP8AAAD/AAAAcwAA
+ AAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAMMAAAD/AAAA/wAAAP+6urr/////////
+ //////////////////////////////////+NjY3/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/pKSk////////////////////////////////////////////5eXl/y4u
+ Lv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP9dXV3/////////////////////////////////////////
+ ///i4uL/DAwM/wAAAP8AAAD/AAAA2AAAAAUAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAALwAA
+ AP0AAAD/AAAA/y8vL//9/f3//////////////////////////////////////+np6f8TExP/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/ubm5////////////////////
+ ///////////////////m5ub/Li4u/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8CAgL/yMjI////
+ ////////////////////////////////////////Xl5e/wAAAP8AAAD/AAAA/wAAAEUAAAAAAAAAAAAA
+ AACysrIAv7+/AAAAAAAAAAAAAAAAhwAAAP8AAAD/AAAA/5GRkf//////////////////////////////
+ /////////////3l5ef8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/hoaG/////////////////////////////////+bm5v8vLy//AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/R0dH////////////////////////////////////////////w8PD/wAA
+ AP8AAAD/AAAA/wAAAKEAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAEAAAA1wAAAP8AAAD/CwsL/+Tk
+ 5P//////////////////////////////////////6+vr/xISEv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/Gxsb/+Pj4///////////////////////5eXl/y8v
+ L/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/8fHx///////////////
+ /////////////////////////Pz8/ywsLP8AAAD/AAAA/wAAAOkAAAAOAAAAAAAAAACysrIAv7+/AAAA
+ AAAAAAAzAAAA/wAAAP8AAAD/SkpK////////////////////////////////////////////jY2N/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8QEBD/MjIy/01N
+ Tf9XV1f/T09P/zg4OP8XFxf/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/ygo
+ KP+wsLD/6+vr/+vr6/+wsLD/Jycn/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/1lZWf///////////////////////////////////////////39/f/8AAAD/AAAA/wAA
+ AP8AAABKAAAAAAAAAACysrIAv7+/AAAAAAAAAAB5AAAA/wAAAP8AAAD/mpqa////////////////////
+ ///////////////////8/Pz/LCws/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8HBwf/VlZW/6+vr//n5+f////////////////////////////u7u7/vLy8/2hoaP8SEhL/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/EhIS/xISEv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wsLC//j4+P/////////////////////////
+ /////////////8zMzP8BAQH/AAAA/wAAAP8AAACUAAAAAAAAAACysrIAv7+/AAAAAAAAAAC8AAAA/wAA
+ AP8GBgb/29vb///////////////////////////////////////ExMT/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/1NTU//R0dH/////////////////////////////////////////
+ ///////////////////i4uL/bGxs/wEBAf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP+RkZH///////////////////////////////////////r6+v8lJSX/AAAA/wAAAP8AAADSAAAAAgAA
+ AACysrIAv7+/AAAAABAAAADsAAAA/wAAAP8uLi7//v7+////////////////////////////////////
+ //9xcXH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8ICAj/mpqa////////////////////
+ /////////////////////////////////////////////////////////////7e3t/8ZGRn/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP89PT3/////////////////////////////////////////
+ //9hYWH/AAAA/wAAAP8AAAD5AAAAIQAAAACysrIAv7+/AAAAADgAAAD/AAAA/wAAAP9mZmb/////////
+ //////////////////////////////z8/P8rKyv/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wwM
+ DP+6urr/////////////////////////////////////////////////////////////////////////
+ ///////////////////X19f/ISEh/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8ICAj/4eHh////
+ //////////////////////////////////+enp7/AAAA/wAAAP8AAAD/AAAAUAAAAACysrIAv7+/AAAA
+ AGYAAAD/AAAA/wAAAP+dnZ3//////////////////////////////////////9fX1/8DAwP/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AgIC/7Gxsf//////////////////////////////////////////////
+ ////////////////////////////////////////////////////////0tLS/xEREf8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/pqam///////////////////////////////////////Q0ND/AQEB/wAA
+ AP8AAAD/AAAAgQAAAACysrIAv7+/AAAAAJIAAAD/AAAA/wAAAP/Jycn/////////////////////////
+ /////////////6Ghof8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/enp6////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ /////////////6Wlpf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/aWlp////////////////////
+ ///////////////////x8fH/FxcX/wAAAP8AAAD/AAAArQAAAACysrIAv7+/AAAAALYAAAD/AAAA/w8P
+ D//p6en//////////////////////////////////////2xsbP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8lJSX/9/f3////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////9JSUn/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/ODg4////////////////////////////////////////////NjY2/wAAAP8AAAD/AAAAzwAA
+ AAGysrIAv7+/AwAAANEAAAD/AAAA/ycnJ//8/Pz//////////////////////////////////////0FB
+ Qf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP+cnJz/////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ///Hx8f/AgIC/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/FhYW//Hx8f//////////////////////////////
+ ////////VlZW/wAAAP8AAAD/AAAA5wAAAA2ysrIAv7+/EgAAAOQAAAD/AAAA/0BAQP//////////////
+ ////////////////////////+vr6/yMjI/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/xcXF//x8fH/////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////ODg4/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AwMD/9fX
+ 1///////////////////////////////////////dHR0/wAAAP8AAAD/AAAA9wAAAB6ysrIAv7+/IQAA
+ APEAAAD/AAAA/1dXV///////////////////////////////////////6enp/w8PD/8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/1paWv////////////////////////////////////////////////////////////z8
+ /P/k5OT/9vb2////////////////////////////////////////////////////////////iIiI/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/7+/v///////////////////////////////////////jIyM/wAA
+ AP8AAAD/AAAA/wAAAC6ysrIAv7+/LwAAAPkAAAD/AAAA/2lpaf//////////////////////////////
+ ////////2dnZ/wQEBP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/5eXl///////////////////////////////
+ ////////////////////////tLS0/y8vL/8MDAz/IiIi/5aWlv//////////////////////////////
+ ////////////////////////w8PD/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/6qqqv//////////////
+ ////////////////////////np6e/wAAAP8AAAD/AAAA/wAAADuysrIAv7+/OgAAAP0AAAD/AAAA/3V1
+ df//////////////////////////////////////zMzM/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/76+
+ vv/////////////////////////////////////////////////S0tL/BwcH/wAAAP8AAAD/AAAA/wAA
+ AP+tra3/////////////////////////////////////////////////4uLi/woKCv8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/5ycnP//////////////////////////////////////qqqq/wAAAP8AAAD/AAAA/wAA
+ AEWysrIAv7+/PwAAAP8AAAD/AAAA/319ff//////////////////////////////////////xcXF/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/9DQ0P//////////////////////////////////////////////
+ //93d3f/AAAA/wAAAP8AAAD/AAAA/wAAAP9JSUn/////////////////////////////////////////
+ ////////8PDw/xYWFv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/5SUlP//////////////////////////////
+ ////////r6+v/wAAAP8AAAD/AAAA/wAAAEqysrIAv7+/QAAAAP8AAAD/AAAA/35+fv//////////////
+ ////////////////////////xMTE/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/9LS0v//////////////
+ //////////////////////////////////9tbW3/AAAA/wAAAP8AAAD/AAAA/wAAAP9AQED/////////
+ ////////////////////////////////////////8fHx/xgYGP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/5SU
+ lP//////////////////////////////////////sLCw/wAAAP8AAAD/AAAA/wAAAEqysrIAv7+/PQAA
+ AP4AAAD/AAAA/3l5ef//////////////////////////////////////ycnJ/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/8XFxf////////////////////////////////////////////////+7u7v/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP+QkJD/////////////////////////////////////////////////5+fn/w0N
+ Df8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/5ubm///////////////////////////////////////qqqq/wAA
+ AP8AAAD/AAAA/wAAAEWysrIAv7+/NAAAAPsAAAD/AAAA/25ubv//////////////////////////////
+ ////////1NTU/wEBAf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/6SkpP//////////////////////////////
+ ////////////////////////hISE/woKCv8AAAD/AgIC/2JiYv/6+vr/////////////////////////
+ ////////////////////////zMzM/wEBAf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/6mpqf//////////////
+ ////////////////////////n5+f/wAAAP8AAAD/AAAA/wAAADyysrIAv7+/JwAAAPQAAAD/AAAA/15e
+ Xv//////////////////////////////////////4+Pj/wsLC/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/2xs
+ bP///////////////////////////////////////////////////////////9vb2/+1tbX/0NDQ////
+ ////////////////////////////////////////////////////////mJiY/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/729vf//////////////////////////////////////jY2N/wAAAP8AAAD/AAAA/wAA
+ AC+ysrIAv7+/GAAAAOoAAAD/AAAA/0lJSf//////////////////////////////////////9PT0/xsb
+ G/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/yYmJv/7+/v/////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////S0tL/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AgIC/9XV1f//////////////////////////////
+ ////////dnZ2/wAAAP8AAAD/AAAA+AAAAB+ysrIAv7+/BwAAANkAAAD/AAAA/zExMf//////////////
+ /////////////////////////////zU1Nf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP+4uLj/////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////d3d3/CQkJ/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/FBQU/+7u
+ 7v//////////////////////////////////////WVlZ/wAAAP8AAAD/AAAA6AAAAA6ysrIAv7+/AAAA
+ AMEAAAD/AAAA/xgYGP/y8vL//////////////////////////////////////1xcXP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP9AQED/////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////9paWn/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/MzMz////////////////////////////////////////////OTk5/wAA
+ AP8AAAD/AAAA0QAAAAGysrIAv7+/AAAAAKAAAAD/AAAA/wMDA//X19f/////////////////////////
+ /////////////4+Pj/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/oqKi////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ /////////////8nJyf8FBQX/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/YmJi////////////////////
+ ///////////////////09PT/Ghoa/wAAAP8AAAD/AAAAsAAAAACysrIAv7+/AAAAAHYAAAD/AAAA/wAA
+ AP+vr6///////////////////////////////////////8bGxv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/EhIS/9fX1///////////////////////////////////////////////////////////////
+ ////////////////////////////////////////8PDw/yoqKv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/nJyc///////////////////////////////////////U1NT/AgIC/wAAAP8AAAD/AAAAhgAA
+ AACysrIAv7+/AAAAAEgAAAD/AAAA/wAAAP96enr///////////////////////////////////////T0
+ 9P8aGhr/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/ycnJ//h4eH/////////////////////////
+ ///////////////////////////////////////////////////////////////////19fX/RkZG/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8EBAT/2NjY////////////////////////////////////
+ //+lpaX/AAAA/wAAAP8AAAD/AAAAVQAAAACysrIAv7+/AAAAABwAAAD2AAAA/wAAAP9BQUH/////////
+ //////////////////////////////////9ZWVn/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8lJSX/y8vL////////////////////////////////////////////////////////////////////
+ /////////////+Hh4f8+Pj7/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8xMTH//v7+////
+ //////////////////////////////////9paWn/AAAA/wAAAP8AAAD7AAAAJgAAAACysrIAv7+/AAAA
+ AAEAAADPAAAA/wAAAP8QEBD/6+vr//////////////////////////////////////+srKz/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8DAwP/AAAA/wAAAP8AAAD/CwsL/4qKiv/29vb/////////////////////////
+ ////////////////////////////////////////oqKi/xoaGv8AAAD/AAAA/wAAAP8EBAT/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP9/f3////////////////////////////////////////39/f8tLS3/AAAA/wAA
+ AP8AAADYAAAABAAAAACysrIAv7+/AAAAAAAAAACRAAAA/wAAAP8AAAD/srKy////////////////////
+ ///////////////////y8vL/GBgY/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wQEBP8PDw//ExMT/wMDA/8AAAD/AAAA/wAA
+ AP8qKir/kJCQ/9/f3///////////////////////////////////////6Ojo/6CgoP85OTn/AAAA/wAA
+ AP8AAAD/AQEB/xISEv8SEhL/BgYG/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wQEBP/V1dX/////////////////////////
+ /////////////9bW1v8EBAT/AAAA/wAAAP8AAACcAAAAAAAAAACysrIAv7+/AAAAAAAAAABKAAAA/wAA
+ AP8AAAD/Y2Nj////////////////////////////////////////////cHBw/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AwMD/w0N
+ Df8XFxf/JCQk/ygoKP8PDw//AAAA/wAAAP8AAAD/AAAA/wsLC/86Ojr/Z2dn/4aGhv+RkZH/iYmJ/25u
+ bv9DQ0P/EhIS/wAAAP8AAAD/AAAA/wAAAP8LCwv/JSUl/ycnJ/8aGhr/Dw8P/wUFBf8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/0JC
+ Qv///////////////////////////////////////////46Ojv8AAAD/AAAA/wAAAP8AAABUAAAAAAAA
+ AACysrIAv7+/AAAAAAAAAAAPAAAA6QAAAP8AAAD/Ghoa//T09P//////////////////////////////
+ ////////19fX/wUFBf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8DAwP/DAwM/xUVFf8gICD/Kioq/zY2Nv9AQED/Li4u/w0NDf8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/CQkJ/ykpKf9AQED/OTk5/yws
+ LP8iIiL/GBgY/w4ODv8FBQX/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/66urv///////////////////////////////////////////zs7
+ O/8AAAD/AAAA/wAAAPAAAAAVAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAowAAAP8AAAD/AAAA/62t
+ rf///////////////////////////////////////////1hYWP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wICAv8LCwv/FBQU/x0dHf8nJyf/MDAw/zs7
+ O/9GRkb/VVVV/1lZWf9ERET/IyMj/woKCv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/BwcH/x8f
+ H/9AQED/WFhY/1hYWP9JSUn/PT09/zMzM/8pKSn/Hx8f/xYWFv8NDQ3/BAQE/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/LS0t//v7+///////////////
+ ////////////////////////1NTU/wQEBP8AAAD/AAAA/wAAAK4AAAAAAAAAAAAAAACysrIAv7+/AAAA
+ AAAAAAAAAAAASAAAAP8AAAD/AAAA/0pKSv///////////////////////////////////////////9PT
+ 0/8FBQX/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AgIC/woK
+ Cv8SEhL/Gxsb/yQkJP8tLS3/Nzc3/0FBQf9LS0v/VVVV/2JiYv9ycnL/fX19/3p6ev9vb2//YWFh/1lZ
+ Wf9XV1f/WFhY/19fX/9sbGz/eXl5/35+fv91dXX/ZWVl/1hYWP9NTU3/Q0ND/zk5Of8vLy//JiYm/x0d
+ Hf8UFBT/DAwM/wQEBP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/qamp////////////////////////////////////////////dXV1/wAAAP8AAAD/AAAA/wAA
+ AFMAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAABwAAANwAAAD/AAAA/wUFBf/V1dX/////////
+ //////////////////////////////////9oaGj/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8CAgL/CQkJ/xEREf8ZGRn/IiIi/yoqKv8zMzP/PDw8/0ZGRv9QUFD/Wlpa/2Vl
+ Zf9wcHD/e3t7/4qKiv+ampr/qqqq/7m5uf/BwcH/vLy8/62trf+dnZ3/jY2N/35+fv9ycnL/Z2dn/1xc
+ XP9SUlL/SEhI/z4+Pv81NTX/LCws/yQkJP8bGxv/ExMT/wsLC/8DAwP/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP86Ojr//v7+////////////////////////////////////
+ ///x8fH/GRkZ/wAAAP8AAAD/AAAA5AAAAAsAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAA
+ AHoAAAD/AAAA/wAAAP9nZ2f////////////////////////////////////////////p6en/FxcX/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wICAv8ICAj/EBAQ/xgYGP8gICD/KCgo/zAw
+ MP85OTn/QkJC/0tLS/9UVFT/Xl5e/2hoaP9zc3P/fn5+/4mJif+VlZX/oqKi/6+vr/+2trb/sbGx/6Sk
+ pP+Xl5f/i4uL/4CAgP91dXX/ampq/2BgYP9WVlb/TU1N/0NDQ/87Ozv/MjIy/yoqKv8iIiL/GRkZ/xIS
+ Ev8KCgr/AwMD/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wMDA//Jycn/////////
+ //////////////////////////////////+Wlpb/AAAA/wAAAP8AAAD/AAAAhgAAAAAAAAAAAAAAAAAA
+ AACysrIAv7+/AAAAAAAAAAAAAAAAAAAAABkAAADxAAAA/wAAAP8LCwv/39/f////////////////////
+ ////////////////////////pKSk/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEB/wgI
+ CP8PDw//FhYW/x4eHv8lJSX/LS0t/zU1Nf8+Pj7/RkZG/09PT/9ZWVn/YmJi/2xsbP92dnb/gICA/4yM
+ jP+Xl5f/o6Oj/6+vr/+2trb/sbGx/6Wlpf+ZmZn/jY2N/4KCgv94eHj/bm5u/2RkZP9aWlr/UVFR/0hI
+ SP9AQED/Nzc3/y8vL/8nJyf/ICAg/xgYGP8RERH/CQkJ/wMDA/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/3R0dP////////////////////////////////////////////f39/8kJCT/AAAA/wAA
+ AP8AAAD3AAAAIQAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAACRAAAA/wAA
+ AP8AAAD/ZWVl/////////////////////////////////////////////////1paWv8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8BAQH/BwcH/w4ODv8VFRX/HBwc/yMjI/8rKyv/MjIy/zo6Ov9CQkL/S0tL/1NT
+ U/9cXFz/ZWVl/29vb/95eXn/g4OD/42Njf+YmJj/o6Oj/6+vr/+2trb/sbGx/6ampv+ampr/j4+P/4WF
+ hf96enr/cXFx/2dnZ/9eXl7/VVVV/0xMTP9ERET/PDw8/zQ0NP8sLCz/JSUl/x4eHv8WFhb/EBAQ/wkJ
+ Cf8CAgL/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/MDAw//b29v//////////////////////////////
+ /////////////5WVlf8AAAD/AAAA/wAAAP8AAACfAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAfAAAA9AAAAP8AAAD/BgYG/9HR0f//////////////////////////////
+ /////////////+/v7/8oKCj/AAAA/wAAAP8AAAD/AAAA/wEBAf8HBwf/DQ0N/xQUFP8aGhr/IiIi/ykp
+ Kf8wMDD/Nzc3/z8/P/9HR0f/T09P/1dXV/9gYGD/aWlp/3Jycv97e3v/hYWF/4+Pj/+ZmZn/pKSk/7Cw
+ sP+2trb/sbGx/6ampv+bm5v/kZGR/4eHh/99fX3/c3Nz/2pqav9hYWH/WVlZ/1BQUP9ISEj/QEBA/zk5
+ Of8xMTH/Kioq/yMjI/8cHBz/FRUV/w8PD/8ICAj/AgIC/wAAAP8AAAD/AAAA/wAAAP8ODg7/09PT////
+ ////////////////////////////////////////7+/v/xoaGv8AAAD/AAAA/wAAAPkAAAAoAAAAAAAA
+ AAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAigAAAP8AAAD/AAAA/0RE
+ RP/////////////////////////////////////////////////S0tL/EBAQ/wAAAP8AAAD/AAAA/wYG
+ Bv8NDQ3/EhIS/xkZGf8gICD/JiYm/y0tLf80NDT/PDw8/0NDQ/9LS0v/UlJS/1tbW/9jY2P/a2tr/3R0
+ dP99fX3/h4eH/5GRkf+ampr/paWl/7CwsP+2trb/srKy/6enp/+cnJz/kpKS/4mJif9/f3//dnZ2/21t
+ bf9lZWX/XFxc/1RUVP9MTEz/RUVF/z09Pf82Njb/Ly8v/ygoKP8hISH/Gxsb/xQUFP8ODg7/CAgI/wEB
+ Af8AAAD/AAAA/wAAAP+srKz/////////////////////////////////////////////////cnJy/wAA
+ AP8AAAD/AAAA/wAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAEwAAAOgAAAD/AAAA/wAAAP+goKD/////////////////////////////////////////
+ ////////t7e3/wYGBv8AAAD/AAAA/wMDA/8RERH/GRkZ/x4eHv8lJSX/Kysr/zIyMv85OTn/QEBA/0dH
+ R/9OTk7/VlZW/15eXv9mZmb/bm5u/3d3d/9/f3//iYmJ/5KSkv+cnJz/pqam/7CwsP+2trb/srKy/6io
+ qP+dnZ3/lJSU/4qKiv+BgYH/eHh4/3BwcP9oaGj/YGBg/1hYWP9QUFD/SEhI/0FBQf86Ojr/MzMz/yws
+ LP8mJib/ICAg/xoaGv8TExP/BQUF/wAAAP8AAAD/AAAA/4+Pj///////////////////////////////
+ ///////////////////Ly8v/BQUF/wAAAP8AAAD/AAAA7wAAABsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGMAAAD/AAAA/wAAAP8UFBT/4+Pj////
+ /////////////////////////////////////////////6ioqP8DAwP/AAAA/wAAAP8EBAT/GRkZ/yUl
+ Jf8pKSn/Ly8v/zY2Nv89PT3/RERE/0pKSv9SUlL/WVlZ/2FhYf9paWn/cXFx/3l5ef+BgYH/ioqK/5OT
+ k/+dnZ3/pqam/7CwsP+2trb/srKy/6ioqP+enp7/lZWV/4yMjP+Dg4P/e3t7/3Jycv9qamr/YmJi/1tb
+ W/9TU1P/TExM/0VFRf8+Pj7/Nzc3/zExMf8qKir/JiYm/x0dHf8HBwf/AAAA/wAAAP8AAAD/goKC////
+ //////////////////////////////////////////////n5+f8zMzP/AAAA/wAAAP8AAAD/AAAAcwAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAEAAAC+AAAA/wAAAP8AAAD/SEhI////////////////////////////////////////////////////
+ //+pqan/BwcH/wAAAP8AAAD/AwMD/xwcHP8wMDD/NDQ0/zo6Ov9AQED/R0dH/05OTv9VVVX/XV1d/2Rk
+ ZP9ra2v/c3Nz/3t7e/+Dg4P/jIyM/5SUlP+enp7/p6en/7CwsP+2trb/srKy/6ioqP+fn5//lpaW/42N
+ jf+FhYX/fX19/3V1df9tbW3/ZWVl/15eXv9XV1f/T09P/0hISP9CQkL/Ozs7/zU1Nf8yMjL/ISEh/wYG
+ Bv8AAAD/AAAA/wAAAP+Hh4f//////////////////////////////////////////////////////3V1
+ df8AAAD/AAAA/wAAAP8AAADLAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnAAAA8wAAAP8AAAD/AAAA/4ODg///////////////
+ ////////////////////////////////////////uLi4/xQUFP8AAAD/AAAA/wAAAP8WFhb/NjY2/0FB
+ Qf9ERET/SkpK/1FRUf9YWFj/X19f/2ZmZv9ubm7/dXV1/319ff+FhYX/jY2N/5aWlv+enp7/p6en/7Cw
+ sP+2trb/srKy/6mpqf+goKD/l5eX/4+Pj/+Hh4f/fn5+/3d3d/9vb2//aGho/2FhYf9aWlr/U1NT/0xM
+ TP9FRUX/QkJC/zo6Ov8cHBz/AgIC/wAAAP8AAAD/BgYG/5ubm///////////////////////////////
+ ////////////////////////r6+v/wAAAP8AAAD/AAAA/wAAAPkAAAAzAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZwAA
+ AP8AAAD/AAAA/wICAv+ysrL//////////////////////////////////////////////////////9TU
+ 1P8xMTH/AAAA/wAAAP8AAAD/CgoK/y4uLv9KSkr/UVFR/1RUVP9bW1v/YmJi/2lpaf9wcHD/d3d3/39/
+ f/+Hh4f/j4+P/5eXl/+fn5//qKio/7Gxsf+2trb/srKy/6mpqf+hoaH/mJiY/5CQkP+IiIj/gICA/3l5
+ ef9ycnL/ampq/2NjY/9cXFz/VlZW/1JSUv9NTU3/NTU1/w8PD/8AAAD/AAAA/wAAAP8eHh7/vb29////
+ ///////////////////////////////////////////////////V1dX/ERER/wAAAP8AAAD/AAAA/wAA
+ AHcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKUAAAD/AAAA/wAAAP8QEBD/zs7O////////////////////
+ ///////////////////////////////////y8vL/ZmZm/wAAAP8AAAD/AAAA/wAAAP8WFhb/Pz8//1tb
+ W/9jY2P/ZmZm/2tra/9ycnL/eXl5/4GBgf+IiIj/kJCQ/5iYmP+goKD/qKio/7Gxsf+2trb/srKy/6qq
+ qv+hoaH/mZmZ/5GRkf+Kior/goKC/3t7e/90dHT/bW1t/2ZmZv9kZGT/XV1d/0VFRf8dHR3/AQEB/wAA
+ AP8AAAD/AAAA/1BQUP/k5OT//////////////////////////////////////////////////////+np
+ 6f8oKCj/AAAA/wAAAP8AAAD/AAAAtAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAADRAAAA/wAA
+ AP8AAAD/Hh4e/9zc3P///////////////////////////////////////////////////////////66u
+ rv8lJSX/AAAA/wAAAP8AAAD/AAAA/xoaGv9DQ0P/ZGRk/3R0dP96enr/fX19/4KCgv+JiYn/kZGR/5mZ
+ mf+hoaH/qamp/7Gxsf+2trb/srKy/6qqqv+ioqL/mpqa/5KSkv+Li4v/hISE/35+fv96enr/dnZ2/2ho
+ aP9JSUn/ICAg/wICAv8AAAD/AAAA/wAAAP8YGBj/mpqa////////////////////////////////////
+ ////////////////////////8vLy/zo6Ov8AAAD/AAAA/wAAAP8AAADbAAAAFQAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAlAAAA6QAAAP8AAAD/AAAA/ycnJ//g4OD/////////////////////////
+ ///////////////////////////////////w8PD/fX19/xAQEP8AAAD/AAAA/wAAAP8AAAD/Dw8P/zIy
+ Mv9YWFj/dnZ2/4mJif+UlJT/mpqa/5+fn/+mpqb/rKys/7S0tP+5ubn/tbW1/62trf+np6f/oKCg/5ub
+ m/+VlZX/i4uL/3p6ev9eXl7/ODg4/xMTE/8AAAD/AAAA/wAAAP8AAAD/CAgI/2tra//k5OT/////////
+ ///////////////////////////////////////////////////z8/P/Q0ND/wAAAP8AAAD/AAAA/wAA
+ APAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPQAAAPUAAAD/AAAA/wAA
+ AP8nJyf/2tra/////////////////////////////////////////////////////////////////9/f
+ 3/9ycnL/FBQU/wAAAP8AAAD/AAAA/wAAAP8AAAD/DQ0N/ycnJ/9FRUX/YmJi/3t7e/+Ojo7/nZ2d/6qq
+ qv+vr6//q6ur/6Ghof+SkpL/f39//2dnZ/9LS0v/LCws/xEREf8AAAD/AAAA/wAAAP8AAAD/AAAA/wwM
+ DP9jY2P/09PT/////////////////////////////////////////////////////////////////+7u
+ 7v9BQUH/AAAA/wAAAP8AAAD/AAAA+gAAAEkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAE0AAAD5AAAA/wAAAP8AAAD/Hh4e/8rKyv//////////////////////////////
+ ////////////////////////////////////////5ubm/4+Pj/80NDT/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8GBgb/Dg4O/xQUFP8UFBT/FBQU/w8PD/8HBwf/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8qKir/gYGB/93d3f//////////////////////////////////////////////
+ ////////////////////////39/f/zMzM/8AAAD/AAAA/wAAAP8AAAD9AAAAWAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSAAAA+QAAAP8AAAD/AAAA/w8P
+ D/+rq6v/////////////////////////////////////////////////////////////////////////
+ ////////y8vL/4GBgf89PT3/Dw8P/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/woKCv80NDT/dnZ2/8HBwf/6+vr/////////////////////////
+ ///////////////////////////////////////////////////CwsL/Hh4e/wAAAP8AAAD/AAAA/wAA
+ APwAAABdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAATAAAAPMAAAD/AAAA/wAAAP8AAAD/fX19//39/f//////////////////////////////
+ ////////////////////////////////////////////////////////5ubm/7u7u/+NjY3/ZGRk/0VF
+ Rf8vLy//ISEh/xkZGf8WFhb/GBgY/x8fH/8sLCz/QEBA/15eXv+FhYX/s7Oz/+Dg4P//////////////
+ /////////////////////////////////////////////////////////////////////////////5SU
+ lP8ICAj/AAAA/wAAAP8AAAD/AAAA9wAAAFUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADsAAADkAAAA/wAAAP8AAAD/AAAA/0RE
+ RP/Y2Nj/////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////+Pj4//Hx8f/v7+//8PDw//b29v/+/v7/////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ///////////////////l5eX/V1dX/wAAAP8AAAD/AAAA/wAAAP8AAADpAAAAQgAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAkAAAAyAAAAP8AAAD/AAAA/wAAAP8RERH/kpKS//39/f//////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////6Ojo/8cHBz/AAAA/wAAAP8AAAD/AAAA/wAA
+ AM0AAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAJsAAAD/AAAA/wAAAP8AAAD/AAAA/zs7
+ O/++vr7/////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////Ly8v/SUlJ/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAAnwAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAABeAAAA6gAAAP8AAAD/AAAA/wAAAP8AAAD/VVVV/8rKyv//////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////1NTU/2JiYv8EBAT/AAAA/wAAAP8AAAD/AAAA/wAAAOwAAABhAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIQAAAKwAAAD/AAAA/wAAAP8AAAD/AAAA/wMD
+ A/9RUVH/u7u7//7+/v//////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ /////////////////////////////8XFxf9dXV3/CAgI/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAArgAA
+ ACMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAABUAAAA1QAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/zMzM/+NjY3/3Nzc////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////+Pj4/+YmJj/PT09/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAANYAAABVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAHMAAADiAAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/CQkJ/0JCQv+Li4v/zMzM//b29v//////////////////////////////////////////////
+ ////////////////////////////////////////////////////////+vr6/9PT0/+VlZX/S0tL/w8P
+ D/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADiAAAAcwAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAASAAAAdAAAANoAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/yAgIP9PT0//gYGB/6ys
+ rP/Ozs7/5ubm//b29v//////////////////////////////////////+Pj4/+rq6v/T09P/s7Oz/4iI
+ iP9XV1f/Jycn/wMDA/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA2gAAAHQAAAATAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAv7+/AAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAABZAAAAugAAAPoAAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/Dg4O/x8fH/8uLi7/Ojo6/0JCQv9GRkb/RERE/z09
+ Pf8xMTH/IiIi/xEREf8CAgL/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA+gAA
+ ALoAAABaAAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AACysrIAv7+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAACoAAAB5AAAAxgAAAPgAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA+QAAAMcAAAB6AAAAKwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysrIAvr6+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACUAAABhAAAAoAAA
+ ANMAAAD1AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/AAAA/wAAAP8AAAD2AAAA1AAAAKIAAABjAAAAJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwsLAAyMjIACIi
+ IgAiIiIAIiIiACIiIgAiIiIAIiIiACIiIgAiIiIAIiIiACIiIgAiIiIAIiIiACIiIgAiIiIAIiIiACIi
+ IgAiIiIAIiIiACIiIgAiIiIAIiIiACIiIgAiIiIAIiIiACIiIgAiIiIAIiIiACIiIgAiIiIAIiIiACIi
+ IgAiIiIAIiIiACIiIgAiIiIAIiIiACIiIgIiIiIeIiIiQSIiImciIiKJIiIipiIiIrwiIiLLIiIi1SIi
+ ItsiIiLdIiIi3CIiItYiIiLMIiIivSIiIqgiIiKLIiIiaSIiIkMiIiIfIiIiAyIiIgAiIiIAIiIiACIi
+ IgAiIiIAIiIiACIiIgAiIiIAIiIiACIiIgAiIiIAIiIiACIiIgAiIiIAIiIiACIiIgAiIiIAIiIiACIi
+ IgAiIiIAIiIiACIiIgAiIiIAIiIiACIiIgAiIiIAIiIiACIiIgAiIiIAIiIiACIiIgAiIiIAIiIiACIi
+ IgAiIiIAIiIiACIiIgC9vb0A/Pz8APT09AD09PQA9PT0APT09AD09PQA9PT0APT09AD09PQA9PT0APT0
+ 9AD09PQA9PT0APT09AD09PQA9PT0APT09AD09PQA9PT0APT09AD09PQA9PT0APT09AD09PQA9PT0APT0
+ 9AD09PQA9PT0APT09AD09PQA9PT0APT09AD09PQA9PT0APT09AD09PQA9PT0APT09AD09PQA9PT0APT0
+ 9AD09PQA9PT0APT09AD09PQA9PT0BfT09Ar09PQL9PT0CvT09Ab09PQA9PT0APT09AD09PQA9PT0APT0
+ 9AD09PQA9PT0APT09AD09PQA9PT0APT09AD09PQA9PT0APT09AD09PQA9PT0APT09AD09PQA9PT0APT0
+ 9AD09PQA9PT0APT09AD09PQA9PT0APT09AD09PQA9PT0APT09AD09PQA9PT0APT09AD09PQA9PT0APT0
+ 9AD09PQA9PT0APT09AD09PQA9PT0APT09AD09PQA9PT0APT09AD8/PwA/////////////+P///////4A
+ AP///8H//////8AAAAf//4D//////gAAAAD//wB/////+AAAAAA//gA/////4AAAAAAP/AAf////gAAA
+ AAAD+AAP///+AAAAAAAA8AAH///4AAAAAAAAIAAD///wAAAAAAAAAAAA///gAAAAAAAAAAAA//+AAAAA
+ AAAAAAAB//8AAAAAAAAAAAAD//4AAAAAAAAAAAAH//wAAAAAAAAAAAAP//gAAAAAAAAAAAAf//AAAAAA
+ AAAAAAA//+AAAAAAAAAAAAB//+AAAAAAAAAAAAD//8AAAAAAAAAAAAH//4AAAAAAAAAAAAP//wAAAAAA
+ AAAAAAH//wAAAAAAAAAAAAH//gAAAAAAAAAAAAD//AAAAAAAAAAAAAB//AAAAAAAAAAAAAB/+AAAAAAA
+ AAAAAAA/+AAAAAAAAAAAAAA/8AAAAAAAAAAAAAAf8AAAAAAAAAAAAAAf8AAAAAAAAAAAAAAP4AAAAAAA
+ AAAAAAAP4AAAAAAAAAAAAAAPwAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAHwAAAAAAA
+ AAAAAAADgAAAAAAAAAAAAAADgAAAAAAAAAAAAAADgAAAAAAAAAAAAAADgAAAAAAAAAAAAAADgAAAAAAA
+ AAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAA
+ AAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAA
+ AAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAABgAAAAAAAAAAAAAABgAAAAAAAAAAAAAADgAAAAAAA
+ AAAAAAADgAAAAAAAAAAAAAADgAAAAAAAAAAAAAADgAAAAAAAAAAAAAADwAAAAAAAAAAAAAAHwAAAAAAA
+ AAAAAAAHwAAAAAAAAAAAAAAH4AAAAAAAAAAAAAAP4AAAAAAAAAAAAAAP4AAAAAAAAAAAAAAP8AAAAAAA
+ AAAAAAAf8AAAAAAAAAAAAAAf+AAAAAAAAAAAAAA/+AAAAAAAAAAAAAA//AAAAAAAAAAAAAB//AAAAAAA
+ AAAAAAB//gAAAAAAAAAAAAD//gAAAAAAAAAAAAD//wAAAAAAAAAAAAH//4AAAAAAAAAAAAP//8AAAAAA
+ AAAAAAP//8AAAAAAAAAAAAf//+AAAAAAAAAAAA////AAAAAAAAAAAB////gAAAAAAAAAAD////wAAAAA
+ AAAAAH////4AAAAAAAAAAP////8AAAAAAAAAAf////+AAAAAAAAAA//////AAAAAAAAAB//////wAAAA
+ AAAAH//////4AAAAAAAAP//////+AAAAAAAA////////AAAAAAAB////////wAAAAAAH////////8AAA
+ AAAf/////////gAAAAD//////////8AAAAf///////////gAAD/////////////4P///////
+
+
+
\ No newline at end of file
diff --git a/QobuzDownloaderX/LoginForm.Designer.cs b/QobuzDownloaderX/LoginForm.Designer.cs
new file mode 100644
index 0000000..ff89dcc
--- /dev/null
+++ b/QobuzDownloaderX/LoginForm.Designer.cs
@@ -0,0 +1,207 @@
+namespace QobuzDownloaderX
+{
+ partial class LoginForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(LoginForm));
+ this.passwordLabel = new System.Windows.Forms.Label();
+ this.emailLabel = new System.Windows.Forms.Label();
+ this.appIdLabel = new System.Windows.Forms.Label();
+ this.emailTextbox = new System.Windows.Forms.TextBox();
+ this.passwordTextbox = new System.Windows.Forms.TextBox();
+ this.loginButton = new System.Windows.Forms.Button();
+ this.appidTextbox = new System.Windows.Forms.TextBox();
+ this.pictureBox1 = new System.Windows.Forms.PictureBox();
+ this.loginText = new System.Windows.Forms.Label();
+ this.md5Button = new System.Windows.Forms.Button();
+ this.loginBG = new System.ComponentModel.BackgroundWorker();
+ this.getSecretBG = new System.ComponentModel.BackgroundWorker();
+ this.verNumLabel2 = new System.Windows.Forms.Label();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
+ this.SuspendLayout();
+ //
+ // passwordLabel
+ //
+ this.passwordLabel.AutoSize = true;
+ this.passwordLabel.Location = new System.Drawing.Point(12, 143);
+ this.passwordLabel.Name = "passwordLabel";
+ this.passwordLabel.Size = new System.Drawing.Size(59, 13);
+ this.passwordLabel.TabIndex = 27;
+ this.passwordLabel.Text = "Password -";
+ //
+ // emailLabel
+ //
+ this.emailLabel.AutoSize = true;
+ this.emailLabel.Location = new System.Drawing.Point(33, 114);
+ this.emailLabel.Name = "emailLabel";
+ this.emailLabel.Size = new System.Drawing.Size(38, 13);
+ this.emailLabel.TabIndex = 26;
+ this.emailLabel.Text = "Email -";
+ //
+ // appIdLabel
+ //
+ this.appIdLabel.AutoSize = true;
+ this.appIdLabel.Location = new System.Drawing.Point(25, 85);
+ this.appIdLabel.Name = "appIdLabel";
+ this.appIdLabel.Size = new System.Drawing.Size(46, 13);
+ this.appIdLabel.TabIndex = 25;
+ this.appIdLabel.Text = "App ID -";
+ //
+ // emailTextbox
+ //
+ this.emailTextbox.Location = new System.Drawing.Point(77, 111);
+ this.emailTextbox.Multiline = true;
+ this.emailTextbox.Name = "emailTextbox";
+ this.emailTextbox.Size = new System.Drawing.Size(189, 23);
+ this.emailTextbox.TabIndex = 24;
+ this.emailTextbox.Text = "E-mail";
+ this.emailTextbox.WordWrap = false;
+ //
+ // passwordTextbox
+ //
+ this.passwordTextbox.Location = new System.Drawing.Point(77, 140);
+ this.passwordTextbox.Multiline = true;
+ this.passwordTextbox.Name = "passwordTextbox";
+ this.passwordTextbox.Size = new System.Drawing.Size(144, 23);
+ this.passwordTextbox.TabIndex = 23;
+ this.passwordTextbox.Text = "Password (Hashed)";
+ this.passwordTextbox.WordWrap = false;
+ //
+ // loginButton
+ //
+ this.loginButton.Location = new System.Drawing.Point(77, 169);
+ this.loginButton.Name = "loginButton";
+ this.loginButton.Size = new System.Drawing.Size(189, 23);
+ this.loginButton.TabIndex = 22;
+ this.loginButton.Text = "Login";
+ this.loginButton.UseVisualStyleBackColor = true;
+ this.loginButton.Click += new System.EventHandler(this.loginButton_Click);
+ //
+ // appidTextbox
+ //
+ this.appidTextbox.Location = new System.Drawing.Point(77, 82);
+ this.appidTextbox.Multiline = true;
+ this.appidTextbox.Name = "appidTextbox";
+ this.appidTextbox.Size = new System.Drawing.Size(189, 23);
+ this.appidTextbox.TabIndex = 21;
+ this.appidTextbox.Text = "app_id Here";
+ this.appidTextbox.WordWrap = false;
+ //
+ // pictureBox1
+ //
+ this.pictureBox1.BackColor = System.Drawing.Color.Transparent;
+ this.pictureBox1.Image = global::QobuzDownloaderX.Properties.Resources.qbdlx;
+ this.pictureBox1.Location = new System.Drawing.Point(12, 12);
+ this.pictureBox1.Name = "pictureBox1";
+ this.pictureBox1.Size = new System.Drawing.Size(257, 64);
+ this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
+ this.pictureBox1.TabIndex = 28;
+ this.pictureBox1.TabStop = false;
+ //
+ // loginText
+ //
+ this.loginText.Location = new System.Drawing.Point(12, 203);
+ this.loginText.Name = "loginText";
+ this.loginText.Size = new System.Drawing.Size(254, 23);
+ this.loginText.TabIndex = 29;
+ this.loginText.Text = "Waiting for login...";
+ this.loginText.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // md5Button
+ //
+ this.md5Button.Location = new System.Drawing.Point(227, 140);
+ this.md5Button.Name = "md5Button";
+ this.md5Button.Size = new System.Drawing.Size(39, 23);
+ this.md5Button.TabIndex = 30;
+ this.md5Button.Text = "MD5";
+ this.md5Button.UseVisualStyleBackColor = true;
+ this.md5Button.Click += new System.EventHandler(this.md5Button_Click);
+ //
+ // loginBG
+ //
+ this.loginBG.DoWork += new System.ComponentModel.DoWorkEventHandler(this.loginBG_DoWork);
+ //
+ // getSecretBG
+ //
+ this.getSecretBG.DoWork += new System.ComponentModel.DoWorkEventHandler(this.getSecretBG_DoWork);
+ //
+ // verNumLabel2
+ //
+ this.verNumLabel2.BackColor = System.Drawing.Color.Transparent;
+ this.verNumLabel2.Location = new System.Drawing.Point(181, 61);
+ this.verNumLabel2.Name = "verNumLabel2";
+ this.verNumLabel2.Size = new System.Drawing.Size(85, 18);
+ this.verNumLabel2.TabIndex = 31;
+ this.verNumLabel2.Text = "#.#.#.#";
+ this.verNumLabel2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // LoginForm
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(281, 235);
+ this.Controls.Add(this.verNumLabel2);
+ this.Controls.Add(this.md5Button);
+ this.Controls.Add(this.loginText);
+ this.Controls.Add(this.pictureBox1);
+ this.Controls.Add(this.passwordLabel);
+ this.Controls.Add(this.emailLabel);
+ this.Controls.Add(this.appIdLabel);
+ this.Controls.Add(this.emailTextbox);
+ this.Controls.Add(this.passwordTextbox);
+ this.Controls.Add(this.loginButton);
+ this.Controls.Add(this.appidTextbox);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.MaximizeBox = false;
+ this.Name = "LoginForm";
+ this.Text = "QobuzDLX | Login";
+ this.Load += new System.EventHandler(this.LoginForm_Load);
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label passwordLabel;
+ private System.Windows.Forms.Label emailLabel;
+ private System.Windows.Forms.Label appIdLabel;
+ private System.Windows.Forms.TextBox emailTextbox;
+ private System.Windows.Forms.TextBox passwordTextbox;
+ private System.Windows.Forms.Button loginButton;
+ private System.Windows.Forms.TextBox appidTextbox;
+ private System.Windows.Forms.PictureBox pictureBox1;
+ private System.Windows.Forms.Label loginText;
+ private System.Windows.Forms.Button md5Button;
+ private System.ComponentModel.BackgroundWorker loginBG;
+ private System.ComponentModel.BackgroundWorker getSecretBG;
+ private System.Windows.Forms.Label verNumLabel2;
+ }
+}
\ No newline at end of file
diff --git a/QobuzDownloaderX/LoginForm.cs b/QobuzDownloaderX/LoginForm.cs
new file mode 100644
index 0000000..98df17c
--- /dev/null
+++ b/QobuzDownloaderX/LoginForm.cs
@@ -0,0 +1,277 @@
+using QobuzDownloaderX.Properties;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.IO;
+using System.Diagnostics;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Security.Cryptography;
+using System.Reflection;
+using System.Text.RegularExpressions;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Drawing.Imaging;
+using TagLib.Flac;
+using QobuzDownloaderX;
+
+namespace QobuzDownloaderX
+{
+ public partial class LoginForm : Form
+ {
+ public LoginForm()
+ {
+ InitializeComponent();
+ }
+
+ private void QobuzDownloaderX_FormClosing(Object sender, FormClosingEventArgs e)
+ {
+ Application.Exit();
+ }
+
+ QobuzDownloaderX qbdlx = new QobuzDownloaderX();
+
+ public string appSecret { get; set; }
+
+ string errorLog = Path.GetDirectoryName(Application.ExecutablePath) + "\\Latest_Error.log";
+ string dllCheck = Path.GetDirectoryName(Application.ExecutablePath) + "\\taglib-sharp.dll";
+
+ private void LoginForm_Load(object sender, EventArgs e)
+ {
+ // Get and display version number.
+ verNumLabel2.Text = Assembly.GetExecutingAssembly().GetName().Version.ToString();
+
+ if (!System.IO.File.Exists(dllCheck))
+ {
+ MessageBox.Show("taglib-sharp.dll missing from folder!\r\nPlease Make sure the DLL is in the same folder as QobuzDownloaderX.exe!", "ERROR",
+ MessageBoxButtons.OK, MessageBoxIcon.Error);
+ Application.Exit();
+ }
+ // Bring to center of screen.
+ CenterToScreen();
+
+ if (Properties.Settings.Default.UpgradeRequired)
+ {
+ Properties.Settings.Default.Upgrade();
+ Properties.Settings.Default.UpgradeRequired = false;
+ Properties.Settings.Default.Save();
+ }
+
+ // Set saved settings to correct places.
+ appidTextbox.Text = Settings.Default.savedAppID.ToString();
+ emailTextbox.Text = Settings.Default.savedEmail.ToString();
+ passwordTextbox.Text = Settings.Default.savedPassword.ToString();
+ }
+
+ static string GetMd5Hash(MD5 md5Hash, string input)
+ {
+
+ // Convert the input string to a byte array and compute the hash.
+ byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
+
+ // Create a new Stringbuilder to collect the bytes and create a string.
+ StringBuilder sBuilder = new StringBuilder();
+
+ // Loop through each byte of the hashed data and format each one as a hexadecimal string.
+ for (int i = 0; i < data.Length; i++)
+ {
+ sBuilder.Append(data[i].ToString("x2"));
+ }
+
+ // Return the hexadecimal string.
+ return sBuilder.ToString();
+ }
+
+ // Verify a hash against a string.
+ static bool VerifyMd5Hash(MD5 md5Hash, string input, string hash)
+ {
+ // Hash the input.
+ string hashOfInput = GetMd5Hash(md5Hash, input);
+
+ // Create a StringComparer an compare the hashes.
+ StringComparer comparer = StringComparer.OrdinalIgnoreCase;
+
+ if (0 == comparer.Compare(hashOfInput, hash))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ private void md5Button_Click(object sender, EventArgs e)
+ {
+ string plainTextPW = passwordTextbox.Text;
+
+ // Generate the MD5 hash using the string created above.
+ using (MD5 md5PassHash = MD5.Create())
+ {
+ string hashedPW = GetMd5Hash(md5PassHash, plainTextPW);
+
+ if (VerifyMd5Hash(md5PassHash, plainTextPW, hashedPW))
+ {
+ // If the MD5 hash is verified, proceed to get the streaming URL.
+ passwordTextbox.Text = hashedPW;
+ }
+ else
+ {
+ // If the hash can't be verified.
+ loginText.Invoke(new Action(() => loginText.Text = "Hashing failed. Please retry."));
+ return;
+ }
+ }
+ }
+
+ private void loginButton_Click(object sender, EventArgs e)
+ {
+ var passMD5CheckLog = Regex.Match(passwordTextbox.Text, "(?^[0-9a-f]{32}$)").Groups;
+ var passMD5Check = passMD5CheckLog[1].Value;
+
+ if (passMD5Check == null | passMD5Check == "")
+ {
+ loginText.Text = "Password not MD5! Hit \"MD5\" before logging in!";
+ return;
+ }
+
+ // Save info locally to be used on next launch.
+ Settings.Default.savedEmail = emailTextbox.Text;
+ Settings.Default.savedAppID = appidTextbox.Text;
+ Settings.Default.savedPassword = passwordTextbox.Text;
+ Settings.Default.Save();
+
+ loginText.Text = "Logging in + obtaining app_secret...";
+ loginBG.RunWorkerAsync();
+ }
+
+ private void loginBG_DoWork(object sender, DoWorkEventArgs e)
+ {
+ loginBG.WorkerSupportsCancellation = true;
+
+ // Create WebRequest to login using login information from input textboxes.
+ WebRequest wr = WebRequest.Create("https://www.qobuz.com/api.json/0.2/user/login?email=" + emailTextbox.Text + "&password=" + passwordTextbox.Text + "&app_id=" + appidTextbox.Text);
+
+ try
+ {
+ // Grab info to be displayed and used.
+ WebResponse ws = wr.GetResponse();
+ StreamReader sr = new StreamReader(ws.GetResponseStream());
+
+ string loginRequest = sr.ReadToEnd();
+ string text = loginRequest;
+
+ // Grab display name
+ var displayNameLog = Regex.Match(loginRequest, "\"display_name\":\"(?.*?)\",\\\"").Groups;
+ var displayName = displayNameLog[1].Value;
+ qbdlx.displayName = displayName;
+
+ // Grab account type
+ var accountTypeLog = Regex.Match(loginRequest, "short_label\":\"(?\\w+)").Groups;
+ var accountType = accountTypeLog[1].Value;
+ qbdlx.accountType = accountType;
+
+ // Grab authentication token
+ var userAuth = Regex.Match(loginRequest, "\"user_auth_token\":\"(?.*?)\\\"}").Groups;
+ var userAuthToken = userAuth[1].Value;
+
+ // Set user_auth_token
+ qbdlx.userAuth = userAuthToken;
+ loginText.Invoke(new Action(() => loginText.Text = "Login Successful! Getting app_secret..."));
+ }
+ catch (Exception ex)
+ {
+ // If connection to API fails, show error info.
+ string error = ex.ToString();
+ loginText.Invoke(new Action(() => loginText.Text = "Login Failed. Error Log saved"));
+ System.IO.File.WriteAllText(errorLog, error);
+ wr.Abort();
+ return;
+ }
+
+ wr.Abort();
+ getSecretBG.RunWorkerAsync();
+ loginBG.CancelAsync();
+ }
+
+ private void getSecretBG_DoWork(object sender, DoWorkEventArgs e)
+ {
+ getSecretBG.WorkerSupportsCancellation = true;
+
+ WebClient bundleURLClient = new WebClient();
+ string bundleHTML = bundleURLClient.DownloadString("https://play.qobuz.com/");
+
+ // Grab link to bundle.js
+ var bundleLog = Regex.Match(bundleHTML, "