├── -assets
├── QBDLX1.png
├── QBDLX2.png
├── QBDLX3.png
├── New-QBDLX.png
├── QBDLX-Icon.ico
├── New-QBDLX-Icon.ico
└── New-QBDLX-Icon.png
├── QobuzDownloaderX
├── Resources
│ ├── alert.png
│ ├── email.png
│ ├── info.png
│ ├── lock.png
│ ├── logout.png
│ ├── search.png
│ ├── download.png
│ ├── log_out.png
│ ├── new-post.png
│ ├── password.png
│ ├── settings.png
│ ├── QBDLX-Icon.ico
│ ├── QBDLX-Icon.png
│ ├── qbdlx_icon.ico
│ ├── qbdlx_new.png
│ ├── download-from-cloud--v1.png
│ ├── themes.json
│ └── Languages
│ │ ├── zh-cn.json
│ │ ├── en.json
│ │ ├── ru.json
│ │ └── de.json
├── packages.config
├── Program.cs
├── Settings.cs
├── Helpers
│ ├── FixMD5.cs
│ ├── PaddingNumbers.cs
│ ├── GetInfo.cs
│ ├── TagFile.cs
│ ├── Updating.cs
│ ├── Download
│ │ ├── DownloadFile.cs
│ │ ├── DownloadTrack.cs
│ │ └── DownloadAlbum.cs
│ ├── RenameTemplates.cs
│ └── SearchPanelHelper.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Settings.settings
│ └── Resources.resx
├── Old
│ ├── AboutForm.cs
│ ├── searchForm.Designer.cs
│ ├── searchForm.cs
│ ├── AboutForm.Designer.cs
│ └── LoginForm-v2.Designer.cs
├── App.config
└── QobuzDownloaderX.csproj
├── QobuzDownloaderX.sln
├── README.md
├── .gitattributes
└── .gitignore
/-assets/QBDLX1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/-assets/QBDLX1.png
--------------------------------------------------------------------------------
/-assets/QBDLX2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/-assets/QBDLX2.png
--------------------------------------------------------------------------------
/-assets/QBDLX3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/-assets/QBDLX3.png
--------------------------------------------------------------------------------
/-assets/New-QBDLX.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/-assets/New-QBDLX.png
--------------------------------------------------------------------------------
/-assets/QBDLX-Icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/-assets/QBDLX-Icon.ico
--------------------------------------------------------------------------------
/-assets/New-QBDLX-Icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/-assets/New-QBDLX-Icon.ico
--------------------------------------------------------------------------------
/-assets/New-QBDLX-Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/-assets/New-QBDLX-Icon.png
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/alert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/alert.png
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/email.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/email.png
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/info.png
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/lock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/lock.png
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/logout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/logout.png
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/search.png
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/download.png
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/log_out.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/log_out.png
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/new-post.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/new-post.png
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/password.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/password.png
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/settings.png
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/QBDLX-Icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/QBDLX-Icon.ico
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/QBDLX-Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/QBDLX-Icon.png
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/qbdlx_icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/qbdlx_icon.ico
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/qbdlx_new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/qbdlx_new.png
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/download-from-cloud--v1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImAiiR/QobuzDownloaderX/HEAD/QobuzDownloaderX/Resources/download-from-cloud--v1.png
--------------------------------------------------------------------------------
/QobuzDownloaderX/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace QobuzDownloaderX
5 | {
6 | static class Program
7 | {
8 | ///
9 | /// The main entry point for the application.
10 | ///
11 | [STAThread]
12 | static void Main()
13 | {
14 | Application.EnableVisualStyles();
15 | Application.SetCompatibleTextRenderingDefault(false);
16 | Application.Run(new LoginForm());
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/QobuzDownloaderX.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QobuzDownloaderX", "QobuzDownloaderX\QobuzDownloaderX.csproj", "{4CEB979A-035A-4D36-9607-D554BBECABE0}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {4CEB979A-035A-4D36-9607-D554BBECABE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {4CEB979A-035A-4D36-9607-D554BBECABE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {4CEB979A-035A-4D36-9607-D554BBECABE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {4CEB979A-035A-4D36-9607-D554BBECABE0}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Settings.cs:
--------------------------------------------------------------------------------
1 | namespace QobuzDownloaderX.Properties {
2 |
3 |
4 | // This class allows you to handle specific events on the settings class:
5 | // The SettingChanging event is raised before a setting's value is changed.
6 | // The PropertyChanged event is raised after a setting's value is changed.
7 | // The SettingsLoaded event is raised after the setting values are loaded.
8 | // The SettingsSaving event is raised before the setting values are saved.
9 | internal sealed partial class Settings {
10 |
11 | public Settings() {
12 | // // To add event handlers for saving and changing settings, uncomment the lines below:
13 | //
14 | // this.SettingChanging += this.SettingChangingEventHandler;
15 | //
16 | // this.SettingsSaving += this.SettingsSavingEventHandler;
17 | //
18 | }
19 |
20 | private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {
21 | // Add code to handle the SettingChangingEvent event here.
22 | }
23 |
24 | private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {
25 | // Add code to handle the SettingsSaving event here.
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Helpers/FixMD5.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 |
4 | namespace QobuzDownloaderX
5 | {
6 | class FixMD5
7 | {
8 | GetInfo getInfo = new GetInfo();
9 |
10 | public string outputResult { get; set; }
11 |
12 | public void fixMD5(string filePath, string flacEXEPath)
13 | {
14 | qbdlxForm._qbdlxForm.logger.Debug("Attempting to fix unset MD5...");
15 | string driveLetter = filePath.Substring(0, 2);
16 | string cmdText = "/C echo Fixing unset MD5s... & \"" + flacEXEPath + "\" -f8 \"" + filePath + "\"";
17 | qbdlxForm._qbdlxForm.logger.Debug("Commands - " + cmdText);
18 |
19 | try
20 | {
21 | qbdlxForm._qbdlxForm.logger.Debug("Running cmd to run ffmpeg command to fix MD5");
22 | Process cmd = new Process();
23 | cmd.StartInfo.FileName = "cmd.exe";
24 | cmd.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
25 | cmd.StartInfo.Arguments = cmdText;
26 | cmd.Start();
27 | cmd.WaitForExit();
28 | outputResult = "COMPLETE";
29 | qbdlxForm._qbdlxForm.logger.Debug("MD5 has been fixed for file!");
30 | }
31 | catch (Exception fixMD5ex)
32 | {
33 | outputResult = "FAILED";
34 | qbdlxForm._qbdlxForm.logger.Error("Failed to fix MD5s, error below:\r\n" + fixMD5ex);
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("QobuzDownloaderX")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("AiiR")]
12 | [assembly: AssemblyProduct("QobuzDownloaderX")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("4ceb979a-035a-4d36-9607-d554bbecabe0")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 |
36 | [assembly: AssemblyVersion("1.0.1.2")]
37 | [assembly: AssemblyFileVersion("1.0.1.2")]
38 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Helpers/PaddingNumbers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using QopenAPI;
3 |
4 | namespace QobuzDownloaderX
5 | {
6 | class PaddingNumbers
7 | {
8 | public Album QoAlbum = new Album();
9 |
10 | public int padTracks(Album QoAlbum)
11 | {
12 | var paddingLength = 2;
13 |
14 | // Prepare track number padding in filename.
15 | string paddingLog = Math.Floor(Math.Log10(QoAlbum.TracksCount) + 1).ToString();
16 |
17 | switch (paddingLog)
18 | {
19 | case "1":
20 | return paddingLength = 2;
21 | default:
22 | return paddingLength = (int)Math.Floor(Math.Log10(QoAlbum.TracksCount) + 1);
23 | }
24 | }
25 |
26 | public int padPlaylistTracks(Playlist QoPlaylist)
27 | {
28 | var paddingLength = 2;
29 |
30 | // Prepare track number padding in filename.
31 | string paddingLog = Math.Floor(Math.Log10(QoPlaylist.TracksCount) + 1).ToString();
32 |
33 | switch (paddingLog)
34 | {
35 | case "1":
36 | return paddingLength = 2;
37 | default:
38 | return paddingLength = (int)Math.Floor(Math.Log10(QoPlaylist.TracksCount) + 1);
39 | }
40 | }
41 |
42 | public int padDiscs(Album QoAlbum)
43 | {
44 | var paddingLength = 2;
45 |
46 | // Prepare track number padding in filename.
47 | string paddingLog = Math.Floor(Math.Log10(QoAlbum.MediaCount) + 1).ToString();
48 |
49 | switch (paddingLog)
50 | {
51 | case "1":
52 | return paddingLength = 2;
53 | default:
54 | return paddingLength = (int)Math.Floor(Math.Log10(QoAlbum.MediaCount) + 1);
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Inspired by Qo-DL by Sorrow & Dash
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Telegram Group Chat - @QbdLX
18 | Telegram Updates Channel - @QobuzDownloaderX
19 | I'm never really active on Telegram, but these are the official channels.
20 |
21 | # About
22 | QobuzDownloaderX is a program for downloading music streams from the streaming platform Qobuz.
23 |
24 | You can not download anything with a free account.
25 |
26 | # Disclaimer & Legal
27 | I will not be responsible for how you use QBDLX (QobuzDownloaderX).
28 |
29 | This program DOES NOT include...
30 | - Code to bypass Qobuz's region restrictions.
31 | - Qobuz app IDs or secrets.
32 |
33 | QBDLX does not publish any of Qobuz's private secrets or app IDs. It contains regular expressions and other code to dynamically grab them from Qobuz's web player's *publicly available* JavaScript, which is not rehosted, but grabbed client side. Scraping public data is not a violation of the Computer Fraud and Abuse Act (USA) according to the Ninth Court of Appeals, [case # 17-16783](http://cdn.ca9.uscourts.gov/datastore/opinions/2019/09/09/17-16783.pdf) (see page 29).
34 |
35 | QBDLX uses the Qobuz API, but is not endorsed, certified or otherwise approved in any way by Qobuz.
36 |
37 | Qobuz brand and name is the registered trademark of its respective owner.
38 |
39 | QBDLX has no partnership, sponsorship or endorsement with Qobuz.
40 |
41 | By using QBDLX, you agree to the following: http://static.qobuz.com/apps/api/QobuzAPI-TermsofUse.pdf
42 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/themes.json:
--------------------------------------------------------------------------------
1 | {
2 | "themes": {
3 | "Dark": {
4 | "FormBackground": "#121212",
5 | "MainPanelBackground": "#121212",
6 | "HighlightedButtonBackground": "#121212",
7 | "SidePanelBackground": "#0d0d0d",
8 | "ButtonBackground": "#0d0d0d",
9 | "ClickedButtonBackground": "#191919",
10 | "TextBoxBackground": "#1e1e1e",
11 | "PlaceholderTextBoxText": "#3c3c3c",
12 | "TextBoxText": "#939393",
13 | "LabelText": "#939393",
14 | "ButtonText": "#939393",
15 | "NavBarIconColor": "#939393",
16 | "HiResLabelText": "#fac819",
17 | "LogoReplaceURL": null,
18 | "InvertLogo": false
19 | },
20 | "Light": {
21 | "FormBackground": "#ededed",
22 | "MainPanelBackground": "#ededed",
23 | "HighlightedButtonBackground": "#ededed",
24 | "SidePanelBackground": "#f2f2f2",
25 | "ButtonBackground": "#f2f2f2",
26 | "ClickedButtonBackground": "#e6e6e6",
27 | "TextBoxBackground": "#e1e1e1",
28 | "PlaceholderTextBoxText": "#c3c3c3",
29 | "TextBoxText": "#6c6c6c",
30 | "LabelText": "#6c6c6c",
31 | "ButtonText": "#6c6c6c",
32 | "NavBarIconColor": "#6c6c6c",
33 | "HiResLabelText": "#cd9b00",
34 | "LogoReplaceURL": null,
35 | "InvertLogo": true
36 | },
37 | "JAM.S": {
38 | "FormBackground": "#2b2f34",
39 | "MainPanelBackground": "#2b2f34",
40 | "HighlightedButtonBackground": "#bc243c",
41 | "SidePanelBackground": "#56343e",
42 | "ButtonBackground": "#56343e",
43 | "ClickedButtonBackground": "#734141",
44 | "TextBoxBackground": "#1e1e1e",
45 | "PlaceholderTextBoxText": "#3c3c3c",
46 | "TextBoxText": "#8c8c8c",
47 | "LabelText": "#8c8c8c",
48 | "ButtonText": "#FFFFFF",
49 | "NavBarIconColor": "#FFFFFF",
50 | "HiResLabelText": "#fac819",
51 | "LogoReplaceURL": "https://justanothermusic.site/styles/pach/logo.png",
52 | "InvertLogo": false
53 | },
54 | "Qotify": {
55 | "FormBackground": "#121212",
56 | "MainPanelBackground": "#121212",
57 | "HighlightedButtonBackground": "#4ac776",
58 | "SidePanelBackground": "#1db954",
59 | "ButtonBackground": "#1db954",
60 | "ClickedButtonBackground": "#62d089",
61 | "TextBoxBackground": "#1e1e1e",
62 | "PlaceholderTextBoxText": "#3c3c3c",
63 | "TextBoxText": "#939393",
64 | "LabelText": "#FFFFFF",
65 | "ButtonText": "#FFFFFF",
66 | "NavBarIconColor": "#FFFFFF",
67 | "HiResLabelText": "#1db954",
68 | "LogoReplaceURL": null,
69 | "InvertLogo": false
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/QobuzDownloaderX/Old/AboutForm.cs:
--------------------------------------------------------------------------------
1 | using QobuzDownloaderX.Properties;
2 | using System;
3 | using System.Runtime.InteropServices;
4 | using System.Collections.Generic;
5 | using System.ComponentModel;
6 | using System.Data;
7 | using System.Drawing;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 | using System.Windows.Forms;
12 | using System.Reflection;
13 |
14 | namespace QobuzDownloaderX
15 | {
16 | public partial class AboutForm : Form
17 | {
18 | public AboutForm()
19 | {
20 | InitializeComponent();
21 | }
22 |
23 | public const int WM_NCLBUTTONDOWN = 0xA1;
24 | public const int HT_CAPTION = 0x2;
25 |
26 | [DllImportAttribute("user32.dll")]
27 | public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
28 | [DllImportAttribute("user32.dll")]
29 | public static extern bool ReleaseCapture();
30 |
31 | private void AboutForm_Load(object sender, EventArgs e)
32 | {
33 | // Get and display version number.
34 | verNumLabel2.Text = Assembly.GetExecutingAssembly().GetName().Version.ToString();
35 | }
36 |
37 | private void exitLabel_Click(object sender, EventArgs e)
38 | {
39 | this.Close();
40 | }
41 |
42 | private void panel1_MouseMove(object sender, MouseEventArgs e)
43 | {
44 | if (e.Button == MouseButtons.Left)
45 | {
46 | ReleaseCapture();
47 | SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
48 | }
49 | }
50 |
51 | private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
52 | {
53 | if (e.Button == MouseButtons.Left)
54 | {
55 | ReleaseCapture();
56 | SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
57 | }
58 | }
59 |
60 | private void verNumLabel2_MouseMove(object sender, MouseEventArgs e)
61 | {
62 | if (e.Button == MouseButtons.Left)
63 | {
64 | ReleaseCapture();
65 | SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
66 | }
67 | }
68 |
69 | private void AboutForm_MouseMove(object sender, MouseEventArgs e)
70 | {
71 | if (e.Button == MouseButtons.Left)
72 | {
73 | ReleaseCapture();
74 | SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Old/searchForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace QobuzDownloaderX
2 | {
3 | partial class searchForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(searchForm));
32 | this.searchInput = new System.Windows.Forms.TextBox();
33 | this.searchButton = new System.Windows.Forms.Button();
34 | this.resultTextbox = new System.Windows.Forms.TextBox();
35 | this.SuspendLayout();
36 | //
37 | // searchInput
38 | //
39 | this.searchInput.Location = new System.Drawing.Point(12, 14);
40 | this.searchInput.Name = "searchInput";
41 | this.searchInput.Size = new System.Drawing.Size(612, 20);
42 | this.searchInput.TabIndex = 0;
43 | this.searchInput.KeyDown += new System.Windows.Forms.KeyEventHandler(this.searchInput_KeyDown);
44 | //
45 | // searchButton
46 | //
47 | this.searchButton.Location = new System.Drawing.Point(630, 12);
48 | this.searchButton.Name = "searchButton";
49 | this.searchButton.Size = new System.Drawing.Size(98, 23);
50 | this.searchButton.TabIndex = 1;
51 | this.searchButton.Text = "Search";
52 | this.searchButton.UseVisualStyleBackColor = true;
53 | this.searchButton.Click += new System.EventHandler(this.searchButton_Click);
54 | //
55 | // resultTextbox
56 | //
57 | this.resultTextbox.Location = new System.Drawing.Point(12, 40);
58 | this.resultTextbox.Multiline = true;
59 | this.resultTextbox.Name = "resultTextbox";
60 | this.resultTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
61 | this.resultTextbox.Size = new System.Drawing.Size(716, 513);
62 | this.resultTextbox.TabIndex = 2;
63 | this.resultTextbox.WordWrap = false;
64 | //
65 | // searchForm
66 | //
67 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
68 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
69 | this.ClientSize = new System.Drawing.Size(740, 565);
70 | this.Controls.Add(this.resultTextbox);
71 | this.Controls.Add(this.searchButton);
72 | this.Controls.Add(this.searchInput);
73 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
74 | this.Name = "searchForm";
75 | this.Text = "QobuzDLX | Search";
76 | this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.searchForm_FormClosed);
77 | this.Load += new System.EventHandler(this.searchForm_Load);
78 | this.ResumeLayout(false);
79 | this.PerformLayout();
80 |
81 | }
82 |
83 | #endregion
84 |
85 | private System.Windows.Forms.TextBox searchInput;
86 | private System.Windows.Forms.Button searchButton;
87 | private System.Windows.Forms.TextBox resultTextbox;
88 | }
89 | }
--------------------------------------------------------------------------------
/QobuzDownloaderX/Old/searchForm.cs:
--------------------------------------------------------------------------------
1 | using QobuzDownloaderX.Properties;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Data;
6 | using System.Drawing;
7 | using System.Linq;
8 | using System.Net;
9 | using System.Text;
10 | using System.IO;
11 | using System.Diagnostics;
12 | using System.Runtime.InteropServices;
13 | using System.Threading.Tasks;
14 | using System.Windows.Forms;
15 | using System.Security.Cryptography;
16 | using System.Reflection;
17 | using System.Text.RegularExpressions;
18 | using System.Net.Http;
19 | using System.Net.Http.Headers;
20 | using System.Drawing.Imaging;
21 | using TagLib.Flac;
22 | using System.Globalization;
23 | using System.Threading;
24 |
25 | namespace QobuzDownloaderX
26 | {
27 | public partial class searchForm : Form
28 | {
29 | public searchForm()
30 | {
31 | InitializeComponent();
32 | }
33 |
34 | public String appid { get; set; }
35 | public String userAuth { get; set; }
36 |
37 | static string DecodeEncodedNonAsciiCharacters(string value)
38 | {
39 | return Regex.Replace(
40 | value,
41 | @"\\u(?[a-zA-Z0-9]{4})",
42 | m => {
43 | return ((char)int.Parse(m.Groups["Value"].Value, NumberStyles.HexNumber)).ToString();
44 | });
45 | }
46 |
47 | private void searchForm_Load(object sender, EventArgs e)
48 | {
49 |
50 | }
51 |
52 | private void searchButton_Click(object sender, EventArgs e)
53 | {
54 | #region Do Search
55 | WebRequest searchwr = WebRequest.Create("http://www.qobuz.com/api.json/0.2/album/search?app_id=" + appid + "&query=" + searchInput.Text + "&limit=15&user_auth_token=" + userAuth);
56 |
57 | WebResponse searchws = searchwr.GetResponse();
58 | StreamReader searchsr = new StreamReader(searchws.GetResponseStream());
59 |
60 | string searchRequest = searchsr.ReadToEnd();
61 |
62 | // Remove backslashes from the stream URL to have a proper URL.
63 | string resultpattern = "\"maximum_bit_depth\":(?.*?),(?:.*?),\"artist\":(?:.*?)\"name\":\"(?.*?)\",(?:.*?)\"title\":\"(?.*?)\"(?:.*?),\"maximum_channel_count\":(?:.*?),\"id\":\"(?.*?)\",\"maximum_sampling_rate\":(?.*?),\"";
64 | string resultinput = searchRequest;
65 | RegexOptions resultoptions = RegexOptions.Multiline;
66 |
67 | resultTextbox.Invoke(new Action(() => resultTextbox.Text = String.Empty));
68 |
69 | foreach (Match mResult in Regex.Matches(resultinput, resultpattern, resultoptions))
70 | {
71 | resultTextbox.Invoke(new Action(() => resultTextbox.AppendText(string.Format("{0} - {1} [{2}bit/{3}kHz]\r\nhttps://play.qobuz.com/album/{4}\r\n\r\n", mResult.Groups["albumArtist"].Value, mResult.Groups["albumTitle"].Value, mResult.Groups["bitDepth"].Value, mResult.Groups["sampleRate"].Value, mResult.Groups["albumID"].Value))));
72 |
73 | // For converting unicode characters to ASCII
74 | string unicodeResult = resultTextbox.Text;
75 | string decodedResult = DecodeEncodedNonAsciiCharacters(unicodeResult);
76 |
77 | var fixedText = decodedResult.Replace(@"\/", "/");
78 | resultTextbox.Invoke(new Action(() => resultTextbox.Text = fixedText));
79 | }
80 |
81 | #endregion
82 | }
83 |
84 | private void searchForm_FormClosed(object sender, FormClosedEventArgs e)
85 | {
86 |
87 | }
88 |
89 | private void searchInput_KeyDown(object sender, KeyEventArgs e)
90 | {
91 | if (e.KeyCode == Keys.Enter)
92 | {
93 | searchButton_Click(sender, e);
94 | e.Handled = true;
95 | e.SuppressKeyPress = true;
96 | }
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | [Xx]64/
19 | [Xx]86/
20 | [Bb]uild/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 |
85 | # Visual Studio profiler
86 | *.psess
87 | *.vsp
88 | *.vspx
89 | *.sap
90 |
91 | # TFS 2012 Local Workspace
92 | $tf/
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 | *.DotSettings.user
101 |
102 | # JustCode is a .NET coding add-in
103 | .JustCode
104 |
105 | # TeamCity is a build add-in
106 | _TeamCity*
107 |
108 | # DotCover is a Code Coverage Tool
109 | *.dotCover
110 |
111 | # NCrunch
112 | _NCrunch_*
113 | .*crunch*.local.xml
114 | nCrunchTemp_*
115 |
116 | # MightyMoose
117 | *.mm.*
118 | AutoTest.Net/
119 |
120 | # Web workbench (sass)
121 | .sass-cache/
122 |
123 | # Installshield output folder
124 | [Ee]xpress/
125 |
126 | # DocProject is a documentation generator add-in
127 | DocProject/buildhelp/
128 | DocProject/Help/*.HxT
129 | DocProject/Help/*.HxC
130 | DocProject/Help/*.hhc
131 | DocProject/Help/*.hhk
132 | DocProject/Help/*.hhp
133 | DocProject/Help/Html2
134 | DocProject/Help/html
135 |
136 | # Click-Once directory
137 | publish/
138 |
139 | # Publish Web Output
140 | *.[Pp]ublish.xml
141 | *.azurePubxml
142 |
143 | # TODO: Un-comment the next line if you do not want to checkin
144 | # your web deploy settings because they may include unencrypted
145 | # passwords
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # NuGet Packages
150 | *.nupkg
151 | # The packages folder can be ignored because of Package Restore
152 | **/packages/*
153 | # except build/, which is used as an MSBuild target.
154 | !**/packages/build/
155 | # Uncomment if necessary however generally it will be regenerated when needed
156 | #!**/packages/repositories.config
157 | # NuGet v3's project.json files produces more ignoreable files
158 | *.nuget.props
159 | *.nuget.targets
160 |
161 | # Microsoft Azure Build Output
162 | csx/
163 | *.build.csdef
164 |
165 | # Microsoft Azure Emulator
166 | ecf/
167 | rcf/
168 |
169 | # Microsoft Azure ApplicationInsights config file
170 | ApplicationInsights.config
171 |
172 | # Windows Store app package directory
173 | AppPackages/
174 | BundleArtifacts/
175 |
176 | # Visual Studio cache files
177 | # files ending in .cache can be ignored
178 | *.[Cc]ache
179 | # but keep track of directories ending in .cache
180 | !*.[Cc]ache/
181 |
182 | # Others
183 | Old/
184 | ClientBin/
185 | [Ss]tyle[Cc]op.*
186 | ~$*
187 | *~
188 | *.dbmdl
189 | *.dbproj.schemaview
190 | *.pfx
191 | *.publishsettings
192 | node_modules/
193 | orleans.codegen.cs
194 |
195 | # RIA/Silverlight projects
196 | Generated_Code/
197 |
198 | # Backup & report files from converting an old project file
199 | # to a newer Visual Studio version. Backup files are not needed,
200 | # because we have git ;-)
201 | _UpgradeReport_Files/
202 | Backup*/
203 | UpgradeLog*.XML
204 | UpgradeLog*.htm
205 |
206 | # SQL Server files
207 | *.mdf
208 | *.ldf
209 |
210 | # Business Intelligence projects
211 | *.rdl.data
212 | *.bim.layout
213 | *.bim_*.settings
214 |
215 | # Microsoft Fakes
216 | FakesAssemblies/
217 |
218 | # GhostDoc plugin setting file
219 | *.GhostDoc.xml
220 |
221 | # Node.js Tools for Visual Studio
222 | .ntvs_analysis.dat
223 |
224 | # Visual Studio 6 build log
225 | *.plg
226 |
227 | # Visual Studio 6 workspace options file
228 | *.opt
229 |
230 | # Visual Studio LightSwitch build output
231 | **/*.HTMLClient/GeneratedArtifacts
232 | **/*.DesktopClient/GeneratedArtifacts
233 | **/*.DesktopClient/ModelManifest.xml
234 | **/*.Server/GeneratedArtifacts
235 | **/*.Server/ModelManifest.xml
236 | _Pvt_Extensions
237 |
238 | # LightSwitch generated files
239 | GeneratedArtifacts/
240 | ModelManifest.xml
241 |
242 | # Paket dependency manager
243 | .paket/paket.exe
244 |
245 | # FAKE - F# Make
246 | .fake/
247 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/Languages/zh-cn.json:
--------------------------------------------------------------------------------
1 | {
2 | "TranslationCredit": "Mxqing",
3 | "TranslationUpdatedOn": "November 21, 2024, 01:15AM GMT+8",
4 | "TranslationFont": "Microsoft YaHei UI",
5 | "_SECTION1_": "=================== 主表单按钮 ===================",
6 | "additionalSettingsButton": "附加设置",
7 | "aboutButton": "关于",
8 | "closeAdditionalButton": "返回设置",
9 | "downloadButton": "获取",
10 | "downloaderButton": "下载器",
11 | "logoutButton": "退出登录",
12 | "openFolderButton": "打开文件夹",
13 | "qualitySelectButton": "音质选择器",
14 | "saveTemplatesButton": "保存",
15 | "searchButton": "搜索",
16 | "searchAlbumsButton": "搜专辑",
17 | "searchTracksButton": "搜曲目",
18 | "selectFolderButton": "选择文件夹",
19 | "settingsButton": "设置",
20 | "_SECTION2_": "=================== 主表单标签 ===================",
21 | "advancedOptionsLabel": "高级选项",
22 | "albumTemplateLabel": "专辑模板",
23 | "artistTemplateLabel": "艺术家模板",
24 | "commentLabel": "自定义备注",
25 | "downloadFolderLabel": "下载文件夹",
26 | "downloadOptionsLabel": "下载选项",
27 | "embeddedArtLabel": "嵌入的封面尺寸",
28 | "extraSettingsLabel": "附加设置",
29 | "languageLabel": "当前语言",
30 | "playlistTemplateLabel": "播放列表模板",
31 | "favoritesTemplateLabel": "收藏模板",
32 | "savedArtLabel": "保存的封面尺寸",
33 | "searchingLabel": "搜索中...",
34 | "taggingOptionsLabel": "标签选项",
35 | "templatesLabel": "模板",
36 | "templatesListLabel": "模板列表",
37 | "themeLabel": "当前主题",
38 | "themeSectionLabel": "主题选项",
39 | "trackTemplateLabel": "曲目模板",
40 | "userInfoLabel": "用户信息",
41 | "welcomeLabel": "欢迎\r\n{username}",
42 | "_SECTION3_": "=================== 主表单复选框 ===================",
43 | "albumArtistCheckbox": "专辑艺术家",
44 | "albumTitleCheckbox": "专辑标题",
45 | "trackArtistCheckbox": "曲目艺术家",
46 | "trackTitleCheckbox": "曲目标题",
47 | "releaseDateCheckbox": "发行日期",
48 | "releaseTypeCheckbox": "发行类型",
49 | "genreCheckbox": "流派",
50 | "trackNumberCheckbox": "曲目编号",
51 | "trackTotalCheckbox": "总曲目数",
52 | "discNumberCheckbox": "光盘编号",
53 | "discTotalCheckbox": "总光盘数",
54 | "composerCheckbox": "作曲家",
55 | "explicitCheckbox": "Explicit 提示",
56 | "coverArtCheckbox": "专辑封面",
57 | "copyrightCheckbox": "版权",
58 | "labelCheckbox": "唱片公司",
59 | "upcCheckbox": "UPC/条形码",
60 | "isrcCheckbox": "ISRC",
61 | "streamableCheckbox": "歌曲流媒体可播性检查",
62 | "fixMD5sCheckbox": "自动修复生成 MD5 校验和(必须在 PATH 变量中包含 FLAC)",
63 | "downloadSpeedCheckbox": "显示下载速度",
64 | "_SECTION4_": "=================== 主表单占位符 ===================",
65 | "albumLabelPlaceholder": "欢迎使用 QBDLX!",
66 | "artistLabelPlaceholder": "输入你的 Qobuz URL 并点击获取!",
67 | "infoLabelPlaceholder": "发行",
68 | "inputTextboxPlaceholder": "粘贴一个 Qobuz URL...",
69 | "searchTextboxPlaceholder": "输入你的搜索内容...",
70 | "downloadFolderPlaceholder": "未选择文件夹",
71 | "userInfoTextboxPlaceholder": "用户 ID = {user_id}\r\n邮箱 = {user_email}\r\n国家 = {user_country}\r\n订阅 = {user_subscription}\r\n到期 = {user_subscription_expiration}",
72 | "downloadOutputWelcome": "欢迎 {user_display_name}!",
73 | "downloadOutputExpired": "你的订阅已过期,下载将仅限于 30 秒的片段!",
74 | "downloadOutputPath": "下载路径",
75 | "downloadOutputNoPath": "未设置路径! 记得选择一个文件夹!",
76 | "downloadOutputAPIError": "Qobuz API 错误。可能是该发行版在当前账户地区不可用?",
77 | "downloadOutputNotImplemented": "尚未实现或 URL 无法理解。是否有拼写错误?",
78 | "downloadOutputCheckLink": "正在检查链接...",
79 | "downloadOutputTrNotStream": "曲目{TrackNumber}不支持流媒体播放。跳过。",
80 | "downloadOutputAlNotStream": "发行版不支持流媒体播放。",
81 | "downloadOutputGoodyFound": "找到歌曲,正在下载...",
82 | "downloadOutputGoodyExists": "歌曲文件已存在",
83 | "downloadOutputGoodyNoURL": "未找到歌曲的下载 URL,跳过",
84 | "downloadOutputFileExists": "曲目{TrackNumber}的文件已存在,跳过。",
85 | "downloadOutputDownloading": "正在下载",
86 | "downloadOutputDone": "完成",
87 | "downloadOutputCompleted": "下载完成",
88 | "progressLabelInactive": "无下载任务",
89 | "progressLabelActive": "下载进度",
90 | "_SECTION5_": "=================== 登录表单按钮 ===================",
91 | "closeAboutButton": "关闭",
92 | "customSaveButton": "保存",
93 | "exitButton": "退出",
94 | "loginButton": "登录",
95 | "_SECTION6_": "=================== 登录表单标签 ===================",
96 | "appidLabel": "App ID",
97 | "appSecretLabel": "App Secret",
98 | "customLabel": "使用自定义 App ID + Secret",
99 | "_SECTION7_": "=================== 登录表单文本框 ===================",
100 | "customInfoTextbox": "如果想自动获取值,请留空!",
101 | "aboutTextbox": "版本 - {version}\r\n由 AiiR 创建\r\n\r\n受 Qo-DL 启发\r\n(由 Sorrow 和 DashLt 创建)\r\n\r\n感谢 Github 和 Telegram 上的用户提供的错误报告和想法! 还要特别感谢 DJDoubleD,在我忙碌的时候保持了原版的运行!",
102 | "_SECTION8_": "=================== 登录表单占位符 ===================",
103 | "emailPlaceholder": "请输入邮箱",
104 | "passwordPlaceholder": "请输入密码",
105 | "tokenPlaceholder": "Token",
106 | "altLoginLabelToken": "使用 Token 登录",
107 | "altLoginLabelEmail": "使用邮箱和密码登录",
108 | "loginTextWaiting": "等待登录...",
109 | "loginTextStart": "正在登录...",
110 | "loginTextError": "登录失败,已保存错误日志",
111 | "loginTextNoEmail": "输入中没有邮箱",
112 | "loginTextNoPassword": "输入中没有密码/Token",
113 | "updateNotification": "QBDLX 的新版本可用!\r\n\r\n已安装版本 - {currentVersion}\r\n最新版本 - {newVersion}\r\n\r\n更新日志如下\r\n==============\r\n{changelog}\r\n==============\r\n\r\n你是否要更新?",
114 | "updateNotificationTitle": "QBDLX | 有可用更新"
115 | }
116 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/Languages/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "TranslationCredit": "AiiR",
3 | "TranslationUpdatedOn": "November 17, 2024, 12:38PM EST",
4 | "TranslationFont": "Nirmala UI",
5 | "_SECTION1_": "=================== MAIN FORM BUTTONS ===================",
6 | "additionalSettingsButton": "Additional Settings",
7 | "aboutButton": "ABOUT",
8 | "closeAdditionalButton": "Back to Settings",
9 | "downloadButton": "GET",
10 | "downloaderButton": "DOWNLOADER",
11 | "logoutButton": "LOGOUT",
12 | "openFolderButton": "Open Folder",
13 | "qualitySelectButton": "Quality Selector",
14 | "saveTemplatesButton": "Save",
15 | "searchButton": "SEARCH",
16 | "searchAlbumsButton": "RELEASES",
17 | "searchTracksButton": "TRACKS",
18 | "selectFolderButton": "Select Folder",
19 | "settingsButton": "SETTINGS",
20 | "_SECTION2_": "=================== MAIN FORM LABELS ===================",
21 | "advancedOptionsLabel": "ADVANCED OPTIONS",
22 | "albumTemplateLabel": "ALBUM TEMPLATE",
23 | "artistTemplateLabel": "ARTIST TEMPLATE",
24 | "commentLabel": "Custom Comment",
25 | "downloadFolderLabel": "DOWNLOAD FOLDER",
26 | "downloadOptionsLabel": "DOWNLOAD OPTIONS",
27 | "embeddedArtLabel": "Embedded Artwork Size",
28 | "extraSettingsLabel": "ADDITIONAL SETTINGS",
29 | "languageLabel": "Current Language",
30 | "playlistTemplateLabel": "PLAYLIST TEMPLATE",
31 | "favoritesTemplateLabel": "FAVORITES TEMPLATE",
32 | "savedArtLabel": "Saved Artwork Size",
33 | "searchingLabel": "Searching...",
34 | "taggingOptionsLabel": "TAGGING OPTIONS",
35 | "templatesLabel": "TEMPLATES",
36 | "templatesListLabel": "TEMPLATES LIST",
37 | "themeLabel": "Current Theme",
38 | "themeSectionLabel": "THEMING OPTIONS",
39 | "trackTemplateLabel": "TRACK TEMPLATE",
40 | "userInfoLabel": "USER INFO",
41 | "welcomeLabel": "Welcome\r\n{username}",
42 | "_SECTION3_": "=================== MAIN FORM CHECKBOXES ===================",
43 | "albumArtistCheckbox": "Album Artist",
44 | "albumTitleCheckbox": "Album Title",
45 | "trackArtistCheckbox": "Track Artist",
46 | "trackTitleCheckbox": "Track Title",
47 | "releaseDateCheckbox": "Release Date",
48 | "releaseTypeCheckbox": "Release Type",
49 | "genreCheckbox": "Genre",
50 | "trackNumberCheckbox": "Track Number",
51 | "trackTotalCheckbox": "Total Tracks",
52 | "discNumberCheckbox": "Disc Number",
53 | "discTotalCheckbox": "Total Discs",
54 | "composerCheckbox": "Composer",
55 | "explicitCheckbox": "Explicit Advisory",
56 | "coverArtCheckbox": "Cover Art",
57 | "copyrightCheckbox": "Copyright",
58 | "labelCheckbox": "Label",
59 | "upcCheckbox": "UPC / Barcode",
60 | "isrcCheckbox": "ISRC",
61 | "streamableCheckbox": "Streamable Check",
62 | "fixMD5sCheckbox": "Auto-Fix Unset MD5s (must have FLAC in PATH variables)",
63 | "downloadSpeedCheckbox": "Print Download Speed",
64 | "_SECTION4_": "=================== MAIN FORM PLACEHOLDERS ===================",
65 | "albumLabelPlaceholder": "Welcome to QBDLX!",
66 | "artistLabelPlaceholder": "Input your Qobuz link and hit GET!",
67 | "infoLabelPlaceholder": "Released",
68 | "inputTextboxPlaceholder": "Paste a Qobuz URL...",
69 | "searchTextboxPlaceholder": "Input your search...",
70 | "downloadFolderPlaceholder": "No folder selected",
71 | "userInfoTextboxPlaceholder": "User ID = {user_id}\r\nE-mail = {user_email}\r\nCountry = {user_country}\r\nSubscription = {user_subscription}\r\nExpires = {user_subscription_expiration}",
72 | "downloadOutputWelcome": "Welcome {user_display_name}!",
73 | "downloadOutputExpired": "YOUR SUBSCRIPTION HAS EXPIRED, DOWNLOADS WILL BE LIMITED TO 30 SECOND SNIPPETS!",
74 | "downloadOutputPath": "Download Path",
75 | "downloadOutputNoPath": "No path has been set! Remember to Choose a Folder!",
76 | "downloadOutputAPIError": "Qobuz API error. Maybe release isn't available in this account region?",
77 | "downloadOutputNotImplemented": "Not implemented yet or the URL is not understood. Is there a typo?",
78 | "downloadOutputCheckLink": "Checking Link...",
79 | "downloadOutputTrNotStream": "Track {TrackNumber} is not available for streaming. Skipping.",
80 | "downloadOutputAlNotStream": "Release is not available for streaming.",
81 | "downloadOutputGoodyFound": "Goody found, downloading...",
82 | "downloadOutputGoodyExists": "File for goody already exists",
83 | "downloadOutputGoodyNoURL": "No download URL found for goody, skipping",
84 | "downloadOutputFileExists": "File for track {TrackNumber} already exists, skipping.",
85 | "downloadOutputDownloading": "Downloading",
86 | "downloadOutputDone": "DONE",
87 | "downloadOutputCompleted": "DOWNLOAD COMPLETE",
88 | "progressLabelInactive": "No download active",
89 | "progressLabelActive": "Download progress",
90 | "_SECTION5_": "=================== LOGIN FORM BUTTONS ===================",
91 | "closeAboutButton": "CLOSE",
92 | "customSaveButton": "SAVE",
93 | "exitButton": "EXIT",
94 | "loginButton": "LOGIN",
95 | "_SECTION6_": "=================== LOGIN FORM LABELS ===================",
96 | "appidLabel": "App ID",
97 | "appSecretLabel": "App Secret",
98 | "customLabel": "USE CUSTOM APP ID + SECRET",
99 | "_SECTION7_": "=================== LOGIN FORM TEXTBOXES ===================",
100 | "customInfoTextbox": "Leave values blank if you would like to automatically grab the values!",
101 | "aboutTextbox": "Version - {version}\r\nCreated by AiiR\r\n\r\nInspired By Qo-DL\r\n(Created by Sorrow and DashLt)\r\n\r\nThanks to the users on Github and Telegram for offering bug reports and ideas! And huge shoutout to DJDoubleD for keeping the original running since I've been busy!",
102 | "_SECTION8_": "=================== LOGIN FORM PLACEHOLDERS ===================",
103 | "emailPlaceholder": "e-mail",
104 | "passwordPlaceholder": "password",
105 | "tokenPlaceholder": "token",
106 | "altLoginLabelToken": "LOGIN WITH TOKEN",
107 | "altLoginLabelEmail": "LOGIN WITH E-MAIL AND PASSWORD",
108 | "loginTextWaiting": "waiting for login...",
109 | "loginTextStart": "logging in...",
110 | "loginTextError": "login failed, error log saved",
111 | "loginTextNoEmail": "no e-mail in input",
112 | "loginTextNoPassword": "no password/token in input",
113 | "updateNotification": "New version of QBDLX is available!\r\n\r\nInstalled version - {currentVersion}\r\nLatest version - {newVersion}\r\n\r\nChangelog Below\r\n==============\r\n{changelog}\r\n==============\r\n\r\nWould you like to update?",
114 | "updateNotificationTitle": "QBDLX | Update Available"
115 | }
116 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Helpers/GetInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using QopenAPI;
3 |
4 | namespace QobuzDownloaderX
5 | {
6 | class GetInfo
7 | {
8 | public Service QoService = new Service();
9 | public User QoUser = new User();
10 | public Artist QoArtist = new Artist();
11 | public Album QoAlbum = new Album();
12 | public Item QoItem = new Item();
13 | public Favorites QoFavorites = new Favorites();
14 | public Playlist QoPlaylist = new Playlist();
15 | public QopenAPI.Label QoLabel = new QopenAPI.Label();
16 |
17 | public string outputText { get; set; }
18 |
19 | public void updateDownloadOutput(string text)
20 | {
21 | if (outputText == "Test String" | outputText == null)
22 | {
23 | qbdlxForm._qbdlxForm.update(null);
24 | outputText = qbdlxForm._qbdlxForm.downloadOutput.Text;
25 | qbdlxForm._qbdlxForm.update(text);
26 | outputText = qbdlxForm._qbdlxForm.downloadOutput.Text;
27 | }
28 | else if (text == null)
29 | {
30 | qbdlxForm._qbdlxForm.update(null);
31 | outputText = qbdlxForm._qbdlxForm.downloadOutput.Text;
32 | }
33 | else
34 | {
35 | qbdlxForm._qbdlxForm.update(outputText + text);
36 | outputText = qbdlxForm._qbdlxForm.downloadOutput.Text;
37 | }
38 |
39 | }
40 |
41 | public Artist getArtistInfo(string app_id, string artist_id, string user_auth_token)
42 | {
43 | try
44 | {
45 | // Grab artist info with auth
46 | outputText = null;
47 | qbdlxForm._qbdlxForm.logger.Debug("Getting artist Info...");
48 | QoArtist = QoService.ArtistGetWithAuth(app_id, artist_id, user_auth_token);
49 | return QoArtist;
50 | }
51 | catch (Exception getArtistInfoEx)
52 | {
53 | updateDownloadOutput("\r\n" + getArtistInfoEx.ToString());
54 | qbdlxForm._qbdlxForm.logger.Error("Failed to get artist info, error below:\r\n" + getArtistInfoEx);
55 | return null;
56 | }
57 | }
58 |
59 | public QopenAPI.Label getLabelInfo(string app_id, string label_id, string user_auth_token)
60 | {
61 | try
62 | {
63 | // Grab label info with auth
64 | outputText = null;
65 | qbdlxForm._qbdlxForm.logger.Debug("Getting label Info...");
66 | QoLabel = QoService.LabelGetWithAuth(app_id, label_id, "albums", 500, 0, user_auth_token);
67 | return QoLabel;
68 | }
69 | catch (Exception getLabelInfoEx)
70 | {
71 | updateDownloadOutput("\r\n" + getLabelInfoEx.ToString());
72 | qbdlxForm._qbdlxForm.logger.Error("Failed to get label info, error below:\r\n" + getLabelInfoEx);
73 | return null;
74 | }
75 | }
76 |
77 | public Favorites getFavoritesInfo(string app_id, string user_id, string type, string user_auth_token)
78 | {
79 | try
80 | {
81 | // Grab favorites info with auth
82 | outputText = null;
83 | qbdlxForm._qbdlxForm.logger.Debug("Getting favorites Info...");
84 | QoFavorites = QoService.FavoriteGetUserFavoritesWithAuth(app_id, user_id, type, 500, 0, user_auth_token);
85 | return QoFavorites;
86 | }
87 | catch (Exception getFavoritesInfoEx)
88 | {
89 | updateDownloadOutput("\r\n" + getFavoritesInfoEx.ToString());
90 | qbdlxForm._qbdlxForm.logger.Error("Failed to get favorites info, error below:\r\n" + getFavoritesInfoEx);
91 | return null;
92 | }
93 | }
94 |
95 | public Item getTrackInfoLabels(string app_id, string track_id, string user_auth_token)
96 | {
97 | try
98 | {
99 | // Grab track info with auth
100 | outputText = null;
101 | qbdlxForm._qbdlxForm.logger.Debug("Getting track Info...");
102 | QoItem = QoService.TrackGetWithAuth(app_id, track_id, user_auth_token);
103 | string album_id = QoItem.Album.Id;
104 | QoAlbum = QoService.AlbumGetWithAuth(app_id, album_id, user_auth_token);
105 | return QoItem;
106 | }
107 | catch (Exception getTrackInfoLabelsEx)
108 | {
109 | updateDownloadOutput("\r\n" + getTrackInfoLabelsEx.ToString());
110 | qbdlxForm._qbdlxForm.logger.Error("Failed to get track info, error below:\r\n" + getTrackInfoLabelsEx);
111 | return null;
112 | }
113 | }
114 |
115 | public Album getAlbumInfoLabels(string app_id, string album_id, string user_auth_token)
116 | {
117 | try
118 | {
119 | // Grab album info with auth
120 | outputText = null;
121 | qbdlxForm._qbdlxForm.logger.Debug("Getting album Info...");
122 | QoAlbum = QoService.AlbumGetWithAuth(app_id, album_id, user_auth_token);
123 | return QoAlbum;
124 | }
125 | catch (Exception getAlbumInfoLabelsEx)
126 | {
127 | updateDownloadOutput("\r\n" + getAlbumInfoLabelsEx.ToString());
128 | qbdlxForm._qbdlxForm.logger.Error("Failed to get album info, error below:\r\n" + getAlbumInfoLabelsEx);
129 | return null;
130 | }
131 | }
132 |
133 | public Playlist getPlaylistInfoLabels(string app_id, string playlist_id, string user_auth_token)
134 | {
135 | try
136 | {
137 | // Grab playlist info with auth
138 | outputText = null;
139 | qbdlxForm._qbdlxForm.logger.Debug("Getting playlist Info...");
140 | QoPlaylist = QoService.PlaylistGetWithAuth(app_id, playlist_id, "tracks", 500, 0, user_auth_token);
141 | return QoPlaylist;
142 | }
143 | catch (Exception getPlaylistInfoLabelsEx)
144 | {
145 | updateDownloadOutput("\r\n" + getPlaylistInfoLabelsEx.ToString());
146 | qbdlxForm._qbdlxForm.logger.Error("Failed to get playlist info, error below:\r\n" + getPlaylistInfoLabelsEx);
147 | return null;
148 | }
149 | }
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/Languages/ru.json:
--------------------------------------------------------------------------------
1 | {
2 | "TranslationCredit": "Kuzmich55",
3 | "TranslationUpdatedOn": "December 03, 2024, 11:01AM MSK",
4 | "TranslationFont": "Segoe UI",
5 | "_SECTION1_": "=================== КНОПКИ ГЛАВНОГО ОКНА ===================",
6 | "additionalSettingsButton": "Дополнительно",
7 | "aboutButton": "О ПРОГРАММЕ",
8 | "closeAdditionalButton": "Назад",
9 | "downloadButton": "ЗАГРУЗИТЬ",
10 | "downloaderButton": "ЗАГРУЗЧИК",
11 | "logoutButton": "ВЫХОД",
12 | "openFolderButton": "Открыть папку",
13 | "qualitySelectButton": "Выбор качества",
14 | "saveTemplatesButton": "Сохранить",
15 | "searchButton": "ПОИСК",
16 | "searchAlbumsButton": "РЕЛИЗЫ",
17 | "searchTracksButton": "ТРЕКИ",
18 | "selectFolderButton": "Выбрать папку",
19 | "settingsButton": "НАСТРОЙКИ",
20 | "_SECTION2_": "=================== ПОДПИСИ ГЛАВНОГО ОКНА ===================",
21 | "advancedOptionsLabel": "РАСШИРЕННЫЕ НАСТРОЙКИ",
22 | "albumTemplateLabel": "ШАБЛОН АЛЬБОМА",
23 | "artistTemplateLabel": "ШАБЛОН ИСПОЛНИТЕЛЯ",
24 | "commentLabel": "Комментарий пользователя",
25 | "downloadFolderLabel": "ПАПКА ЗАГРУЗКИ",
26 | "downloadOptionsLabel": "ПАРАМЕТРЫ ЗАГРУЗКИ",
27 | "embeddedArtLabel": "Размер встраиваемого изображения",
28 | "extraSettingsLabel": "ДОПОЛНИТЕЛЬНО",
29 | "languageLabel": "Язык интерфейса",
30 | "playlistTemplateLabel": "ШАБЛОН ПЛЕЙЛИСТА",
31 | "favoritesTemplateLabel": "ШАБЛОН ИЗБРАННОГО",
32 | "savedArtLabel": "Размер сохраняемого изображения",
33 | "searchingLabel": "Поиск...",
34 | "taggingOptionsLabel": "ПАРАМЕТРЫ ТЕГИРОВАНИЯ",
35 | "templatesLabel": "ШАБЛОНЫ",
36 | "templatesListLabel": "СПИСОК ШАБЛОНОВ",
37 | "themeLabel": "Тема оформления",
38 | "themeSectionLabel": "ПАРАМЕТРЫ ТЕМ",
39 | "trackTemplateLabel": "ШАБЛОН ТРЕКА",
40 | "userInfoLabel": "ИНФОРМАЦИЯ О ПОЛЬЗОВАТЕЛЕ",
41 | "welcomeLabel": "Добро пожаловать\r\n{username}",
42 | "_SECTION3_": "=================== ЧЕКБОКСЫ ОСНОВНОЙ ФОРМЫ ===================",
43 | "albumArtistCheckbox": "Исполнитель альбома",
44 | "albumTitleCheckbox": "Название альбома",
45 | "trackArtistCheckbox": "Исполнитель трека",
46 | "trackTitleCheckbox": "Название трека",
47 | "releaseDateCheckbox": "Дата релиза",
48 | "releaseTypeCheckbox": "Тип релиза",
49 | "genreCheckbox": "Жанр",
50 | "trackNumberCheckbox": "Номер трека",
51 | "trackTotalCheckbox": "Общее количество треков",
52 | "discNumberCheckbox": "Номер диска",
53 | "discTotalCheckbox": "Общее количество дисков",
54 | "composerCheckbox": "Композитор",
55 | "explicitCheckbox": "Предупреждение о содержании",
56 | "coverArtCheckbox": "Обложка альбома",
57 | "copyrightCheckbox": "Авторские права",
58 | "labelCheckbox": "Лейбл",
59 | "upcCheckbox": "UPC / Штрих-код",
60 | "isrcCheckbox": "ISRC",
61 | "streamableCheckbox": "Проверка возможности трансляции",
62 | "fixMD5sCheckbox": "Автоматическое исправление отсутствующих MD5 (FLAC должен быть в переменной PATH)",
63 | "downloadSpeedCheckbox": "Показывать скорость загрузки",
64 | "_SECTION4_": "=================== ПЛЕЙСХОЛДЕРЫ ОСНОВНОЙ ФОРМЫ ===================",
65 | "albumLabelPlaceholder": "Добро пожаловать в QBDLX!",
66 | "artistLabelPlaceholder": "Вставьте Qobuz URL и нажмите загрузить!",
67 | "infoLabelPlaceholder": "Дата релиза",
68 | "inputTextboxPlaceholder": "Вставьте Qobuz URL...",
69 | "searchTextboxPlaceholder": "Введите запрос...",
70 | "downloadFolderPlaceholder": "Папка не выбрана",
71 | "userInfoTextboxPlaceholder": "ID пользователя = {user_id}\r\nE-mail = {user_email}\r\nСтрана = {user_country}\r\nПодписка = {user_subscription}\r\nИстекает = {user_subscription_expiration}",
72 | "downloadOutputWelcome": "Добро пожаловать {user_display_name}!",
73 | "downloadOutputExpired": "ВАША ПОДПИСКА ИСТЕКЛА, ЗАГРУЗКИ БУДУТ ОГРАНИЧЕНЫ 30-СЕКУНДНЫМИ ФРАГМЕНТАМИ!",
74 | "downloadOutputPath": "Путь загрузки",
75 | "downloadOutputNoPath": "Путь не установлен! Не забудьте выбрать папку!",
76 | "downloadOutputAPIError": "Ошибка API Qobuz. Возможно, релиз недоступен в этом регионе аккаунта?",
77 | "downloadOutputNotImplemented": "Ещё не реализовано или URL невозможно разобрать. Возможно, есть опечатка?",
78 | "downloadOutputCheckLink": "Проверка ссылки...",
79 | "downloadOutputTrNotStream": "Трек {TrackNumber} недоступен для трансляции, пропускаем его.",
80 | "downloadOutputAlNotStream": "Релиз недоступен для трансляции.",
81 | "downloadOutputGoodyFound": "Хорошая находка, загружаем...",
82 | "downloadOutputGoodyExists": "Файл уже существует",
83 | "downloadOutputGoodyNoURL": "Не найден URL для загрузки, пропускаем его.",
84 | "downloadOutputFileExists": "Файл {TrackNumber} трека уже существует, пропускаем его.",
85 | "downloadOutputDownloading": "Загрузка",
86 | "downloadOutputDone": "ГОТОВО",
87 | "downloadOutputCompleted": "ЗАГРУЗКА ЗАВЕРШЕНА",
88 | "progressLabelInactive": "Активных загрузок нет",
89 | "progressLabelActive": "Прогресс загрузки",
90 | "_SECTION5_": "=================== КНОПКИ ФОРМЫ АВТОРИЗАЦИИ ===================",
91 | "closeAboutButton": "ЗАКРЫТЬ",
92 | "customSaveButton": "СОХРАНИТЬ",
93 | "exitButton": "ВЫХОД",
94 | "loginButton": "ВХОД",
95 | "_SECTION6_": "=================== ПОДПИСИ ФОРМЫ АВТОРИЗАЦИИ ===================",
96 | "appidLabel": "App ID",
97 | "appSecretLabel": "App Secret",
98 | "customLabel": "ИСПОЛЬЗОВАТЬ СВОЙ APP ID + SECRET",
99 | "_SECTION7_": "=================== ТЕКСТОВЫЕ ПОЛЯ ФОРМЫ АВТОРИЗАЦИИ ===================",
100 | "customInfoTextbox": "Оставьте поля пустыми, чтобы заполнить значения автоматически!",
101 | "aboutTextbox": "Версия - {version}\r\nСоздано AiiR\r\n\r\nВдохновлено Qo-DL\r\n(Создано Sorrow и DashLt)\r\n\r\nСпасибо пользователям на Github и в Telegram за отчеты об ошибках и идеи! И огромное спасибо DJDoubleD за поддержку оригинала, пока я был занят!",
102 | "_SECTION8_": "=================== ПЛЕЙСХОЛДЕРЫ ФОРМЫ АВТОРИЗАЦИИ ===================",
103 | "emailPlaceholder": "e-mail",
104 | "passwordPlaceholder": "пароль",
105 | "tokenPlaceholder": "токен",
106 | "altLoginLabelToken": "ВХОД ПО ТОКЕНУ",
107 | "altLoginLabelEmail": "ВХОД ПО E-MAIL И ПАРОЛЮ",
108 | "loginTextWaiting": "ожидание входа...",
109 | "loginTextStart": "вход в систему...",
110 | "loginTextError": "вход не выполнен, ошибка сохранена в журнал",
111 | "loginTextNoEmail": "в поле ввода отсутствует e-mail",
112 | "loginTextNoPassword": "в поле ввода отсутствует пароль/токен",
113 | "updateNotification": "Доступна новая версия QBDLX!\r\n\r\nУстановлена версия - {currentVersion}\r\nПоследняя версия - {newVersion}\r\n\r\nЖурнал изменений\r\n==============\r\n{changelog}\r\n==============\r\n\r\nВы хотите обновить?",
114 | "updateNotificationTitle": "QBDLX | Доступно обновление"
115 | }
116 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Resources/Languages/de.json:
--------------------------------------------------------------------------------
1 | {
2 | "TranslationCredit": "TheParaTiger",
3 | "TranslationUpdatedOn": "November 24, 2024, 09:37AM MET",
4 | "TranslationFont": "Nirmala UI",
5 | "_SECTION1_": "=================== MAIN FORM BUTTONS ===================",
6 | "additionalSettingsButton": "Weitere Optionen",
7 | "aboutButton": "ÜBER",
8 | "closeAdditionalButton": "Optionen",
9 | "downloadButton": "HOLEN!",
10 | "downloaderButton": "DOWNLOADER",
11 | "logoutButton": "AUSLOGGEN",
12 | "openFolderButton": "Ordner Öffnen",
13 | "qualitySelectButton": "Qualität",
14 | "saveTemplatesButton": "Speichern",
15 | "searchButton": "SUCHE",
16 | "searchAlbumsButton": "ALBUM",
17 | "searchTracksButton": "TRACK",
18 | "selectFolderButton": "Ordner Auswählen",
19 | "settingsButton": "OPTIONEN",
20 | "_SECTION2_": "=================== MAIN FORM LABELS ===================",
21 | "advancedOptionsLabel": "Weitere Optionen",
22 | "albumTemplateLabel": "ALBUM VORLAGE",
23 | "artistTemplateLabel": "ARTIST VORLAGE",
24 | "commentLabel": "Eigener Kommentar",
25 | "downloadFolderLabel": "DOWNLOAD ORDNER",
26 | "downloadOptionsLabel": "DOWNLOAD OPTIONEN",
27 | "embeddedArtLabel": "Eingebettete Artwork Größe",
28 | "extraSettingsLabel": "WEITERE OPTIONEN",
29 | "languageLabel": "Aktuelle Sprache",
30 | "playlistTemplateLabel": "PLAYLIST VORLAGE",
31 | "favoritesTemplateLabel": "FAVORITEN VORLAGE",
32 | "savedArtLabel": "Gespeicherte Artwork Größe",
33 | "searchingLabel": "Suche...",
34 | "taggingOptionsLabel": "TAG OPTIONEN",
35 | "templatesLabel": "VORLAGEN",
36 | "templatesListLabel": "VORLAGEN LISTE",
37 | "themeLabel": "Aktuelles Theme",
38 | "themeSectionLabel": "THEME OPTIONEN",
39 | "trackTemplateLabel": "TRACK VORLAGE",
40 | "userInfoLabel": "BENUTZERINFO",
41 | "welcomeLabel": "Willkommen\r\n{username}",
42 | "_SECTION3_": "=================== MAIN FORM CHECKBOXES ===================",
43 | "albumArtistCheckbox": "Album Artist",
44 | "albumTitleCheckbox": "Album Titel",
45 | "trackArtistCheckbox": "Track Artist",
46 | "trackTitleCheckbox": "Track Titel",
47 | "releaseDateCheckbox": "Veröffentlichungsdatum",
48 | "releaseTypeCheckbox": "Veröffentlichungstyp",
49 | "genreCheckbox": "Genre",
50 | "trackNumberCheckbox": "Track Nummer",
51 | "trackTotalCheckbox": "Totale Anzahl Tracks",
52 | "discNumberCheckbox": "CD-Nummer",
53 | "discTotalCheckbox": "Totale Anzahl CDs",
54 | "composerCheckbox": "Komponist",
55 | "explicitCheckbox": "Explizit",
56 | "coverArtCheckbox": "Cover Art",
57 | "copyrightCheckbox": "Copyright",
58 | "labelCheckbox": "Label",
59 | "upcCheckbox": "UPC / Barcode",
60 | "isrcCheckbox": "ISRC",
61 | "streamableCheckbox": "Ist Streamfähig Check",
62 | "fixMD5sCheckbox": "Nicht gesetzte MD5s setzen (muss FLAC in der PATH Variable haben)",
63 | "downloadSpeedCheckbox": "Downloadgeschwindigkeit Anzeigen",
64 | "_SECTION4_": "=================== MAIN FORM PLACEHOLDERS ===================",
65 | "albumLabelPlaceholder": "Willkommen in QBDLX!",
66 | "artistLabelPlaceholder": "Füge einen Qobuz-Link ein und Klicke HOLEN!",
67 | "infoLabelPlaceholder": "Veröffentlicht:",
68 | "inputTextboxPlaceholder": "Qobuz URL Eingeben...",
69 | "searchTextboxPlaceholder": "Suchbegriff eingeben...",
70 | "downloadFolderPlaceholder": "Kein Ordner Ausgewählt",
71 | "userInfoTextboxPlaceholder": "Nutzer ID = {user_id}\r\nE-Mail = {user_email}\r\nLand = {user_country}\r\nAbonnement = {user_subscription}\r\nLäuft ab = {user_subscription_expiration}",
72 | "downloadOutputWelcome": "Willkommen {user_display_name}!",
73 | "downloadOutputExpired": "DEIN ABONNEMENT IST ABGELAUFEN!, ES WERDEN NUR 30-SEKUNDEN AUSSCHNITTE HERUNTERGELADEN!",
74 | "downloadOutputPath": "Download Pfad",
75 | "downloadOutputNoPath": "Es wurde kein Pfad gesetzt! Denke daran einen Ordner auszuwählen!",
76 | "downloadOutputAPIError": "Qobuz-API Fehler, ist dieses Album in deiner Region verfügbar?",
77 | "downloadOutputNotImplemented": "Noch nicht Implementiert oder nicht verstanden, hast du dich vielleicht vertippt?",
78 | "downloadOutputCheckLink": "Überprüfe Link...",
79 | "downloadOutputTrNotStream": "Track {TrackNumber} ist nicht fürs Streamen verfügbar und wird Übersprungen",
80 | "downloadOutputAlNotStream": "Album ist nicht fürs Streaming verfügbar.",
81 | "downloadOutputGoodyFound": "Zusatzinhalte gefunden. Es wird versucht, sie Herunterzuladen...",
82 | "downloadOutputGoodyExists": "Die Datei für den Zusatzinhalt existiert bereits.",
83 | "downloadOutputGoodyNoURL": "Keine Download URL für den Zusatzinhalt gefunden. Er wird Übersprungen",
84 | "downloadOutputFileExists": "Die Datei für den Track {TrackNumber} existiert bereits und wird Übersprungen",
85 | "downloadOutputDownloading": "Lädt Herunter",
86 | "downloadOutputDone": "FERTIG",
87 | "downloadOutputCompleted": "DOWNLOAD FERTIG!",
88 | "progressLabelInactive": "Kein Download aktiv",
89 | "progressLabelActive": "Download Fortschritt",
90 | "_SECTION5_": "=================== LOGIN FORM BUTTONS ===================",
91 | "closeAboutButton": "SCHLIEßEN",
92 | "customSaveButton": "SPEICHERN",
93 | "exitButton": "VERLASSEN",
94 | "loginButton": "EINLOGGEN",
95 | "_SECTION6_": "=================== LOGIN FORM LABELS ===================",
96 | "appidLabel": "App ID",
97 | "appSecretLabel": "App Secret",
98 | "customLabel": "EIGENE APP ID + SECRET NUTZEN",
99 | "_SECTION7_": "=================== LOGIN FORM TEXTBOXES ===================",
100 | "customInfoTextbox": "Felder leerlassen wenn du willst, dass das Programm die Werte selber holt.",
101 | "aboutTextbox": "Version - {version}\r\nErstellt von AiiR\r\n\r\nInspiriert von Qo-DL\r\n(Erstellt von Sorrow und DashLt)\r\n\r\nDanke an die Benutzer von GitHub und Telegramm für die Fehlerberichte und Ideen! Und ein großes Dankeschön an DJDoubleD für die Weiterentwicklung des ursprünglichen Programms während ich Beschäftigt war!",
102 | "_SECTION8_": "=================== LOGIN FORM PLACEHOLDERS ===================",
103 | "emailPlaceholder": "E-Mail",
104 | "passwordPlaceholder": "Passwort",
105 | "tokenPlaceholder": "Token",
106 | "altLoginLabelToken": "MIT TOKEN ANMELDEN",
107 | "altLoginLabelEmail": "MIT E-MAIL UND PASSWORT ANMELDEN",
108 | "loginTextWaiting": "Wartet auf das Einloggen...",
109 | "loginTextStart": "Loggt sich ein...",
110 | "loginTextError": "Login fehlgeschlagen. Der Fehler wurde im Fehler-log gespeichert.",
111 | "loginTextNoEmail": "Keine E-Mail in dem Feld",
112 | "loginTextNoPassword": "Kein Passwort/Token in dem Feld",
113 | "updateNotification": "Eine neue Version von QBDLX ist verfügbar!\r\n\r\nInstallierte Version - {currentVersion}\r\nNeueste Version - {newVersion}\r\n\r\nÄnderungsliste\r\n==============\r\n{changelog}\r\n==============\r\n\r\nMöchtest du aktualisieren?",
114 | "updateNotificationTitle": "QBDLX | Update Verfügbar"
115 | }
116 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Helpers/TagFile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using TagLib;
4 | using File = TagLib.File;
5 | using QobuzDownloaderX.Properties;
6 | using QopenAPI;
7 | using TagLib.Id3v2;
8 | using System.Text.RegularExpressions;
9 |
10 | namespace QobuzDownloaderX
11 | {
12 | class TagFile
13 | {
14 | public static void WriteToFile(string tempPath, string artworkPath, Album QoAlbum, Item QoItem)
15 | {
16 | using (var file = File.Create(tempPath))
17 | {
18 | bool isFlac = tempPath.Contains(".flac");
19 | qbdlxForm._qbdlxForm.logger.Debug(isFlac ? "FLAC detected, setting FLAC specific tags" : "Non-FLAC detected, setting MP3 specific tags");
20 |
21 | if (isFlac)
22 | {
23 | var customTagsFLAC = (TagLib.Ogg.XiphComment)file.GetTag(TagLib.TagTypes.Xiph);
24 | SetFlacTags(customTagsFLAC, QoAlbum, QoItem);
25 | }
26 | else
27 | {
28 | var mp3Tag = (TagLib.Id3v2.Tag)file.GetTag(TagTypes.Id3v2, true);
29 | SetMp3Tags(mp3Tag, QoAlbum, QoItem);
30 | }
31 |
32 | SetCommonTags(file, QoAlbum, QoItem);
33 | SetAlbumArtists(file, QoAlbum);
34 | EmbedArtwork(file, artworkPath);
35 |
36 | // Save All Tags
37 | file.Save();
38 | qbdlxForm._qbdlxForm.logger.Debug("File tagging completed!");
39 | }
40 | }
41 |
42 | private static void SetFlacTags(TagLib.Ogg.XiphComment customTags, Album QoAlbum, Item QoItem)
43 | {
44 | if (Settings.Default.yearTag) customTags.SetField("DATE", QoAlbum.ReleaseDateOriginal);
45 | if (Settings.Default.isrcTag) customTags.SetField("ISRC", QoItem.ISRC);
46 | if (Settings.Default.typeTag) customTags.SetField("MEDIATYPE", QoAlbum.ProductType.ToUpper());
47 | if (Settings.Default.upcTag) customTags.SetField("BARCODE", QoAlbum.UPC);
48 | if (Settings.Default.labelTag) customTags.SetField("LABEL", Regex.Replace(QoAlbum.Label.Name, @"\s+", " "));
49 | if (Settings.Default.explicitTag) customTags.SetField("ITUNESADVISORY", QoItem.ParentalWarning ? "1" : "0");
50 | if (Settings.Default.commentTag && !string.IsNullOrEmpty(Settings.Default.commentText))
51 | {
52 | customTags.SetField("COMMENT", new string[]
53 | {
54 | Regex.Replace(Settings.Default.commentText, @"%(.*?)%", match => match.Value.ToLower())
55 | .Replace("%description%", QoAlbum.Description)
56 | .Replace("
", Environment.NewLine)
57 | .Replace("
", Environment.NewLine)
58 | });
59 | }
60 | }
61 |
62 | private static void SetMp3Tags(TagLib.Id3v2.Tag mp3Tag, Album QoAlbum, Item QoItem)
63 | {
64 | if (Settings.Default.upcTag) UserTextInformationFrame.Get(mp3Tag, "BARCODE", true).Text = new[] { QoAlbum.UPC };
65 | if (Settings.Default.explicitTag) UserTextInformationFrame.Get(mp3Tag, "ITUNESADVISORY", true).Text = new[] { QoItem.ParentalWarning ? "1" : "0" };
66 | if (Settings.Default.yearTag) mp3Tag.Year = uint.Parse(QoAlbum.ReleaseDateOriginal.Substring(0, 4));
67 | if (Settings.Default.isrcTag) mp3Tag.SetTextFrame("TSRC", QoItem.ISRC);
68 | if (Settings.Default.labelTag) mp3Tag.SetTextFrame("TPUB", Regex.Replace(QoAlbum.Label.Name, @"\s+", " "));
69 | if (Settings.Default.typeTag) mp3Tag.SetTextFrame("TMED", QoAlbum.ProductType.ToUpper());
70 | if (Settings.Default.commentTag && !string.IsNullOrEmpty(Settings.Default.commentText))
71 | {
72 | mp3Tag.Comment = Regex.Replace(Settings.Default.commentText, @"%(.*?)%", match => match.Value.ToLower())
73 | .Replace("%description%", QoAlbum.Description)
74 | .Replace("
", Environment.NewLine)
75 | .Replace("
", Environment.NewLine);
76 | }
77 | }
78 |
79 | private static void SetCommonTags(TagLib.File file, Album QoAlbum, Item QoItem)
80 | {
81 | if (Settings.Default.trackTitleTag) file.Tag.Title = QoItem.Version == null ? QoItem.Title : $"{QoItem.Title.TrimEnd()} ({QoItem.Version})";
82 | if (Settings.Default.artistTag) file.Tag.Performers = new[] { QoItem.Performer?.Name };
83 | if (Settings.Default.genreTag) file.Tag.Genres = new[] { QoAlbum.Genre.Name };
84 | if (Settings.Default.albumTag) file.Tag.Album = QoAlbum.Version == null ? QoAlbum.Title : $"{QoAlbum.Title.TrimEnd()} ({QoAlbum.Version})";
85 | if (Settings.Default.composerTag) file.Tag.Composers = new[] { QoItem.Composer?.Name };
86 | if (Settings.Default.trackTag) file.Tag.Track = (uint)QoItem.TrackNumber;
87 | if (Settings.Default.totalTracksTag) file.Tag.TrackCount = (uint)QoAlbum.TracksCount;
88 | if (Settings.Default.discTag) file.Tag.Disc = (uint)QoItem.MediaNumber;
89 | if (Settings.Default.totalDiscsTag) file.Tag.DiscCount = (uint)QoAlbum.MediaCount;
90 | if (Settings.Default.copyrightTag) file.Tag.Copyright = QoAlbum.Copyright;
91 | }
92 |
93 | private static void SetAlbumArtists(TagLib.File file, Album QoAlbum)
94 | {
95 | if (!Settings.Default.albumArtistTag) return;
96 |
97 | var mainArtists = QoAlbum.Artists.Where(a => a.Roles.Contains("main-artist")).ToList();
98 | if (mainArtists.Count > 1)
99 | {
100 | var allButLastArtist = string.Join(", ", mainArtists.Take(mainArtists.Count - 1).Select(a => a.Name));
101 | var lastArtist = mainArtists.Last().Name;
102 | file.Tag.AlbumArtists = new[] { $"{allButLastArtist} & {lastArtist}" };
103 | return;
104 | }
105 |
106 | file.Tag.AlbumArtists = new[] { QoAlbum.Artist.Name };
107 | }
108 |
109 | private static void EmbedArtwork(TagLib.File file, string artworkPath)
110 | {
111 | if (!Settings.Default.imageTag) return;
112 | try
113 | {
114 | qbdlxForm._qbdlxForm.logger.Debug("Attempting to embed artwork");
115 | var pic = new AttachedPictureFrame
116 | {
117 | TextEncoding = TagLib.StringType.Latin1,
118 | MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg,
119 | Type = PictureType.FrontCover,
120 | Data = ByteVector.FromPath(artworkPath)
121 | };
122 | file.Tag.Pictures = new IPicture[] { pic };
123 | qbdlxForm._qbdlxForm.logger.Debug("Artwork embed complete");
124 | }
125 | catch
126 | {
127 | qbdlxForm._qbdlxForm.logger.Error("Unable to write embedded artwork");
128 | }
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace QobuzDownloaderX.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("QobuzDownloaderX.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized resource of type System.Drawing.Bitmap.
65 | ///
66 | internal static System.Drawing.Bitmap alert {
67 | get {
68 | object obj = ResourceManager.GetObject("alert", resourceCulture);
69 | return ((System.Drawing.Bitmap)(obj));
70 | }
71 | }
72 |
73 | ///
74 | /// Looks up a localized resource of type System.Drawing.Bitmap.
75 | ///
76 | internal static System.Drawing.Bitmap email {
77 | get {
78 | object obj = ResourceManager.GetObject("email", resourceCulture);
79 | return ((System.Drawing.Bitmap)(obj));
80 | }
81 | }
82 |
83 | ///
84 | /// Looks up a localized resource of type System.Drawing.Bitmap.
85 | ///
86 | internal static System.Drawing.Bitmap info {
87 | get {
88 | object obj = ResourceManager.GetObject("info", resourceCulture);
89 | return ((System.Drawing.Bitmap)(obj));
90 | }
91 | }
92 |
93 | ///
94 | /// Looks up a localized resource of type System.Drawing.Bitmap.
95 | ///
96 | internal static System.Drawing.Bitmap log_out {
97 | get {
98 | object obj = ResourceManager.GetObject("log_out", resourceCulture);
99 | return ((System.Drawing.Bitmap)(obj));
100 | }
101 | }
102 |
103 | ///
104 | /// Looks up a localized resource of type System.Drawing.Bitmap.
105 | ///
106 | internal static System.Drawing.Bitmap logout {
107 | get {
108 | object obj = ResourceManager.GetObject("logout", resourceCulture);
109 | return ((System.Drawing.Bitmap)(obj));
110 | }
111 | }
112 |
113 | ///
114 | /// Looks up a localized resource of type System.Drawing.Bitmap.
115 | ///
116 | internal static System.Drawing.Bitmap password {
117 | get {
118 | object obj = ResourceManager.GetObject("password", resourceCulture);
119 | return ((System.Drawing.Bitmap)(obj));
120 | }
121 | }
122 |
123 | ///
124 | /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
125 | ///
126 | internal static System.Drawing.Icon QBDLX_Icon1 {
127 | get {
128 | object obj = ResourceManager.GetObject("QBDLX_Icon1", resourceCulture);
129 | return ((System.Drawing.Icon)(obj));
130 | }
131 | }
132 |
133 | ///
134 | /// Looks up a localized resource of type System.Drawing.Bitmap.
135 | ///
136 | internal static System.Drawing.Bitmap qbdlx_new {
137 | get {
138 | object obj = ResourceManager.GetObject("qbdlx_new", resourceCulture);
139 | return ((System.Drawing.Bitmap)(obj));
140 | }
141 | }
142 |
143 | ///
144 | /// Looks up a localized resource of type System.Drawing.Bitmap.
145 | ///
146 | internal static System.Drawing.Bitmap search {
147 | get {
148 | object obj = ResourceManager.GetObject("search", resourceCulture);
149 | return ((System.Drawing.Bitmap)(obj));
150 | }
151 | }
152 |
153 | ///
154 | /// Looks up a localized resource of type System.Drawing.Bitmap.
155 | ///
156 | internal static System.Drawing.Bitmap settings {
157 | get {
158 | object obj = ResourceManager.GetObject("settings", resourceCulture);
159 | return ((System.Drawing.Bitmap)(obj));
160 | }
161 | }
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | True
22 |
23 |
24 | True
25 |
26 |
27 | True
28 |
29 |
30 | True
31 |
32 |
33 | True
34 |
35 |
36 | True
37 |
38 |
39 | True
40 |
41 |
42 | True
43 |
44 |
45 | True
46 |
47 |
48 | True
49 |
50 |
51 | True
52 |
53 |
54 | True
55 |
56 |
57 | True
58 |
59 |
60 | True
61 |
62 |
63 | True
64 |
65 |
66 | False
67 |
68 |
69 | True
70 |
71 |
72 | True
73 |
74 |
75 |
76 |
77 |
78 | False
79 |
80 |
81 | False
82 |
83 |
84 | False
85 |
86 |
87 | True
88 |
89 |
90 | 27
91 |
92 |
93 | .flac
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | False
103 |
104 |
105 | 2
106 |
107 |
108 | True
109 |
110 |
111 | 36
112 |
113 |
114 | 1
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 | %TrackNumber% %TrackTitle%
124 |
125 |
126 | %AlbumTitle%
127 |
128 |
129 | %ArtistName%
130 |
131 |
132 | %PlaylistTitle%
133 |
134 |
135 | - Favorites
136 |
137 |
138 | 0
139 |
140 |
141 | True
142 |
143 |
144 | True
145 |
146 |
147 | True
148 |
149 |
150 | False
151 |
152 |
153 | Dark
154 |
155 |
156 | EN
157 |
158 |
159 | AiiR
160 |
161 |
162 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | True
30 |
31 |
32 | True
33 |
34 |
35 | True
36 |
37 |
38 | True
39 |
40 |
41 | True
42 |
43 |
44 | True
45 |
46 |
47 | True
48 |
49 |
50 | True
51 |
52 |
53 | True
54 |
55 |
56 | True
57 |
58 |
59 | True
60 |
61 |
62 | True
63 |
64 |
65 | True
66 |
67 |
68 | True
69 |
70 |
71 | True
72 |
73 |
74 | False
75 |
76 |
77 | True
78 |
79 |
80 | True
81 |
82 |
83 |
84 |
85 |
86 | False
87 |
88 |
89 | False
90 |
91 |
92 | False
93 |
94 |
95 | True
96 |
97 |
98 | 27
99 |
100 |
101 | .flac
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | False
111 |
112 |
113 | 2
114 |
115 |
116 | True
117 |
118 |
119 | 36
120 |
121 |
122 | 1
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | %TrackNumber% %TrackTitle%
132 |
133 |
134 | %AlbumTitle%
135 |
136 |
137 | %ArtistName%
138 |
139 |
140 | %PlaylistTitle%
141 |
142 |
143 | - Favorites
144 |
145 |
146 | 0
147 |
148 |
149 | True
150 |
151 |
152 | True
153 |
154 |
155 | True
156 |
157 |
158 | False
159 |
160 |
161 | Dark
162 |
163 |
164 | EN
165 |
166 |
167 | AiiR
168 |
169 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Helpers/Updating.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System;
3 | using Newtonsoft.Json.Linq;
4 | using System.Net.Http;
5 | using System.Threading.Tasks;
6 | using System.Reflection;
7 | using System.Net;
8 | using ZetaLongPaths;
9 |
10 | namespace QobuzDownloaderX.Helpers
11 | {
12 | public class TranslationUpdater
13 | {
14 | // List of language files
15 | private static readonly Dictionary LanguageFiles = new Dictionary
16 | {
17 | { "en.json", "Languages/en.json" },
18 | { "ru.json", "Languages/ru.json" },
19 | { "zh-cn.json", "Languages/zh-cn.json" }
20 | };
21 |
22 | public static async Task CheckAndUpdateLanguageFiles()
23 | {
24 | using (HttpClient client = new HttpClient())
25 | {
26 | client.DefaultRequestHeaders.Add("User-Agent", "TranslationUpdater");
27 |
28 | foreach (var languageFile in LanguageFiles)
29 | {
30 | string fileName = languageFile.Key;
31 | string localFilePath = languageFile.Value;
32 |
33 | string apiUrl = $"https://api.github.com/repos/ImAiiR/QobuzDownloaderX/contents/QobuzDownloaderX/Resources/{localFilePath}";
34 |
35 | try
36 | {
37 | HttpResponseMessage response = await client.GetAsync(apiUrl);
38 | if (response.IsSuccessStatusCode)
39 | {
40 | string jsonResponse = await response.Content.ReadAsStringAsync();
41 | JObject fileMetadata = JObject.Parse(jsonResponse);
42 |
43 | // Retrieve the download URL for the remote file
44 | string downloadUrl = fileMetadata["download_url"]?.ToString();
45 | if (!string.IsNullOrEmpty(downloadUrl))
46 | {
47 | // Fetch the remote file content
48 | string remoteContent = await client.GetStringAsync(downloadUrl);
49 |
50 | // Parse the "TranslationUpdatedOn" field from the remote file
51 | JObject remoteJson = JObject.Parse(remoteContent);
52 | string remoteUpdatedOnString = remoteJson["TranslationUpdatedOn"]?.ToString();
53 |
54 | // Parse the local file's "TranslationUpdatedOn" field
55 | if (ZlpIOHelper.FileExists(localFilePath.ToLower()))
56 | {
57 | string localContent = ZlpIOHelper.ReadAllText(localFilePath.ToLower());
58 | JObject localJson = JObject.Parse(localContent);
59 | string localUpdatedOnString = localJson["TranslationUpdatedOn"]?.ToString();
60 |
61 | // Compare updated date
62 | if (remoteUpdatedOnString != localUpdatedOnString)
63 | {
64 | ZlpIOHelper.WriteAllText(localFilePath.ToLower(), remoteContent);
65 | qbdlxForm._qbdlxForm.logger.Debug($"File {fileName} updated successfully.");
66 | }
67 | else
68 | {
69 | qbdlxForm._qbdlxForm.logger.Debug($"File {fileName} is already up-to-date.");
70 | }
71 | }
72 | else
73 | {
74 | // Local file does not exist, download it
75 | ZlpIOHelper.WriteAllText(localFilePath.ToLower(), remoteContent);
76 | qbdlxForm._qbdlxForm.logger.Debug($"File {fileName} downloaded successfully.");
77 | }
78 | }
79 | else
80 | {
81 | qbdlxForm._qbdlxForm.logger.Error($"Failed to retrieve the download URL for {fileName}.");
82 | }
83 | }
84 | else
85 | {
86 | qbdlxForm._qbdlxForm.logger.Error($"Failed to fetch metadata for {fileName}: {response.StatusCode}");
87 | }
88 | }
89 | catch (Exception ex)
90 | {
91 | qbdlxForm._qbdlxForm.logger.Error($"Error updating {fileName}: {ex.Message}");
92 | }
93 | }
94 | }
95 | }
96 | }
97 |
98 | public static class VersionChecker
99 | {
100 | public static async Task<(bool isUpdateAvailable, string newVersion, string currentVersion, string changes)> CheckForUpdate()
101 | {
102 | string changes = string.Empty;
103 | string currentVersion = string.Empty;
104 | string newVersion = string.Empty;
105 | bool isUpdateAvailable = false;
106 |
107 | try
108 | {
109 | // Initialize HttpClient to grab version number from GitHub
110 | using (var versionURLClient = new HttpClient())
111 | {
112 | qbdlxForm._qbdlxForm.logger.Debug("versionURLClient initialized");
113 |
114 | // Configure TLS for secure connection
115 | ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
116 |
117 | // Set user-agent to Firefox
118 | versionURLClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0");
119 |
120 | // Request the latest release from GitHub
121 | qbdlxForm._qbdlxForm.logger.Debug("Starting request for latest GitHub version");
122 | var versionURL = "https://api.github.com/repos/ImAiiR/QobuzDownloaderX/releases/latest";
123 | var versionURLResponse = await versionURLClient.GetAsync(versionURL);
124 | string versionURLResponseString = await versionURLResponse.Content.ReadAsStringAsync();
125 |
126 | // Parse the JSON response
127 | JObject joVersionResponse = JObject.Parse(versionURLResponseString);
128 |
129 | // Extract version number and changelog
130 | newVersion = (string)joVersionResponse["tag_name"];
131 | qbdlxForm._qbdlxForm.logger.Debug("Received version from GitHub: " + newVersion);
132 | changes = (string)joVersionResponse["body"];
133 |
134 | // Get the current version from the assembly
135 | currentVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
136 |
137 | // Compare versions
138 | if (!currentVersion.Contains(newVersion))
139 | {
140 | isUpdateAvailable = true;
141 | qbdlxForm._qbdlxForm.logger.Debug("New version available: " + newVersion);
142 | }
143 | else
144 | {
145 | qbdlxForm._qbdlxForm.logger.Debug("Current version matches the latest version.");
146 | }
147 | }
148 | }
149 | catch (Exception ex)
150 | {
151 | qbdlxForm._qbdlxForm.logger.Error("Connection to GitHub failed: " + ex.Message);
152 | }
153 |
154 | return (isUpdateAvailable, newVersion, currentVersion, changes);
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 |
122 | ..\Resources\info.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
123 |
124 |
125 | ..\Resources\qbdlx_icon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
126 |
127 |
128 | ..\Resources\email.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
129 |
130 |
131 | ..\Resources\qbdlx_new.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
132 |
133 |
134 | ..\Resources\password.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
135 |
136 |
137 | ..\Resources\log_out.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
138 |
139 |
140 | ..\Resources\logout.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
141 |
142 |
143 | ..\Resources\settings.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
144 |
145 |
146 | ..\Resources\QBDLX-Icon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
147 |
148 |
149 | ..\Resources\QBDLX-Icon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
150 |
151 |
152 | ..\Resources\alert.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
153 |
154 |
155 | ..\Resources\search.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
156 |
157 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/QobuzDownloaderX.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {4CEB979A-035A-4D36-9607-D554BBECABE0}
8 | WinExe
9 | Properties
10 | QobuzDownloaderX
11 | QobuzDownloaderX
12 | v4.8
13 | 512
14 | true
15 |
16 | publish\
17 | true
18 | Disk
19 | false
20 | Foreground
21 | 7
22 | Days
23 | false
24 | false
25 | true
26 | 0
27 | 1.0.0.%2a
28 | false
29 | false
30 | true
31 |
32 |
33 | AnyCPU
34 | true
35 | full
36 | false
37 | bin\Debug\
38 | DEBUG;TRACE
39 | prompt
40 | 4
41 |
42 |
43 | AnyCPU
44 | pdbonly
45 | true
46 | bin\Release\
47 | TRACE
48 | prompt
49 | 4
50 |
51 |
52 | Resources\QBDLX-Icon.ico
53 |
54 |
55 |
56 |
57 |
58 |
59 | ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll
60 | True
61 |
62 |
63 | ..\packages\taglib.2.1.0.0\lib\policy.2.0.taglib-sharp.dll
64 | True
65 |
66 |
67 | ..\packages\QopenAPI.0.0.3.4\lib\net48\Qo(penAPI).dll
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | ..\packages\taglib.2.1.0.0\lib\taglib-sharp.dll
82 | True
83 |
84 |
85 | ..\packages\ZetaLongPaths.1.0.17\lib\net452-full\ZetaLongPaths.dll
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | Form
101 |
102 |
103 | LoginForm.cs
104 |
105 |
106 |
107 |
108 | Form
109 |
110 |
111 | qbdlxForm.cs
112 |
113 |
114 |
115 |
116 | LoginForm.cs
117 |
118 |
119 | ResXFileCodeGenerator
120 | Resources.Designer.cs
121 | Designer
122 |
123 |
124 | True
125 | Resources.resx
126 | True
127 |
128 |
129 | qbdlxForm.cs
130 |
131 |
132 |
133 | SettingsSingleFileGenerator
134 | Settings.Designer.cs
135 |
136 |
137 | True
138 | Settings.settings
139 | True
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 | Designer
151 |
152 |
153 |
154 |
155 | False
156 | Microsoft .NET Framework 4.6 %28x86 and x64%29
157 | true
158 |
159 |
160 | False
161 | .NET Framework 3.5 SP1
162 | false
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 | xcopy /y /i "$(ProjectDir)Resources\Languages\*.json" "$(TargetDir)languages\"
183 | xcopy /y /i "$(ProjectDir)Resources\themes.json" "$(TargetDir)"
184 |
185 |
186 |
193 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Old/AboutForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace QobuzDownloaderX
2 | {
3 | partial class AboutForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutForm));
32 | this.panel1 = new System.Windows.Forms.Panel();
33 | this.verNumLabel2 = new System.Windows.Forms.Label();
34 | this.exitLabel = new System.Windows.Forms.Label();
35 | this.pictureBox1 = new System.Windows.Forms.PictureBox();
36 | this.devLabel = new System.Windows.Forms.Label();
37 | this.label1 = new System.Windows.Forms.Label();
38 | this.label2 = new System.Windows.Forms.Label();
39 | this.label3 = new System.Windows.Forms.Label();
40 | this.panel1.SuspendLayout();
41 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
42 | this.SuspendLayout();
43 | //
44 | // panel1
45 | //
46 | this.panel1.BackgroundImage = null;
47 | this.panel1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
48 | this.panel1.Controls.Add(this.exitLabel);
49 | this.panel1.Controls.Add(this.pictureBox1);
50 | this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
51 | this.panel1.Location = new System.Drawing.Point(0, 0);
52 | this.panel1.Name = "panel1";
53 | this.panel1.Size = new System.Drawing.Size(365, 95);
54 | this.panel1.TabIndex = 1;
55 | this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseMove);
56 | //
57 | // verNumLabel2
58 | //
59 | this.verNumLabel2.BackColor = System.Drawing.Color.Transparent;
60 | this.verNumLabel2.Font = new System.Drawing.Font("Trebuchet MS", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
61 | this.verNumLabel2.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(88)))), ((int)(((byte)(92)))), ((int)(((byte)(102)))));
62 | this.verNumLabel2.Location = new System.Drawing.Point(12, 98);
63 | this.verNumLabel2.Name = "verNumLabel2";
64 | this.verNumLabel2.Size = new System.Drawing.Size(341, 18);
65 | this.verNumLabel2.TabIndex = 32;
66 | this.verNumLabel2.Text = "#.#.#.#";
67 | this.verNumLabel2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
68 | this.verNumLabel2.MouseMove += new System.Windows.Forms.MouseEventHandler(this.verNumLabel2_MouseMove);
69 | //
70 | // exitLabel
71 | //
72 | this.exitLabel.AutoSize = true;
73 | this.exitLabel.BackColor = System.Drawing.Color.Transparent;
74 | this.exitLabel.Font = new System.Drawing.Font("Calibri", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
75 | this.exitLabel.ForeColor = System.Drawing.Color.Black;
76 | this.exitLabel.Location = new System.Drawing.Point(345, 0);
77 | this.exitLabel.Name = "exitLabel";
78 | this.exitLabel.Size = new System.Drawing.Size(20, 23);
79 | this.exitLabel.TabIndex = 9;
80 | this.exitLabel.Text = "X";
81 | this.exitLabel.TextAlign = System.Drawing.ContentAlignment.TopCenter;
82 | this.exitLabel.Click += new System.EventHandler(this.exitLabel_Click);
83 | //
84 | // pictureBox1
85 | //
86 | this.pictureBox1.BackColor = System.Drawing.Color.Transparent;
87 | this.pictureBox1.Image = null;
88 | this.pictureBox1.Location = new System.Drawing.Point(53, 12);
89 | this.pictureBox1.Name = "pictureBox1";
90 | this.pictureBox1.Size = new System.Drawing.Size(258, 64);
91 | this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
92 | this.pictureBox1.TabIndex = 29;
93 | this.pictureBox1.TabStop = false;
94 | this.pictureBox1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseMove);
95 | //
96 | // devLabel
97 | //
98 | this.devLabel.AutoSize = true;
99 | this.devLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(88)))), ((int)(((byte)(92)))), ((int)(((byte)(102)))));
100 | this.devLabel.Location = new System.Drawing.Point(140, 131);
101 | this.devLabel.Name = "devLabel";
102 | this.devLabel.Size = new System.Drawing.Size(84, 13);
103 | this.devLabel.TabIndex = 34;
104 | this.devLabel.Text = "Developer - AiiR";
105 | //
106 | // label1
107 | //
108 | this.label1.AutoSize = true;
109 | this.label1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(88)))), ((int)(((byte)(92)))), ((int)(((byte)(102)))));
110 | this.label1.Location = new System.Drawing.Point(79, 154);
111 | this.label1.Name = "label1";
112 | this.label1.Size = new System.Drawing.Size(207, 13);
113 | this.label1.TabIndex = 35;
114 | this.label1.Text = "Inspired By - Qo-DL by Sorrow and DashLt";
115 | this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
116 | //
117 | // label2
118 | //
119 | this.label2.AutoSize = true;
120 | this.label2.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(88)))), ((int)(((byte)(92)))), ((int)(((byte)(102)))));
121 | this.label2.Location = new System.Drawing.Point(47, 177);
122 | this.label2.Name = "label2";
123 | this.label2.Size = new System.Drawing.Size(271, 26);
124 | this.label2.TabIndex = 36;
125 | this.label2.Text = "Thanks to the users on Github and Telegram for offering\r\nbug reports and ideas!";
126 | this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
127 | //
128 | // label3
129 | //
130 | this.label3.AutoSize = true;
131 | this.label3.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(88)))), ((int)(((byte)(92)))), ((int)(((byte)(102)))));
132 | this.label3.Location = new System.Drawing.Point(15, 237);
133 | this.label3.Name = "label3";
134 | this.label3.Size = new System.Drawing.Size(334, 26);
135 | this.label3.TabIndex = 37;
136 | this.label3.Text = "IF YOU PAID FOR THIS PROGRAM, YOU HAVE BEEN SCAMMED!\r\nTHIS SOFTWARE IS COMPLETELY" +
137 | " FREE AND OPEN-SOURCE.";
138 | this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
139 | //
140 | // AboutForm
141 | //
142 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
143 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
144 | this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20)))));
145 | this.ClientSize = new System.Drawing.Size(365, 289);
146 | this.Controls.Add(this.label3);
147 | this.Controls.Add(this.label2);
148 | this.Controls.Add(this.label1);
149 | this.Controls.Add(this.devLabel);
150 | this.Controls.Add(this.verNumLabel2);
151 | this.Controls.Add(this.panel1);
152 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
153 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
154 | this.Name = "AboutForm";
155 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
156 | this.Text = "QobuzDLX | About";
157 | this.Load += new System.EventHandler(this.AboutForm_Load);
158 | this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.AboutForm_MouseMove);
159 | this.panel1.ResumeLayout(false);
160 | this.panel1.PerformLayout();
161 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
162 | this.ResumeLayout(false);
163 | this.PerformLayout();
164 |
165 | }
166 |
167 | #endregion
168 |
169 | private System.Windows.Forms.Panel panel1;
170 | private System.Windows.Forms.Label verNumLabel2;
171 | private System.Windows.Forms.Label exitLabel;
172 | private System.Windows.Forms.PictureBox pictureBox1;
173 | private System.Windows.Forms.Label devLabel;
174 | private System.Windows.Forms.Label label1;
175 | private System.Windows.Forms.Label label2;
176 | private System.Windows.Forms.Label label3;
177 | }
178 | }
--------------------------------------------------------------------------------
/QobuzDownloaderX/Helpers/Download/DownloadFile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading.Tasks;
4 | using QopenAPI;
5 | using QobuzDownloaderX.Properties;
6 | using System.Text.RegularExpressions;
7 | using ZetaLongPaths;
8 |
9 | namespace QobuzDownloaderX
10 | {
11 | class DownloadFile
12 | {
13 | TagFile tagFile = new TagFile();
14 | RenameTemplates renameTemplates = new RenameTemplates();
15 | PaddingNumbers paddingNumbers = new PaddingNumbers();
16 | GetInfo getInfo = new GetInfo();
17 | FixMD5 fixMD5 = new FixMD5();
18 |
19 | public string artworkPath { get; set; }
20 |
21 | public async Task createPath(string downloadLocation, string artistTemplate, string albumTemplate, string trackTemplate, string playlistTemplate, string favoritesTemplate, int paddedTrackLength, int paddedDiscLength, Album QoAlbum, Item QoItem, Playlist QoPlaylist)
22 | {
23 | return await Task.Run(() =>
24 | {
25 | string downloadPath;
26 | if (QoPlaylist == null)
27 | {
28 | qbdlxForm._qbdlxForm.logger.Debug("Using non-playlist path");
29 | string artistTemplateConverted = renameTemplates.renameTemplates(artistTemplate, paddedTrackLength, paddedDiscLength, qbdlxForm._qbdlxForm.audio_format, QoAlbum, null, null);
30 | string albumTemplateConverted = renameTemplates.renameTemplates(albumTemplate, paddedTrackLength, paddedDiscLength, qbdlxForm._qbdlxForm.audio_format, QoAlbum, null, null);
31 | downloadPath = ZlpPathHelper.Combine(downloadLocation, artistTemplateConverted, albumTemplateConverted.TrimEnd(ZlpPathHelper.DirectorySeparatorChar) + ZlpPathHelper.DirectorySeparatorChar);
32 | downloadPath = Regex.Replace(downloadPath, @"\s+", " "); // Remove double spaces
33 |
34 | }
35 | else
36 | {
37 | qbdlxForm._qbdlxForm.logger.Debug("Using playlist path");
38 | string playlistTemplateConverted = renameTemplates.renameTemplates(playlistTemplate, paddedTrackLength, paddedDiscLength, qbdlxForm._qbdlxForm.audio_format, null, null, QoPlaylist);
39 | downloadPath = ZlpPathHelper.Combine(downloadLocation, playlistTemplateConverted.TrimEnd(ZlpPathHelper.DirectorySeparatorChar) + ZlpPathHelper.DirectorySeparatorChar);
40 | downloadPath = Regex.Replace(downloadPath, @"\s+", " "); // Remove double spaces
41 | }
42 | return downloadPath;
43 | });
44 | }
45 |
46 | public async Task DownloadStream(string streamUrl, string downloadPath, string filePath, string audio_format, Album QoAlbum, Item QoItem)
47 | {
48 | qbdlxForm._qbdlxForm.logger.Debug("Writing temp file to qbdlx-temp/qbdlx_downloading-" + QoItem.Id.ToString() + audio_format);
49 |
50 | // Create a temp directory inside the exe location, to download files to.
51 | string tempFile = ZlpPathHelper.Combine(@"qbdlx-temp", "qbdlx_downloading-" + QoItem.Id.ToString() + audio_format);
52 | ZlpIOHelper.CreateDirectory(@"qbdlx-temp");
53 |
54 | using (var client = new WebClient())
55 | {
56 | // Set path for downloaded artwork.
57 | artworkPath = downloadPath + qbdlxForm._qbdlxForm.embeddedArtSize + @".jpg";
58 | qbdlxForm._qbdlxForm.logger.Debug("Artwork path: " + artworkPath);
59 |
60 | // Use secure connection
61 | ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
62 |
63 | // Create a TaskCompletionSource to handle asynchronous waiting
64 | var tcs = new TaskCompletionSource();
65 |
66 | // Fields to track previous progress and time for speed calculation
67 | long previousBytesReceived = 0;
68 | DateTime lastUpdateTime = DateTime.Now;
69 |
70 | // Subscribe to progress changed event
71 | client.DownloadProgressChanged += (sender, e) =>
72 | {
73 | int progressPercentage = e.ProgressPercentage;
74 | long bytesReceived = e.BytesReceived;
75 | long totalBytesToReceive = e.TotalBytesToReceive;
76 |
77 | if (qbdlxForm._qbdlxForm.downloadSpeedCheckbox.Checked)
78 | {
79 | // Calculate download speed in bytes per second
80 | DateTime currentTime = DateTime.Now;
81 | double timeDiff = (currentTime - lastUpdateTime).TotalSeconds;
82 |
83 | if (timeDiff > 0)
84 | {
85 | long bytesDiff = bytesReceived - previousBytesReceived;
86 | double speed = bytesDiff / timeDiff; // bytes per second
87 | string speedText = speed > 1024 * 1024
88 | ? $"{speed / (1024 * 1024):F2} MB/s"
89 | : $"{speed / 1024:F2} KB/s";
90 |
91 | qbdlxForm._qbdlxForm.BeginInvoke(new Action(() => { qbdlxForm._qbdlxForm.progressLabel.Text = $"{qbdlxForm._qbdlxForm.progressLabelActive} - {progressPercentage}% [{speedText}]"; }));
92 | }
93 | }
94 | else
95 | {
96 | qbdlxForm._qbdlxForm.BeginInvoke(new Action(() => { qbdlxForm._qbdlxForm.progressLabel.Text = $"{qbdlxForm._qbdlxForm.progressLabelActive} - {progressPercentage}%"; }));
97 | }
98 | };
99 |
100 | // Handle completion of the download
101 | client.DownloadFileCompleted += (sender, e) =>
102 | {
103 | if (e.Error != null)
104 | {
105 | qbdlxForm._qbdlxForm.logger.Error("Download failed: " + e.Error.Message);
106 | tcs.SetException(e.Error);
107 | return;
108 | }
109 |
110 | qbdlxForm._qbdlxForm.logger.Debug("Download complete.");
111 |
112 | if (Settings.Default.fixMD5s && audio_format.Contains("flac"))
113 | {
114 | qbdlxForm._qbdlxForm.logger.Debug("Attempting to fix unset MD5s...");
115 | fixMD5.fixMD5(tempFile, "flac");
116 | }
117 |
118 | qbdlxForm._qbdlxForm.logger.Debug("Starting file metadata tagging");
119 | TagFile.WriteToFile(tempFile, artworkPath, QoAlbum, QoItem);
120 |
121 | // Move the file with the full name (Zeta Long Paths to avoid MAX_PATH error)
122 | qbdlxForm._qbdlxForm.logger.Debug("Moving temp file to - " + filePath);
123 | ZlpIOHelper.MoveFile(tempFile, filePath);
124 |
125 | // Signal the TaskCompletionSource that the task is complete
126 | tcs.SetResult(true);
127 | };
128 |
129 | // Start the asynchronous download
130 | qbdlxForm._qbdlxForm.logger.Debug("Downloading to temp file...");
131 | if (QoAlbum.MediaCount > 1)
132 | {
133 | qbdlxForm._qbdlxForm.logger.Debug("More than 1 volume, using subfolders for each volume");
134 | ZlpIOHelper.CreateDirectory(ZlpPathHelper.GetDirectoryPathNameFromFilePath(downloadPath + "CD " + QoItem.MediaNumber.ToString().PadLeft(paddingNumbers.padDiscs(QoAlbum), '0') + ZlpPathHelper.DirectorySeparatorChar));
135 | }
136 | else
137 | {
138 | ZlpIOHelper.CreateDirectory(ZlpPathHelper.GetDirectoryPathNameFromFilePath(downloadPath));
139 | }
140 |
141 | client.DownloadFileAsync(new Uri(streamUrl), tempFile);
142 |
143 | // Await the TaskCompletionSource to wait until download completes
144 | await tcs.Task;
145 | }
146 | }
147 |
148 | public async Task DownloadArtwork(string downloadPath, Album QoAlbum)
149 | {
150 | using (var client = new WebClient())
151 | {
152 | // Use secure connection
153 | ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
154 |
155 | // Download cover art (600x600) to the download path
156 | qbdlxForm._qbdlxForm.logger.Debug("Downloading Cover Art");
157 | ZlpIOHelper.CreateDirectory(ZlpPathHelper.GetDirectoryPathNameFromFilePath(downloadPath));
158 |
159 | if (!ZlpIOHelper.FileExists(downloadPath + @"Cover.jpg"))
160 | {
161 | qbdlxForm._qbdlxForm.logger.Debug("Saved artwork Cover.jpg not found, downloading");
162 | try { await client.DownloadFileTaskAsync(QoAlbum.Image.Large.Replace("_600", "_" + qbdlxForm._qbdlxForm.savedArtSize), ZlpPathHelper.GetFullPath(downloadPath + @"Cover.jpg")); } catch (Exception ex) { qbdlxForm._qbdlxForm.logger.Error($"Failed to download cover art. Error below:\r\n{ex}"); }
163 | }
164 | if (!ZlpIOHelper.FileExists(downloadPath + qbdlxForm._qbdlxForm.embeddedArtSize + @".jpg"))
165 | {
166 | qbdlxForm._qbdlxForm.logger.Debug("Saved artwork for embedding not found, downloading");
167 | try { await client.DownloadFileTaskAsync(QoAlbum.Image.Large.Replace("_600", "_" + qbdlxForm._qbdlxForm.embeddedArtSize), ZlpPathHelper.GetFullPath(downloadPath + qbdlxForm._qbdlxForm.embeddedArtSize + @".jpg")); } catch (Exception ex) { qbdlxForm._qbdlxForm.logger.Error($"Failed to download cover art. Error below:\r\n{ex}"); }
168 | }
169 | }
170 | }
171 |
172 | public async Task DownloadGoody(string downloadPath, Album QoAlbum, Goody QoGoody)
173 | {
174 | using (var client = new WebClient())
175 | {
176 | // Use secure connection
177 | ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
178 |
179 | // Download goody to the download path
180 | ZlpIOHelper.CreateDirectory(ZlpPathHelper.GetDirectoryPathNameFromFilePath(downloadPath));
181 | await client.DownloadFileTaskAsync(QoGoody.Url, downloadPath + renameTemplates.GetSafeFilename(QoAlbum.Title) + " (" + QoGoody.Id + @").pdf");
182 | }
183 | }
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Helpers/Download/DownloadTrack.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using QopenAPI;
4 | using QobuzDownloaderX.Properties;
5 | using ZetaLongPaths;
6 |
7 | namespace QobuzDownloaderX
8 | {
9 | class DownloadTrack
10 | {
11 | public Service QoService = new Service();
12 | public User QoUser = new User();
13 | public Item QoItem = new Item();
14 | public QopenAPI.Stream QoStream = new QopenAPI.Stream();
15 |
16 | public int paddedTrackLength { get; set; }
17 | public int paddedDiscLength { get; set; }
18 |
19 | public string downloadPath { get; set; }
20 | public string filePath { get; set; }
21 |
22 | PaddingNumbers padNumber = new PaddingNumbers();
23 | DownloadFile downloadFile = new DownloadFile();
24 | RenameTemplates renameTemplates = new RenameTemplates();
25 | GetInfo getInfo = new GetInfo();
26 | FixMD5 fixMD5 = new FixMD5();
27 |
28 | public void clearOutputText() => getInfo.outputText = null;
29 |
30 | private bool VerifyStreamable(Item QoItem, int paddedTrackLength)
31 | {
32 | if (QoItem.Streamable || !Settings.Default.streamableCheck) return true;
33 |
34 | getInfo.updateDownloadOutput($"{qbdlxForm._qbdlxForm.downloadOutputTrNotStream.Replace("{TrackNumber}", QoItem.TrackNumber.ToString().PadLeft(paddedTrackLength, '0'))}\r\n");
35 | return false;
36 | }
37 |
38 | private bool CheckForExistingFile(string filePath, int paddedTrackLength, Item QoItem)
39 | {
40 | if (ZlpIOHelper.FileExists(filePath))
41 | {
42 | getInfo.updateDownloadOutput($"{qbdlxForm._qbdlxForm.downloadOutputFileExists.Replace("{TrackNumber}", QoItem.TrackNumber.ToString().PadLeft(paddedTrackLength, '0'))}\r\n");
43 | return true;
44 | }
45 | return false;
46 | }
47 |
48 | private void CleanupArtwork(string downloadPath)
49 | {
50 | string artworkPath = downloadFile.artworkPath;
51 | if (ZlpIOHelper.FileExists(artworkPath))
52 | {
53 | ZlpIOHelper.DeleteFile(artworkPath);
54 | }
55 | }
56 |
57 | private void CreatePadding(Album QoAlbum, Playlist QoPlaylist)
58 | {
59 | if (QoPlaylist != null)
60 | {
61 | paddedTrackLength = padNumber.padPlaylistTracks(QoPlaylist);
62 | paddedDiscLength = 2;
63 | }
64 | else
65 | {
66 | paddedTrackLength = padNumber.padTracks(QoAlbum);
67 | paddedDiscLength = padNumber.padDiscs(QoAlbum);
68 | }
69 | }
70 |
71 | private async Task DownloadAndSaveTrack(string app_id, string format_id, string user_auth_token, string app_secret, Album QoAlbum, Item QoItem, Playlist QoPlaylist, string downloadPath, string filePath, string audio_format, int paddedTrackLength)
72 | {
73 | var QoStream = QoService.TrackGetFileUrl(QoItem.Id.ToString(), format_id, app_id, user_auth_token, app_secret);
74 | string streamURL = QoStream.StreamURL;
75 |
76 | // Display download status (depending on track number or playlist position number)
77 | var trackName = QoItem.Version == null ? QoItem.Title : $"{QoItem.Title.Trim()} ({QoItem.Version})";
78 | if (QoPlaylist == null) { getInfo.updateDownloadOutput($"{qbdlxForm._qbdlxForm.downloadOutputDownloading} - {QoItem.TrackNumber.ToString().PadLeft(paddedTrackLength, '0')} {trackName}..."); }
79 | else { getInfo.updateDownloadOutput($"{qbdlxForm._qbdlxForm.downloadOutputDownloading} - {QoItem.Position.ToString().PadLeft(paddedTrackLength, '0')} {trackName}..."); }
80 |
81 | // Download stream
82 | await downloadFile.DownloadStream(streamURL, downloadPath, filePath, audio_format, QoAlbum, QoItem);
83 | getInfo.updateDownloadOutput($" {qbdlxForm._qbdlxForm.downloadOutputDone}\r\n");
84 | }
85 |
86 | public async Task DownloadTrackAsync(string downloadType, string app_id, string album_id, string format_id, string audio_format, string user_auth_token, string app_secret, string downloadLocation, string artistTemplate, string albumTemplate, string trackTemplate, Album QoAlbum, Item QoItem)
87 | {
88 | // Empty output on main form if individual track download
89 | if (downloadType == "track") { getInfo.outputText = null; }
90 |
91 | try
92 | {
93 | // Create padding for tracks and possible multi-volume releases
94 | CreatePadding(QoAlbum, null);
95 |
96 | try
97 | {
98 | // Get track info with auth if not there already
99 | if (QoItem == null) { QoItem = QoService.TrackGetWithAuth(app_id, album_id, user_auth_token); }
100 |
101 | // Check if QoItem is still null. If so, skip.
102 | if (QoItem == null)
103 | {
104 | getInfo.updateDownloadOutput($"{qbdlxForm._qbdlxForm.downloadOutputAPIError}\r\n");
105 | return;
106 | }
107 |
108 | // Verify Streamable
109 | try { if (!VerifyStreamable(QoItem, paddedTrackLength)) return; } catch (Exception ex) { qbdlxForm._qbdlxForm.logger.Error($"Unable to verify if track is streamable. Error below:\r\n{ex}"); }
110 |
111 | // Setting up download and file path
112 | downloadPath = await downloadFile.createPath(downloadLocation, artistTemplate, albumTemplate, trackTemplate, null, null, paddedTrackLength, paddedDiscLength, QoAlbum, QoItem, null);
113 | string trackTemplateConverted = renameTemplates.renameTemplates(trackTemplate, paddedTrackLength, paddedDiscLength, audio_format, QoAlbum, QoItem, null);
114 |
115 | if (trackTemplateConverted.Contains(@"\"))
116 | {
117 | downloadPath = downloadPath + trackTemplateConverted.Substring(0, trackTemplateConverted.LastIndexOf(@"\")) + @"\";
118 | trackTemplateConverted = trackTemplateConverted.Substring(trackTemplateConverted.LastIndexOf(@"\") + 1);
119 | Console.WriteLine(downloadPath);
120 | }
121 |
122 | // Create subfolders for multi-volume releases
123 | if (QoAlbum.MediaCount > 1)
124 | {
125 | filePath = downloadPath + "CD " + QoItem.MediaNumber.ToString().PadLeft(paddedDiscLength, '0') + ZlpPathHelper.DirectorySeparatorChar + trackTemplateConverted.TrimEnd() + audio_format;
126 | }
127 | else
128 | {
129 | filePath = downloadPath + trackTemplateConverted.TrimEnd() + audio_format;
130 | }
131 |
132 | // Download cover art
133 | try { await downloadFile.DownloadArtwork(downloadPath, QoAlbum); } catch (Exception ex) { qbdlxForm._qbdlxForm.logger.Error($"Failed to Download Cover Art. Error below:\r\n{ex}"); }
134 |
135 | // Check for Existing File
136 | if (CheckForExistingFile(filePath, paddedTrackLength, QoItem)) return;
137 |
138 | // Download and Save Track
139 | await DownloadAndSaveTrack(app_id, format_id, user_auth_token, app_secret, QoAlbum, QoItem, null, downloadPath, filePath, audio_format, paddedTrackLength);
140 | }
141 | catch (Exception downloadAlbumEx)
142 | {
143 | getInfo.updateDownloadOutput("\r\n\r\n" + downloadAlbumEx + "\r\n\r\n");
144 | Console.WriteLine(downloadAlbumEx);
145 | return;
146 | }
147 | }
148 | catch (Exception downloadAlbumEx)
149 | {
150 | Console.WriteLine(downloadAlbumEx);
151 | return;
152 | }
153 | }
154 |
155 | public async Task DownloadPlaylistTrackAsync(string app_id, string album_id, string format_id, string audio_format, string user_auth_token, string app_secret, string downloadLocation, string artistTemplate, string albumTemplate, string trackTemplate, string playlistTemplate, Album QoAlbum, Item QoItem, Playlist QoPlaylist)
156 | {
157 | try
158 | {
159 | // Create padding for tracks
160 | CreatePadding(null, QoPlaylist);
161 |
162 | // Verify Streamable
163 | if (!VerifyStreamable(QoItem, paddedTrackLength)) return;
164 |
165 | try
166 | {
167 | // Setting up download and file path
168 | downloadPath = await downloadFile.createPath(downloadLocation, null, null, trackTemplate, playlistTemplate, null, paddedTrackLength, paddedDiscLength, QoAlbum, QoItem, QoPlaylist);
169 | string trackTemplateConverted = renameTemplates.renameTemplates(trackTemplate, paddedTrackLength, paddedDiscLength, audio_format, QoAlbum, QoItem, QoPlaylist);
170 |
171 | if (trackTemplateConverted.Contains(@"\"))
172 | {
173 | downloadPath = downloadPath + trackTemplateConverted.Substring(0, trackTemplateConverted.LastIndexOf(@"\")) + @"\";
174 | trackTemplateConverted = trackTemplateConverted.Substring(trackTemplateConverted.LastIndexOf(@"\") + 1);
175 | Console.WriteLine(downloadPath);
176 | }
177 |
178 | filePath = downloadPath + trackTemplateConverted.TrimEnd() + audio_format;
179 |
180 | // Check for Existing File
181 | if (CheckForExistingFile(filePath, paddedTrackLength, QoItem)) return;
182 |
183 | // Download cover art
184 | try { await downloadFile.DownloadArtwork(downloadPath, QoAlbum); } catch (Exception ex) { Console.WriteLine($"Failed to Download Cover Art. Error below:\r\n{ex}"); }
185 |
186 | // Download and Save Track
187 | await DownloadAndSaveTrack(app_id, format_id, user_auth_token, app_secret, QoAlbum, QoItem, QoPlaylist, downloadPath, filePath, audio_format, paddedTrackLength);
188 |
189 | // Delete image used for embedded artwork
190 | CleanupArtwork(downloadPath);
191 | }
192 | catch (Exception downloadAlbumEx)
193 | {
194 | getInfo.updateDownloadOutput("\r\n\r\n" + downloadAlbumEx + "\r\n\r\n");
195 | Console.WriteLine(downloadAlbumEx);
196 | return;
197 | }
198 |
199 | }
200 | catch (Exception downloadAlbumEx)
201 | {
202 | Console.WriteLine(downloadAlbumEx);
203 | return;
204 | }
205 | }
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Helpers/Download/DownloadAlbum.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using QopenAPI;
4 | using System.IO;
5 | using QobuzDownloaderX.Properties;
6 | using System.Text.RegularExpressions;
7 | using ZetaLongPaths;
8 |
9 | namespace QobuzDownloaderX
10 | {
11 | public static class StringExt
12 | {
13 | public static string Truncate(this string value, int maxLength)
14 | {
15 | // This is currently unused, but leaving this here in case it needs to be used in the future.
16 | if (string.IsNullOrEmpty(value)) return value;
17 | return value.Length <= maxLength ? value : value.Substring(0, maxLength);
18 | }
19 | }
20 |
21 | class DownloadAlbum
22 | {
23 | public Service QoService = new Service();
24 | public User QoUser = new User();
25 | public Album QoAlbum = new Album();
26 | public Item QoItem = new Item();
27 | public QopenAPI.Stream QoStream = new QopenAPI.Stream();
28 |
29 | public int paddedTrackLength { get; set; }
30 | public int paddedDiscLength { get; set; }
31 |
32 | public string downloadPath { get; set; }
33 |
34 | PaddingNumbers padNumber = new PaddingNumbers();
35 | DownloadTrack downloadTrack = new DownloadTrack();
36 | DownloadFile downloadFile = new DownloadFile();
37 | GetInfo getInfo = new GetInfo();
38 |
39 | private async Task DownloadArtwork(string downloadPath, Album album)
40 | {
41 | try
42 | {
43 | qbdlxForm._qbdlxForm.logger.Debug("Downloading artwork...");
44 | await downloadFile.DownloadArtwork(downloadPath, album);
45 | qbdlxForm._qbdlxForm.logger.Debug("Artwork download complete");
46 | }
47 | catch (Exception ex)
48 | {
49 | qbdlxForm._qbdlxForm.logger.Error($"Artwork download failed: {ex}");
50 | Console.WriteLine("Unable to download artwork");
51 | }
52 | }
53 |
54 | private void DeleteEmbeddedArtwork(string downloadPath)
55 | {
56 | try
57 | {
58 | qbdlxForm._qbdlxForm.logger.Debug("Deleting embedded artwork...");
59 | ZlpIOHelper.DeleteFile($"{downloadPath}{qbdlxForm._qbdlxForm.embeddedArtSize}.jpg");
60 | }
61 | catch
62 | {
63 | qbdlxForm._qbdlxForm.logger.Warning("Unable to delete embedded artwork");
64 | }
65 | }
66 |
67 | private async Task DownloadGoodiesAsync(string downloadPath, Album album)
68 | {
69 | try
70 | {
71 | foreach (var goody in album.Goodies)
72 | {
73 | getInfo.updateDownloadOutput($"{qbdlxForm._qbdlxForm.downloadOutputGoodyFound} ");
74 |
75 | if (goody.Url == null)
76 | {
77 | qbdlxForm._qbdlxForm.logger.Warning("No URL found for the goody, skipping.");
78 | getInfo.updateDownloadOutput($"\r\n{qbdlxForm._qbdlxForm.downloadOutputGoodyNoURL}\r\n");
79 | continue;
80 | }
81 |
82 | qbdlxForm._qbdlxForm.logger.Debug("Downloading goody...");
83 | await downloadFile.DownloadGoody(downloadPath, album, goody);
84 | qbdlxForm._qbdlxForm.logger.Debug("Goody download complete");
85 | getInfo.updateDownloadOutput($"{qbdlxForm._qbdlxForm.downloadOutputDone}\r\n");
86 | }
87 | }
88 | catch
89 | {
90 | qbdlxForm._qbdlxForm.logger.Warning("No goodies found or failed to download");
91 | }
92 | }
93 |
94 | public async Task DownloadTracksAsync(string app_id, string album_id, string format_id, string audio_format, string user_auth_token, string app_secret, string downloadLocation, string artistTemplate, string albumTemplate, string trackTemplate, Album album)
95 | {
96 | foreach (var item in album.Tracks.Items)
97 | {
98 | try
99 | {
100 | qbdlxForm._qbdlxForm.logger.Debug("Downloading track...");
101 | await downloadTrack.DownloadTrackAsync("album", app_id, album_id, format_id, audio_format, user_auth_token, app_secret, downloadLocation, artistTemplate, albumTemplate, trackTemplate, album, QoService.TrackGetWithAuth(app_id, item.Id.ToString(), user_auth_token));
102 | qbdlxForm._qbdlxForm.logger.Debug("Track download complete");
103 | }
104 | catch (Exception ex)
105 | {
106 | qbdlxForm._qbdlxForm.logger.Error($"Track download failed: {ex}");
107 | getInfo.updateDownloadOutput($"\r\n{ex}");
108 | Console.WriteLine(ex);
109 | return;
110 | }
111 | }
112 | }
113 |
114 | public async Task DownloadAlbumAsync(string app_id, string album_id, string format_id, string audio_format, string user_auth_token, string app_secret, string downloadLocation, string artistTemplate, string albumTemplate, string trackTemplate, Album QoAlbum)
115 | {
116 | qbdlxForm._qbdlxForm.logger.Debug("Starting album download (downloadAlbum)");
117 |
118 | // Clear output text from DownloadTrack to avoid text from previous downloads sticking around.
119 | qbdlxForm._qbdlxForm.logger.Debug("Clearing output text");
120 | downloadTrack.clearOutputText();
121 |
122 | getInfo.outputText = null;
123 |
124 | if (QoAlbum.Streamable == false)
125 | {
126 | if (Settings.Default.streamableCheck == true)
127 | {
128 | qbdlxForm._qbdlxForm.logger.Debug("Streamable tag is set to false on Qobuz, and streamable check is enabled, skipping download");
129 | getInfo.updateDownloadOutput(qbdlxForm._qbdlxForm.downloadOutputAlNotStream);
130 | getInfo.updateDownloadOutput("\r\n" + qbdlxForm._qbdlxForm.downloadOutputCompleted);
131 | return;
132 | }
133 | else
134 | {
135 | qbdlxForm._qbdlxForm.logger.Debug("Streamable tag is set to false on Qobuz, but streamable check is disabled, attempting download");
136 | }
137 | }
138 |
139 | try
140 | {
141 | // Find the how many characters are needed for padding
142 | paddedTrackLength = padNumber.padTracks(QoAlbum);
143 | paddedDiscLength = padNumber.padTracks(QoAlbum);
144 |
145 | // Set download path
146 | downloadPath = await downloadFile.createPath(downloadLocation, artistTemplate, albumTemplate, trackTemplate, null, null, paddedTrackLength, paddedDiscLength, QoAlbum, null, null);
147 | qbdlxForm._qbdlxForm.logger.Debug("Download path: " + downloadPath);
148 |
149 | // Download artwork
150 | await DownloadArtwork(downloadPath, QoAlbum);
151 |
152 | // Download tracks
153 | await DownloadTracksAsync(app_id, album_id, format_id, audio_format, user_auth_token, app_secret, downloadLocation, artistTemplate, albumTemplate, trackTemplate, QoAlbum);
154 |
155 | // Delete image used for embedding artwork
156 | DeleteEmbeddedArtwork(downloadPath);
157 |
158 | // Set current output text
159 | getInfo.outputText = qbdlxForm._qbdlxForm.downloadOutput.Text;
160 |
161 | // Download goodies
162 | await DownloadGoodiesAsync(downloadPath, QoAlbum);
163 |
164 | // Tell user that download is completed
165 | qbdlxForm._qbdlxForm.logger.Debug("All downloads completed!");
166 |
167 | // Write post template
168 | WritePostTemplate(QoAlbum);
169 | }
170 | catch (Exception downloadAlbumEx)
171 | {
172 | qbdlxForm._qbdlxForm.logger.Error("Error occured during downloadAlbum, error below:\r\n" + downloadAlbumEx);
173 | Console.WriteLine(downloadAlbumEx);
174 | return;
175 | }
176 | }
177 |
178 | private void WritePostTemplate(Album album)
179 | {
180 | try
181 | {
182 | // Not useful at all for normal users, but I use it so... yeah
183 | qbdlxForm._qbdlxForm.logger.Debug("Writing post template...");
184 | var templateDate = DateTime.Parse(album.ReleaseDateOriginal).ToString("MMMM d, yyyy");
185 | ZlpIOHelper.WriteAllText("post_template.txt", String.Empty);
186 |
187 | using (StreamWriter sw = File.AppendText("post_template.txt"))
188 | {
189 | sw.WriteLine("[center]");
190 | sw.WriteLine($"[CoverArt]{album.Image.Large}[/CoverArt]");
191 | sw.WriteLine($"[b]Release Date:[/b] {templateDate}");
192 | sw.WriteLine($"[b]Genre:[/b] {album.Genre.Name.Replace("Alternativ und Indie", "Alternative").Replace("Hörbücher", "Comedy/Other")}");
193 | sw.WriteLine("");
194 | sw.WriteLine("[b]TRACKLIST[/b]");
195 | sw.WriteLine("-----------------------------------");
196 |
197 | foreach (var item in album.Tracks.Items)
198 | {
199 | sw.WriteLine(item.Version != null
200 | ? $"{item.TrackNumber}. {item.Title.TrimEnd()} ({item.Version})"
201 | : $"{item.TrackNumber}. {item.Title.TrimEnd()}");
202 | }
203 |
204 | sw.WriteLine("-----------------------------------");
205 | sw.WriteLine("");
206 | sw.WriteLine("[b]DOWNLOADS[/b]");
207 | sw.WriteLine("-----------------------------------");
208 | sw.WriteLine($"[spoiler={Regex.Replace(album.Label.Name, @"\s+", " ")} / {album.UPC} / WEB]");
209 | if (album.MaximumBitDepth > 16)
210 | {
211 | sw.WriteLine($"[format=FLAC / Lossless ({album.MaximumBitDepth.ToString()}bit/{album.MaximumSamplingRate.ToString()}kHz) / WEB]");
212 | sw.WriteLine($"Uploaded by @{Settings.Default.postTemplateUsername.ToString()}");
213 | sw.WriteLine("");
214 | sw.WriteLine("DOWNLOAD");
215 | sw.WriteLine("REPLACE THIS WITH URL");
216 | sw.WriteLine("[/format]");
217 | }
218 | sw.WriteLine("[format=FLAC / Lossless / WEB]");
219 | sw.WriteLine($"Uploaded by @{Settings.Default.postTemplateUsername.ToString()}");
220 | sw.WriteLine("");
221 | sw.WriteLine("DOWNLOAD");
222 | sw.WriteLine("REPLACE THIS WITH URL");
223 | sw.WriteLine("[/format]");
224 | sw.WriteLine("[format=MP3 / 320 / WEB]");
225 | sw.WriteLine($"Uploaded by @{Settings.Default.postTemplateUsername.ToString()}");
226 | sw.WriteLine("");
227 | sw.WriteLine("DOWNLOAD");
228 | sw.WriteLine("REPLACE THIS WITH URL");
229 | sw.WriteLine("[/format]");
230 | sw.WriteLine("[/spoiler]");
231 | sw.WriteLine("-----------------------------------");
232 | sw.WriteLine("");
233 | sw.WriteLine("REPLACE WITH STREAM LINK");
234 | sw.WriteLine("");
235 | sw.WriteLine("[/center]");
236 | }
237 | }
238 | catch (Exception ex)
239 | {
240 | qbdlxForm._qbdlxForm.logger.Error($"Error writing post template: {ex}");
241 | }
242 | }
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Helpers/RenameTemplates.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.IO;
4 | using QopenAPI;
5 | using System.Text.RegularExpressions;
6 | using ZetaLongPaths;
7 |
8 | namespace QobuzDownloaderX
9 | {
10 | class RenameTemplates
11 | {
12 | public string GetSafeFilename(string filename)
13 | {
14 | // For converting illegal filename characters to an underscore.
15 | Console.WriteLine(string.Join("_", filename.TrimEnd().TrimEnd('.').TrimEnd('.').Split(Path.GetInvalidFileNameChars())));
16 | return string.Join("_", filename.TrimEnd().TrimEnd('.').TrimEnd('.').Split(Path.GetInvalidFileNameChars()));
17 | }
18 |
19 | public string GetReleaseArtists(Album QoAlbum)
20 | {
21 | var mainArtists = QoAlbum.Artists.Where(a => a.Roles.Contains("main-artist")).ToList();
22 | if (mainArtists.Count > 1)
23 | {
24 | var allButLastArtist = string.Join(", ", mainArtists.Take(mainArtists.Count - 1).Select(a => a.Name));
25 | var lastArtist = mainArtists.Last().Name;
26 | return $"{allButLastArtist} & {lastArtist}";
27 | }
28 | return QoAlbum.Artist.Name;
29 | }
30 |
31 | private string ReplaceParentalWarningTags(string template, bool isExplicit)
32 | {
33 | template = template.Replace("%trackpa%", isExplicit ? "Explicit" : "Clean");
34 | template = template.Replace("%trackpashort%", isExplicit ? "E" : "C");
35 | template = template.Replace("%trackpaifex%", isExplicit ? "Explicit" : "");
36 | template = template.Replace("%trackpaifexshort%", isExplicit ? "E" : "");
37 | template = template.Replace("%trackpaifcl%", isExplicit ? "" : "Clean");
38 | template = template.Replace("%trackpaifclshort%", isExplicit ? "" : "C");
39 | template = template.Replace("%trackpaenclosed%", isExplicit ? $"(Explicit)" : $"(Clean)");
40 | template = template.Replace("%trackpaenclosed[]%", isExplicit ? $"[Explicit]" : $"[Clean]");
41 | template = template.Replace("%trackpaenclosedshort%", isExplicit ? $"(E)" : $"(C)");
42 | template = template.Replace("%trackpaenclosedshort[]%", isExplicit ? $"[E]" : $"[C]");
43 | template = template.Replace("%trackpaifexenclosed%", isExplicit ? $"(Explicit)" : $"");
44 | template = template.Replace("%trackpaifexenclosed[]%", isExplicit ? $"[Explicit]" : $"");
45 | template = template.Replace("%trackpaifexenclosedshort%", isExplicit ? $"(E)" : $"");
46 | template = template.Replace("%trackpaifexenclosedshort[]%", isExplicit ? $"[E]" : $"");
47 | template = template.Replace("%trackpaifclenclosed%", isExplicit ? $"" : $"(Clean)");
48 | template = template.Replace("%trackpaifclenclosed[]%", isExplicit ? $"" : $"[Clean]");
49 | template = template.Replace("%trackpaifclenclosedshort%", isExplicit ? $"" : $"(C)");
50 | template = template.Replace("%trackpaifclenclosedshort[]%", isExplicit ? $"" : $"[C]");
51 | template = template.Replace("%albumpa%", isExplicit ? "Explicit" : "Clean");
52 | template = template.Replace("%albumpashort%", isExplicit ? "E" : "C");
53 | template = template.Replace("%albumpaifex%", isExplicit ? "Explicit" : "");
54 | template = template.Replace("%albumpaifexshort%", isExplicit ? "E" : "");
55 | template = template.Replace("%albumpaifcl%", isExplicit ? "" : "Clean");
56 | template = template.Replace("%albumpaifclshort%", isExplicit ? "" : "C");
57 | template = template.Replace("%albumpaenclosed%", isExplicit ? $"(Explicit)" : $"(Clean)");
58 | template = template.Replace("%albumpaenclosed[]%", isExplicit ? $"[Explicit]" : $"[Clean]");
59 | template = template.Replace("%albumpaenclosedshort%", isExplicit ? $"(E)" : $"(C)");
60 | template = template.Replace("%albumpaenclosedshort[]%", isExplicit ? $"[E]" : $"[C]");
61 | template = template.Replace("%albumpaifexenclosed%", isExplicit ? $"(Explicit)" : $"");
62 | template = template.Replace("%albumpaifexenclosed[]%", isExplicit ? $"[Explicit]" : $"");
63 | template = template.Replace("%albumpaifexenclosedshort%", isExplicit ? $"(E)" : $"");
64 | template = template.Replace("%albumpaifexenclosedshort[]%", isExplicit ? $"[E]" : $"");
65 | template = template.Replace("%albumpaifclenclosed%", isExplicit ? $"" : $"(Clean)");
66 | template = template.Replace("%albumpaifclenclosed[]%", isExplicit ? $"" : $"[Clean]");
67 | template = template.Replace("%albumpaifclenclosedshort%", isExplicit ? $"" : $"(C)");
68 | template = template.Replace("%albumpaifclenclosedshort[]%", isExplicit ? $"" : $"[C]");
69 | return template;
70 | }
71 |
72 | private string RenameFormatTemplate(string template, string formatId, string fileFormat, int maximumBitDepth, double maximumSamplingRate, string formatWithHiresQualityPlaceholder, string formatWithQualityPlaceholder)
73 | {
74 | fileFormat = fileFormat.ToUpper().TrimStart('.');
75 |
76 | switch (formatId)
77 | {
78 | case "5":
79 | template = template
80 | .Replace(formatWithHiresQualityPlaceholder, fileFormat)
81 | .Replace(formatWithQualityPlaceholder, fileFormat);
82 | break;
83 |
84 | case "6":
85 | template = template
86 | .Replace(formatWithHiresQualityPlaceholder, fileFormat)
87 | .Replace(formatWithQualityPlaceholder, $"{fileFormat} ({maximumBitDepth}bit-{maximumSamplingRate}kHz)");
88 | break;
89 |
90 | case "7":
91 | case "27":
92 | if (maximumBitDepth == 16)
93 | {
94 | template = template
95 | .Replace(formatWithHiresQualityPlaceholder, fileFormat)
96 | .Replace(formatWithQualityPlaceholder, $"{fileFormat} ({maximumBitDepth}bit-{maximumSamplingRate}kHz)");
97 | }
98 | else if (maximumSamplingRate < 192)
99 | {
100 | template = template.Replace(formatWithQualityPlaceholder, formatWithHiresQualityPlaceholder);
101 |
102 | if (maximumSamplingRate < 96)
103 | {
104 | template = template.Replace(formatWithHiresQualityPlaceholder, $"{fileFormat} ({maximumBitDepth}bit-{maximumSamplingRate}kHz)");
105 | }
106 | else if (maximumSamplingRate > 96 && maximumSamplingRate < 192)
107 | {
108 | if (formatId == "7" && maximumSamplingRate == 176.4)
109 | {
110 | template = template.Replace(formatWithHiresQualityPlaceholder, $"{fileFormat} (24bit-88.2kHz)");
111 | }
112 | else if (formatId == "7")
113 | {
114 | template = template.Replace(formatWithHiresQualityPlaceholder, $"{fileFormat} (24bit-96kHz)");
115 | }
116 | else
117 | {
118 | template = template.Replace(formatWithHiresQualityPlaceholder, $"{fileFormat} ({maximumBitDepth}bit-{maximumSamplingRate}kHz)");
119 | }
120 | }
121 | else
122 | {
123 | template = template.Replace(formatWithHiresQualityPlaceholder, $"{fileFormat} (24bit-96kHz)");
124 | }
125 | }
126 | else
127 | {
128 | template = template.Replace(formatWithQualityPlaceholder, formatWithHiresQualityPlaceholder);
129 | template = template.Replace(formatWithHiresQualityPlaceholder, $"{fileFormat} (24bit-192kHz)");
130 | }
131 | break;
132 | }
133 |
134 | return template;
135 | }
136 |
137 | public string renameTemplates(string template, int paddedTrackLength, int paddedDiscLength, string fileFormat, Album QoAlbum, Item QoItem, Playlist QoPlaylist)
138 | {
139 | qbdlxForm._qbdlxForm.logger.Debug("Renaming user template - " + template);
140 |
141 | // Convert all text between % symbols to lowercase
142 | template = Regex.Replace(template, @"%(.*?)%", match => match.Value.ToLower());
143 |
144 | // Keep backslashes to be used to make new folders
145 | if (template.Contains(ZlpPathHelper.DirectorySeparatorChar))
146 | {
147 | template = template.Replace(@"\", "{backslash}").Replace(@"/", "{forwardslash}");
148 | }
149 |
150 | // Artist Templates
151 | /* bro there ain't shit here */
152 |
153 | // Track Templates
154 | if (QoItem != null)
155 | {
156 | template = ReplaceParentalWarningTags(template, QoItem.ParentalWarning);
157 | template = template
158 | .Replace("%trackid%", QoItem.Id.ToString())
159 | .Replace("%trackartist%", QoItem?.Performer?.Name?.ToString())
160 | .Replace("%trackcomposer%", QoItem?.Composer?.Name?.ToString())
161 | .Replace("%tracknumber%", QoItem.TrackNumber.ToString().PadLeft(paddedTrackLength, '0'))
162 | .Replace("%isrc%", QoItem.ISRC.ToString())
163 | .Replace("%trackbitdepth%", QoItem.MaximumBitDepth.ToString())
164 | .Replace("%tracksamplerate%", QoItem.MaximumSamplingRate.ToString())
165 | .Replace("%tracktitle%", QoItem.Version == null ? QoItem.Title : $"{QoItem.Title.TrimEnd()} ({QoItem.Version})");
166 |
167 | // Track Format Templates
168 | template = template.Replace("%trackformat%", fileFormat.ToUpper().TrimStart('.'));
169 | template = RenameFormatTemplate(template, qbdlxForm._qbdlxForm.format_id, fileFormat, QoItem.MaximumBitDepth, QoItem.MaximumSamplingRate, "%trackformatwithhiresquality%", "%trackformatwithquality%");
170 | }
171 |
172 | // Album Templates
173 | if (QoAlbum != null)
174 | {
175 | template = ReplaceParentalWarningTags(template, QoAlbum.ParentalWarning);
176 | template = template
177 | .Replace("%albumid%", QoAlbum.Id.ToString())
178 | .Replace("%albumurl%", QoAlbum.Url.ToString())
179 | .Replace("%artistname%", GetReleaseArtists(QoAlbum))
180 | .Replace("%albumgenre%", QoAlbum?.Genre?.Name)
181 | .Replace("%albumcomposer%", QoAlbum?.Composer?.Name?.ToString())
182 | .Replace("%label%", Regex.Replace(QoAlbum.Label.Name, @"\s+", " ")) // Qobuz sometimes has multiple spaces in place of where a single space should be when it comes to Labels
183 | .Replace("%copyright%", QoAlbum.Copyright)
184 | .Replace("%upc%", QoAlbum.UPC)
185 | .Replace("%releasedate%", QoAlbum.ReleaseDateOriginal)
186 | .Replace("%year%", UInt32.Parse(QoAlbum.ReleaseDateOriginal.Substring(0, 4)).ToString())
187 | .Replace("%releasetype%", char.ToUpper(QoAlbum.ProductType.First()) + QoAlbum.ProductType.Substring(1).ToLower())
188 | .Replace("%bitdepth%", QoAlbum.MaximumBitDepth.ToString())
189 | .Replace("%samplerate%", QoAlbum.MaximumSamplingRate.ToString())
190 | .Replace("%albumtitle%", QoAlbum.Version == null ? QoAlbum.Title : $"{QoAlbum.Title.TrimEnd()} ({QoAlbum.Version})")
191 | .Replace("%format%", fileFormat.ToUpper().TrimStart('.'));
192 | }
193 |
194 | if (QoPlaylist == null)
195 | {
196 | // Release Format Templates
197 | template = RenameFormatTemplate(template, qbdlxForm._qbdlxForm.format_id, fileFormat, QoAlbum.MaximumBitDepth, QoAlbum.MaximumSamplingRate, "%formatwithhiresquality%", "%formatwithquality%");
198 | }
199 | else
200 | {
201 | // Playlist Templates
202 | template = template
203 | .Replace("%playlistid%", QoPlaylist.Id.ToString())
204 | .Replace("%playlisttitle%", QoPlaylist.Name)
205 | .Replace("%format%", fileFormat.ToUpper().TrimStart('.'))
206 | .Replace("%formatwithhiresquality%", fileFormat.ToUpper().TrimStart('.'))
207 | .Replace("%formatwithquality%", fileFormat.ToUpper().TrimStart('.'));
208 | }
209 |
210 | // GetSafeFilename call to make sure path will be valid
211 | template = GetSafeFilename(template);
212 |
213 | // Remove any double spaces
214 | template = Regex.Replace(Regex.Replace(template.Replace("{backslash}", @"\").Replace("{forwardslash}", @"/"), @"\s+", " ").Replace(@" \", @"\"), @"\s+\\", " "); // Replace slash placeholders & remove double spaces
215 |
216 | qbdlxForm._qbdlxForm.logger.Debug("Template output - " + template);
217 | return template;
218 | }
219 | }
220 | }
221 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Helpers/SearchPanelHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using QopenAPI;
3 | using QobuzDownloaderX.Properties;
4 | using System.Windows.Forms;
5 | using System.Drawing;
6 | using System.Threading.Tasks;
7 |
8 | namespace QobuzDownloaderX
9 | {
10 | class SearchPanelHelper
11 | {
12 | public Service QoService = new Service();
13 | public User QoUser = new User();
14 | public Item QoItem = new Item();
15 | public SearchAlbumResult QoAlbumSearch = new SearchAlbumResult();
16 | public SearchTrackResult QoTrackSearch = new SearchTrackResult();
17 |
18 | public void SearchInitiate(string searchType, string app_id, string searchQuery, string user_auth_token)
19 | {
20 | if (searchType == "releases")
21 | {
22 | QoAlbumSearch = QoService.SearchAlbumsWithAuth(app_id, searchQuery, 25, 0, user_auth_token);
23 | PopulateTableAlbums(qbdlxForm._qbdlxForm, QoAlbumSearch);
24 | }
25 | else if (searchType == "tracks")
26 | {
27 | QoTrackSearch = QoService.SearchTracksWithAuth(app_id, searchQuery, 25, 0, user_auth_token);
28 | PopulateTableTracks(qbdlxForm._qbdlxForm, QoTrackSearch);
29 | }
30 | }
31 |
32 | public void PopulateTableAlbums(qbdlxForm mainForm, SearchAlbumResult QoAlbumSearch)
33 | {
34 | // Access the "items" array from the response
35 | var albums = QoAlbumSearch.Albums.Items;
36 |
37 | // Load the font name from the translation file
38 | string fontName = qbdlxForm._qbdlxForm.languageManager.GetTranslation("TranslationFont");
39 |
40 | mainForm.Invoke((MethodInvoker)delegate ()
41 | {
42 | TableLayoutPanel searchResultsTablePanel = mainForm.searchResultsTablePanel;
43 | searchResultsTablePanel.Controls.Clear();
44 | searchResultsTablePanel.ColumnCount = 5; // Artwork, Artist, Title, Quality, Button
45 | searchResultsTablePanel.RowCount = 25; // Set row count based on the number of albums
46 | searchResultsTablePanel.AutoSize = true;
47 |
48 | // Set ColumnStyles to define the size of each column
49 | searchResultsTablePanel.ColumnStyles.Clear();
50 | searchResultsTablePanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 70F)); // Artwork column
51 | searchResultsTablePanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 200F)); // Artist name
52 | searchResultsTablePanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 200F)); // Album title
53 | searchResultsTablePanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 140F)); // Quality
54 | searchResultsTablePanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 70F)); // Button column
55 |
56 | int rowIndex = 0;
57 |
58 | foreach (var album in albums)
59 | {
60 | // Add PictureBox for artwork
61 | PictureBox artwork = new PictureBox();
62 | artwork.SizeMode = PictureBoxSizeMode.StretchImage;
63 | try { artwork.Load(album.Image.Large.ToString()); /* Using the thumbnail URL */ } catch { artwork.Image = Resources.qbdlx_new; /* Use QBDLX Icon as fallback */ }
64 | artwork.Width = 65;
65 | artwork.Height = 65;
66 | artwork.Anchor = AnchorStyles.None; // Center both horizontally and vertically
67 | searchResultsTablePanel.Controls.Add(artwork, 0, rowIndex);
68 |
69 | // Add Label for artist name
70 | System.Windows.Forms.Label artistName = new System.Windows.Forms.Label();
71 | artistName.Text = album.Artist.Name.ToString();
72 | artistName.AutoSize = true; // Disable auto-sizing to allow wrapping
73 | /*artistName.MaximumSize = new Size(0, 0);*/ // Word-wrap if needed
74 | artistName.TextAlign = ContentAlignment.MiddleCenter; // Center text horizontally and vertically
75 | artistName.Anchor = AnchorStyles.None; // Center within the cell
76 | artistName.ForeColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.LabelText); // Set text color
77 | artistName.Font = new Font(fontName, 10F, FontStyle.Regular); // Set font size and style
78 | searchResultsTablePanel.Controls.Add(artistName, 1, rowIndex);
79 |
80 | // Add Label for album title
81 | System.Windows.Forms.Label albumTitle = new System.Windows.Forms.Label();
82 | albumTitle.Text = album.Title.ToString().TrimEnd();
83 | if (album.Version != null) { albumTitle.Text = albumTitle.Text + " (" + album.Version + ")"; }
84 | if (album.ParentalWarning == true) { albumTitle.Text = "[E] " + albumTitle.Text; } // Add "[E]" if Qobuz lists the release with a parental warning
85 | albumTitle.AutoSize = true;
86 | /*albumTitle.MaximumSize = new Size(0, 0);*/ // Allow word-wrap
87 | albumTitle.TextAlign = ContentAlignment.MiddleCenter; // Center text horizontally and vertically
88 | albumTitle.Anchor = AnchorStyles.None; // Center within the cell
89 | albumTitle.ForeColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.LabelText); // Set text color
90 | albumTitle.Font = new Font(fontName, 10F, FontStyle.Regular); // Set font size and style
91 | searchResultsTablePanel.Controls.Add(albumTitle, 2, rowIndex);
92 |
93 | // Add Label for quality
94 | System.Windows.Forms.Label qualityLabel = new System.Windows.Forms.Label();
95 | qualityLabel.Text = album.MaximumBitDepth.ToString() + "bit/" + album.MaximumSamplingRate + "kHz";
96 | qualityLabel.AutoSize = true;
97 | qualityLabel.MaximumSize = new Size(0, 0); // Allow word-wrap
98 | qualityLabel.TextAlign = ContentAlignment.MiddleCenter; // Center text horizontally and vertically
99 | qualityLabel.Anchor = AnchorStyles.None; // Center within the cell
100 |
101 | // Set text color
102 | if (qualityLabel.Text.Contains("24bit"))
103 | {
104 | qualityLabel.ForeColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.HiResLabelText);
105 | }
106 | else
107 | {
108 | qualityLabel.ForeColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.LabelText); ;
109 | }
110 |
111 | qualityLabel.Font = new Font(fontName, 10F, FontStyle.Regular); // Set font size and style
112 | searchResultsTablePanel.Controls.Add(qualityLabel, 3, rowIndex);
113 |
114 | // Add Button for selecting album ID
115 | Button selectButton = new Button();
116 | selectButton.Text = qbdlxForm._qbdlxForm.languageManager.GetTranslation("downloadButton");
117 | selectButton.ForeColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.ButtonText); // Set button text color
118 | selectButton.BackColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.ButtonBackground); // Set button background color
119 | selectButton.Font = new Font(fontName, 8F, FontStyle.Regular); // Set font size and style
120 | selectButton.FlatStyle = FlatStyle.Flat; // Set FlatStyle to Flat
121 | selectButton.FlatAppearance.BorderSize = 0; // Set border size
122 | selectButton.FlatAppearance.MouseOverBackColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.HighlightedButtonBackground); // Set background color when hovering
123 | selectButton.FlatAppearance.MouseDownBackColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.ClickedButtonBackground); // Set background color when clicked
124 | string albumLink = "https://play.qobuz.com/album/" + album.Id.ToString(); // Store the album link
125 | selectButton.Click += (sender, e) => SendURL(mainForm, albumLink);
126 | selectButton.Anchor = AnchorStyles.None; // Center the button
127 | searchResultsTablePanel.Controls.Add(selectButton, 4, rowIndex);
128 |
129 | rowIndex++;
130 | }
131 | });
132 | }
133 |
134 | public void PopulateTableTracks(qbdlxForm mainForm, SearchTrackResult QoTrackSearch)
135 | {
136 | // Access the "items" array from the response
137 | var tracks = QoTrackSearch.Tracks.Items;
138 |
139 | // Load the font name from the translation file
140 | string fontName = qbdlxForm._qbdlxForm.languageManager.GetTranslation("TranslationFont");
141 |
142 | mainForm.Invoke((MethodInvoker)delegate ()
143 | {
144 | TableLayoutPanel searchResultsTablePanel = mainForm.searchResultsTablePanel;
145 | searchResultsTablePanel.Controls.Clear();
146 | searchResultsTablePanel.ColumnCount = 5; // Artwork, Artist, Title, Quality, Button
147 | searchResultsTablePanel.RowCount = 25; // Set row count based on the number of albums
148 | searchResultsTablePanel.AutoSize = true;
149 |
150 | // Set ColumnStyles to define the size of each column
151 | searchResultsTablePanel.ColumnStyles.Clear();
152 | searchResultsTablePanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 70F)); // Artwork column
153 | searchResultsTablePanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 200F)); // Artist name
154 | searchResultsTablePanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 200F)); // Track title
155 | searchResultsTablePanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 140F)); // Quality
156 | searchResultsTablePanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 70F)); // Button column
157 |
158 | int rowIndex = 0;
159 |
160 | foreach (var track in tracks)
161 | {
162 | // Add PictureBox for artwork
163 | PictureBox artwork = new PictureBox();
164 | artwork.SizeMode = PictureBoxSizeMode.StretchImage;
165 | try { artwork.Load(track.Album.Image.Large.ToString()); /* Using the thumbnail URL */ } catch { artwork.Image = Resources.qbdlx_new; /* Use QBDLX Icon as fallback */ }
166 | artwork.Width = 65;
167 | artwork.Height = 65;
168 | artwork.Anchor = AnchorStyles.None; // Center both horizontally and vertically
169 | searchResultsTablePanel.Controls.Add(artwork, 0, rowIndex);
170 |
171 | // Add Label for artist name
172 | System.Windows.Forms.Label artistName = new System.Windows.Forms.Label();
173 | artistName.Text = track.Performer.Name.ToString();
174 | artistName.AutoSize = true; // Disable auto-sizing to allow wrapping
175 | /*artistName.MaximumSize = new Size(0, 0);*/ // Word-wrap if needed
176 | artistName.TextAlign = ContentAlignment.MiddleCenter; // Center text horizontally and vertically
177 | artistName.Anchor = AnchorStyles.None; // Center within the cell
178 | artistName.ForeColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.LabelText); // Set text color
179 | artistName.Font = new Font(fontName, 10F, FontStyle.Regular); // Set font size and style
180 | searchResultsTablePanel.Controls.Add(artistName, 1, rowIndex);
181 |
182 | // Add Label for track title
183 | System.Windows.Forms.Label trackTitle = new System.Windows.Forms.Label();
184 | trackTitle.Text = track.Title.ToString().TrimEnd();
185 | if (track.Version != null) { trackTitle.Text = trackTitle.Text + " (" + track.Version + ")"; }
186 | if (track.ParentalWarning == true) { trackTitle.Text = "[E] " + trackTitle.Text; } // Add "[E]" if Qobuz lists the track with a parental warning
187 | trackTitle.AutoSize = true;
188 | /*trackTitle.MaximumSize = new Size(0, 0);*/ // Allow word-wrap
189 | trackTitle.TextAlign = ContentAlignment.MiddleCenter; // Center text horizontally and vertically
190 | trackTitle.Anchor = AnchorStyles.None; // Center within the cell
191 | trackTitle.ForeColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.LabelText); // Set text color
192 | trackTitle.Font = new Font(fontName, 10F, FontStyle.Regular); // Set font size and style
193 | searchResultsTablePanel.Controls.Add(trackTitle, 2, rowIndex);
194 |
195 | // Add Label for quality
196 | System.Windows.Forms.Label qualityLabel = new System.Windows.Forms.Label();
197 | qualityLabel.Text = track.MaximumBitDepth.ToString() + "bit/" + track.MaximumSamplingRate + "kHz";
198 | qualityLabel.AutoSize = true;
199 | qualityLabel.MaximumSize = new Size(0, 0); // Allow word-wrap
200 | qualityLabel.TextAlign = ContentAlignment.MiddleCenter; // Center text horizontally and vertically
201 | qualityLabel.Anchor = AnchorStyles.None; // Center within the cell
202 |
203 | // Set text color
204 | if (qualityLabel.Text.Contains("24bit"))
205 | {
206 | qualityLabel.ForeColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.HiResLabelText);
207 | }
208 | else
209 | {
210 | qualityLabel.ForeColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.LabelText);
211 | }
212 |
213 | qualityLabel.Font = new Font(fontName, 10F, FontStyle.Regular); // Set font size and style
214 | searchResultsTablePanel.Controls.Add(qualityLabel, 3, rowIndex);
215 |
216 | // Add Button for selecting album ID
217 | Button selectButton = new Button();
218 | selectButton.Text = qbdlxForm._qbdlxForm.languageManager.GetTranslation("downloadButton");
219 | selectButton.ForeColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.ButtonText); // Set button text color
220 | selectButton.BackColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.ButtonBackground); // Set button background color
221 | selectButton.Font = new Font(fontName, 8F, FontStyle.Regular); // Set font size and style
222 | selectButton.FlatStyle = FlatStyle.Flat; // Set FlatStyle to Flat
223 | selectButton.FlatAppearance.BorderSize = 0; // Set border size
224 | selectButton.FlatAppearance.MouseOverBackColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.HighlightedButtonBackground); // Set background color when hovering
225 | selectButton.FlatAppearance.MouseDownBackColor = ColorTranslator.FromHtml(qbdlxForm._qbdlxForm._themeManager._currentTheme.ClickedButtonBackground); // Set background color when clicked
226 | string trackLink = "https://open.qobuz.com/track/" + track.Id.ToString(); // Store the track link
227 | selectButton.Click += (sender, e) => SendURL(mainForm, trackLink);
228 | selectButton.Anchor = AnchorStyles.None; // Center the button
229 | searchResultsTablePanel.Controls.Add(selectButton, 4, rowIndex);
230 |
231 | rowIndex++;
232 | }
233 | });
234 | }
235 |
236 | public void SendURL(qbdlxForm mainForm, string url)
237 | {
238 | try
239 | {
240 | // Send URL to the input textbox, and start download
241 | mainForm.logger.Debug("Sending URL to download panel, and starting download");
242 | TextBox inputTextbox = mainForm.inputTextbox;
243 | inputTextbox.Text = url;
244 | inputTextbox.ForeColor = Color.FromArgb(200, 200, 200);
245 | mainForm.downloaderButton_Click(this, EventArgs.Empty);
246 | mainForm.getLinkType();
247 | }
248 | catch (Exception ex)
249 | {
250 | mainForm.logger.Error("Error on SendURL (SearchPanelHelper). Error below:\r\n" + ex);
251 | return;
252 | }
253 | }
254 | }
255 | }
256 |
--------------------------------------------------------------------------------
/QobuzDownloaderX/Old/LoginForm-v2.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace QobuzDownloaderX
2 | {
3 | partial class LoginFrm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(LoginFrm));
32 | this.panel1 = new System.Windows.Forms.Panel();
33 | this.disableLogin = new System.Windows.Forms.CheckBox();
34 | this.verNumLabel2 = new System.Windows.Forms.Label();
35 | this.md5Button = new System.Windows.Forms.Button();
36 | this.exitLabel = new System.Windows.Forms.Label();
37 | this.pictureBox1 = new System.Windows.Forms.PictureBox();
38 | this.userAuthTokenTextbox = new System.Windows.Forms.TextBox();
39 | this.loginButton = new System.Windows.Forms.Button();
40 | this.panel3 = new System.Windows.Forms.Panel();
41 | this.panel4 = new System.Windows.Forms.Panel();
42 | this.emailTextbox = new System.Windows.Forms.TextBox();
43 | this.passwordTextbox = new System.Windows.Forms.TextBox();
44 | this.loginText = new System.Windows.Forms.Label();
45 | this.getSecretBG = new System.ComponentModel.BackgroundWorker();
46 | this.loginBG = new System.ComponentModel.BackgroundWorker();
47 | this.visableCheckbox = new System.Windows.Forms.CheckBox();
48 | this.altLoginLabel = new System.Windows.Forms.Label();
49 | this.altLoginTutLabel = new System.Windows.Forms.Label();
50 | this.userIdTextbox = new System.Windows.Forms.TextBox();
51 | this.altLoginBG = new System.ComponentModel.BackgroundWorker();
52 | this.aboutLabel = new System.Windows.Forms.Label();
53 | this.panel1.SuspendLayout();
54 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
55 | this.SuspendLayout();
56 | //
57 | // panel1
58 | //
59 | this.panel1.BackgroundImage = null;
60 | this.panel1.Controls.Add(this.aboutLabel);
61 | this.panel1.Controls.Add(this.disableLogin);
62 | this.panel1.Controls.Add(this.verNumLabel2);
63 | this.panel1.Controls.Add(this.md5Button);
64 | this.panel1.Controls.Add(this.exitLabel);
65 | this.panel1.Controls.Add(this.pictureBox1);
66 | this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
67 | this.panel1.Location = new System.Drawing.Point(0, 0);
68 | this.panel1.Name = "panel1";
69 | this.panel1.Size = new System.Drawing.Size(282, 175);
70 | this.panel1.TabIndex = 0;
71 | this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseMove);
72 | //
73 | // disableLogin
74 | //
75 | this.disableLogin.AutoSize = true;
76 | this.disableLogin.ForeColor = System.Drawing.Color.Transparent;
77 | this.disableLogin.Location = new System.Drawing.Point(12, 155);
78 | this.disableLogin.Name = "disableLogin";
79 | this.disableLogin.Size = new System.Drawing.Size(90, 17);
80 | this.disableLogin.TabIndex = 34;
81 | this.disableLogin.Text = "Disable Login";
82 | this.disableLogin.UseVisualStyleBackColor = true;
83 | this.disableLogin.Visible = false;
84 | //
85 | // verNumLabel2
86 | //
87 | this.verNumLabel2.BackColor = System.Drawing.Color.Transparent;
88 | this.verNumLabel2.Font = new System.Drawing.Font("Trebuchet MS", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
89 | this.verNumLabel2.ForeColor = System.Drawing.Color.White;
90 | this.verNumLabel2.Location = new System.Drawing.Point(194, 157);
91 | this.verNumLabel2.Name = "verNumLabel2";
92 | this.verNumLabel2.Size = new System.Drawing.Size(85, 18);
93 | this.verNumLabel2.TabIndex = 32;
94 | this.verNumLabel2.Text = "#.#.#.#";
95 | this.verNumLabel2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
96 | this.verNumLabel2.MouseMove += new System.Windows.Forms.MouseEventHandler(this.verNumLabel2_MouseMove);
97 | //
98 | // md5Button
99 | //
100 | this.md5Button.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(112)))), ((int)(((byte)(239)))));
101 | this.md5Button.Enabled = false;
102 | this.md5Button.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20)))));
103 | this.md5Button.FlatAppearance.BorderSize = 2;
104 | this.md5Button.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
105 | this.md5Button.ForeColor = System.Drawing.Color.White;
106 | this.md5Button.Location = new System.Drawing.Point(227, 122);
107 | this.md5Button.Name = "md5Button";
108 | this.md5Button.Size = new System.Drawing.Size(43, 27);
109 | this.md5Button.TabIndex = 9;
110 | this.md5Button.Text = "MD5";
111 | this.md5Button.UseVisualStyleBackColor = false;
112 | this.md5Button.Visible = false;
113 | this.md5Button.Click += new System.EventHandler(this.md5Button_Click);
114 | //
115 | // exitLabel
116 | //
117 | this.exitLabel.AutoSize = true;
118 | this.exitLabel.BackColor = System.Drawing.Color.Transparent;
119 | this.exitLabel.Font = new System.Drawing.Font("Calibri", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
120 | this.exitLabel.ForeColor = System.Drawing.Color.Black;
121 | this.exitLabel.Location = new System.Drawing.Point(262, 0);
122 | this.exitLabel.Name = "exitLabel";
123 | this.exitLabel.Size = new System.Drawing.Size(20, 23);
124 | this.exitLabel.TabIndex = 9;
125 | this.exitLabel.Text = "X";
126 | this.exitLabel.TextAlign = System.Drawing.ContentAlignment.TopCenter;
127 | this.exitLabel.Click += new System.EventHandler(this.exitLabel_Click);
128 | //
129 | // pictureBox1
130 | //
131 | this.pictureBox1.BackColor = System.Drawing.Color.Transparent;
132 | this.pictureBox1.Image = null;
133 | this.pictureBox1.Location = new System.Drawing.Point(12, 52);
134 | this.pictureBox1.Name = "pictureBox1";
135 | this.pictureBox1.Size = new System.Drawing.Size(258, 64);
136 | this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
137 | this.pictureBox1.TabIndex = 29;
138 | this.pictureBox1.TabStop = false;
139 | this.pictureBox1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseMove);
140 | //
141 | // userAuthTokenTextbox
142 | //
143 | this.userAuthTokenTextbox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20)))));
144 | this.userAuthTokenTextbox.BorderStyle = System.Windows.Forms.BorderStyle.None;
145 | this.userAuthTokenTextbox.Font = new System.Drawing.Font("Trebuchet MS", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
146 | this.userAuthTokenTextbox.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(88)))), ((int)(((byte)(92)))), ((int)(((byte)(102)))));
147 | this.userAuthTokenTextbox.Location = new System.Drawing.Point(12, 255);
148 | this.userAuthTokenTextbox.Multiline = true;
149 | this.userAuthTokenTextbox.Name = "userAuthTokenTextbox";
150 | this.userAuthTokenTextbox.Size = new System.Drawing.Size(237, 23);
151 | this.userAuthTokenTextbox.TabIndex = 35;
152 | this.userAuthTokenTextbox.Text = "user_auth_token";
153 | this.userAuthTokenTextbox.Visible = false;
154 | this.userAuthTokenTextbox.Click += new System.EventHandler(this.userAuthTokenTextbox_Click);
155 | this.userAuthTokenTextbox.Leave += new System.EventHandler(this.userAuthTokenTextbox_Leave);
156 | //
157 | // loginButton
158 | //
159 | this.loginButton.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(112)))), ((int)(((byte)(239)))));
160 | this.loginButton.FlatAppearance.BorderSize = 0;
161 | this.loginButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
162 | this.loginButton.Font = new System.Drawing.Font("Trebuchet MS", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
163 | this.loginButton.ForeColor = System.Drawing.Color.White;
164 | this.loginButton.Location = new System.Drawing.Point(12, 293);
165 | this.loginButton.Name = "loginButton";
166 | this.loginButton.Size = new System.Drawing.Size(258, 30);
167 | this.loginButton.TabIndex = 2;
168 | this.loginButton.Text = "LOGIN";
169 | this.loginButton.UseVisualStyleBackColor = false;
170 | this.loginButton.Click += new System.EventHandler(this.loginButton_Click);
171 | //
172 | // panel3
173 | //
174 | this.panel3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(88)))), ((int)(((byte)(92)))), ((int)(((byte)(102)))));
175 | this.panel3.Location = new System.Drawing.Point(12, 221);
176 | this.panel3.Name = "panel3";
177 | this.panel3.Size = new System.Drawing.Size(258, 1);
178 | this.panel3.TabIndex = 2;
179 | //
180 | // panel4
181 | //
182 | this.panel4.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(88)))), ((int)(((byte)(92)))), ((int)(((byte)(102)))));
183 | this.panel4.Location = new System.Drawing.Point(12, 277);
184 | this.panel4.Name = "panel4";
185 | this.panel4.Size = new System.Drawing.Size(258, 1);
186 | this.panel4.TabIndex = 2;
187 | //
188 | // emailTextbox
189 | //
190 | this.emailTextbox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20)))));
191 | this.emailTextbox.BorderStyle = System.Windows.Forms.BorderStyle.None;
192 | this.emailTextbox.Font = new System.Drawing.Font("Trebuchet MS", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
193 | this.emailTextbox.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(88)))), ((int)(((byte)(92)))), ((int)(((byte)(102)))));
194 | this.emailTextbox.Location = new System.Drawing.Point(12, 199);
195 | this.emailTextbox.Multiline = true;
196 | this.emailTextbox.Name = "emailTextbox";
197 | this.emailTextbox.Size = new System.Drawing.Size(258, 23);
198 | this.emailTextbox.TabIndex = 7;
199 | this.emailTextbox.Text = "Email";
200 | this.emailTextbox.Click += new System.EventHandler(this.emailTextbox_Click);
201 | this.emailTextbox.Leave += new System.EventHandler(this.emailTextbox_Leave);
202 | //
203 | // passwordTextbox
204 | //
205 | this.passwordTextbox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20)))));
206 | this.passwordTextbox.BorderStyle = System.Windows.Forms.BorderStyle.None;
207 | this.passwordTextbox.Font = new System.Drawing.Font("Trebuchet MS", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
208 | this.passwordTextbox.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(88)))), ((int)(((byte)(92)))), ((int)(((byte)(102)))));
209 | this.passwordTextbox.Location = new System.Drawing.Point(12, 255);
210 | this.passwordTextbox.Multiline = true;
211 | this.passwordTextbox.Name = "passwordTextbox";
212 | this.passwordTextbox.Size = new System.Drawing.Size(237, 23);
213 | this.passwordTextbox.TabIndex = 8;
214 | this.passwordTextbox.Text = "Password";
215 | this.passwordTextbox.Click += new System.EventHandler(this.passwordTextbox_Click);
216 | this.passwordTextbox.Leave += new System.EventHandler(this.passwordTextbox_Leave);
217 | //
218 | // loginText
219 | //
220 | this.loginText.Font = new System.Drawing.Font("Trebuchet MS", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
221 | this.loginText.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(88)))), ((int)(((byte)(92)))), ((int)(((byte)(102)))));
222 | this.loginText.Location = new System.Drawing.Point(12, 349);
223 | this.loginText.Name = "loginText";
224 | this.loginText.Size = new System.Drawing.Size(258, 23);
225 | this.loginText.TabIndex = 30;
226 | this.loginText.Text = "Waiting for login...";
227 | this.loginText.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
228 | //
229 | // getSecretBG
230 | //
231 | this.getSecretBG.DoWork += new System.ComponentModel.DoWorkEventHandler(this.getSecretBG_DoWork);
232 | //
233 | // loginBG
234 | //
235 | this.loginBG.DoWork += new System.ComponentModel.DoWorkEventHandler(this.loginBG_DoWork);
236 | //
237 | // visableCheckbox
238 | //
239 | this.visableCheckbox.AutoSize = true;
240 | this.visableCheckbox.Location = new System.Drawing.Point(255, 256);
241 | this.visableCheckbox.Name = "visableCheckbox";
242 | this.visableCheckbox.Size = new System.Drawing.Size(15, 14);
243 | this.visableCheckbox.TabIndex = 31;
244 | this.visableCheckbox.UseVisualStyleBackColor = true;
245 | this.visableCheckbox.CheckedChanged += new System.EventHandler(this.visableCheckbox_CheckedChanged);
246 | //
247 | // altLoginLabel
248 | //
249 | this.altLoginLabel.Font = new System.Drawing.Font("Trebuchet MS", 8.25F);
250 | this.altLoginLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(88)))), ((int)(((byte)(92)))), ((int)(((byte)(102)))));
251 | this.altLoginLabel.Location = new System.Drawing.Point(12, 326);
252 | this.altLoginLabel.Name = "altLoginLabel";
253 | this.altLoginLabel.Size = new System.Drawing.Size(258, 20);
254 | this.altLoginLabel.TabIndex = 32;
255 | this.altLoginLabel.Text = "Can\'t login? Click here";
256 | this.altLoginLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
257 | this.altLoginLabel.Click += new System.EventHandler(this.altLoginLabel_Click);
258 | //
259 | // altLoginTutLabel
260 | //
261 | this.altLoginTutLabel.AutoSize = true;
262 | this.altLoginTutLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(88)))), ((int)(((byte)(92)))), ((int)(((byte)(102)))));
263 | this.altLoginTutLabel.Location = new System.Drawing.Point(77, 180);
264 | this.altLoginTutLabel.Name = "altLoginTutLabel";
265 | this.altLoginTutLabel.Size = new System.Drawing.Size(128, 13);
266 | this.altLoginTutLabel.TabIndex = 33;
267 | this.altLoginTutLabel.Text = "Click Here for Instructions";
268 | this.altLoginTutLabel.Visible = false;
269 | this.altLoginTutLabel.Click += new System.EventHandler(this.altLoginTutLabel_Click);
270 | //
271 | // userIdTextbox
272 | //
273 | this.userIdTextbox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20)))));
274 | this.userIdTextbox.BorderStyle = System.Windows.Forms.BorderStyle.None;
275 | this.userIdTextbox.Font = new System.Drawing.Font("Trebuchet MS", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
276 | this.userIdTextbox.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(88)))), ((int)(((byte)(92)))), ((int)(((byte)(102)))));
277 | this.userIdTextbox.Location = new System.Drawing.Point(12, 199);
278 | this.userIdTextbox.Multiline = true;
279 | this.userIdTextbox.Name = "userIdTextbox";
280 | this.userIdTextbox.Size = new System.Drawing.Size(258, 23);
281 | this.userIdTextbox.TabIndex = 9;
282 | this.userIdTextbox.Text = "user_id";
283 | this.userIdTextbox.Visible = false;
284 | this.userIdTextbox.Click += new System.EventHandler(this.userIdTextbox_Click);
285 | this.userIdTextbox.Leave += new System.EventHandler(this.userIdTextbox_Leave);
286 | //
287 | // altLoginBG
288 | //
289 | this.altLoginBG.DoWork += new System.ComponentModel.DoWorkEventHandler(this.altLoginBG_DoWork);
290 | //
291 | // aboutLabel
292 | //
293 | this.aboutLabel.AutoSize = true;
294 | this.aboutLabel.BackColor = System.Drawing.Color.Transparent;
295 | this.aboutLabel.Font = new System.Drawing.Font("Calibri", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
296 | this.aboutLabel.ForeColor = System.Drawing.Color.Black;
297 | this.aboutLabel.Location = new System.Drawing.Point(241, 0);
298 | this.aboutLabel.Name = "aboutLabel";
299 | this.aboutLabel.Size = new System.Drawing.Size(15, 23);
300 | this.aboutLabel.TabIndex = 35;
301 | this.aboutLabel.Text = "i";
302 | this.aboutLabel.TextAlign = System.Drawing.ContentAlignment.TopCenter;
303 | this.aboutLabel.Click += new System.EventHandler(this.aboutLabel_Click);
304 | //
305 | // LoginFrm
306 | //
307 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
308 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
309 | this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20)))));
310 | this.ClientSize = new System.Drawing.Size(282, 392);
311 | this.Controls.Add(this.altLoginTutLabel);
312 | this.Controls.Add(this.altLoginLabel);
313 | this.Controls.Add(this.visableCheckbox);
314 | this.Controls.Add(this.loginText);
315 | this.Controls.Add(this.panel4);
316 | this.Controls.Add(this.panel3);
317 | this.Controls.Add(this.passwordTextbox);
318 | this.Controls.Add(this.emailTextbox);
319 | this.Controls.Add(this.loginButton);
320 | this.Controls.Add(this.panel1);
321 | this.Controls.Add(this.userIdTextbox);
322 | this.Controls.Add(this.userAuthTokenTextbox);
323 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
324 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
325 | this.Name = "LoginFrm";
326 | this.Text = "QobuzDLX | Login";
327 | this.Load += new System.EventHandler(this.LoginFrm_Load);
328 | this.panel1.ResumeLayout(false);
329 | this.panel1.PerformLayout();
330 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
331 | this.ResumeLayout(false);
332 | this.PerformLayout();
333 |
334 | }
335 |
336 | #endregion
337 |
338 | private System.Windows.Forms.Panel panel1;
339 | private System.Windows.Forms.PictureBox pictureBox1;
340 | private System.Windows.Forms.Button loginButton;
341 | private System.Windows.Forms.Panel panel3;
342 | private System.Windows.Forms.Panel panel4;
343 | private System.Windows.Forms.TextBox emailTextbox;
344 | private System.Windows.Forms.TextBox passwordTextbox;
345 | private System.Windows.Forms.Label exitLabel;
346 | private System.Windows.Forms.Button md5Button;
347 | private System.Windows.Forms.Label loginText;
348 | private System.ComponentModel.BackgroundWorker getSecretBG;
349 | private System.ComponentModel.BackgroundWorker loginBG;
350 | private System.Windows.Forms.Label verNumLabel2;
351 | private System.Windows.Forms.CheckBox visableCheckbox;
352 | private System.Windows.Forms.CheckBox disableLogin;
353 | private System.Windows.Forms.TextBox userAuthTokenTextbox;
354 | private System.Windows.Forms.Label altLoginLabel;
355 | private System.Windows.Forms.Label altLoginTutLabel;
356 | private System.Windows.Forms.TextBox userIdTextbox;
357 | private System.ComponentModel.BackgroundWorker altLoginBG;
358 | private System.Windows.Forms.Label aboutLabel;
359 | }
360 | }
--------------------------------------------------------------------------------