Build an Electron.JS Udemy Course Downloader in node.JS GUI Desktop App in Javascript

You are currently viewing Build an Electron.JS Udemy Course Downloader in node.JS GUI Desktop App in Javascript

Build an Electron.js Udemy Course Downloader in Node.js GUI Desktop App in Javascript

You must have npm and nodejs installed.
 

1. Clone the project
2. Run npm install
3. Run npm start
 

npm run dist
 

npm run build-win
 

npm run build-mac
 

npm run build-linux
 

npm run build
 

npm run build-win -- --ia32

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Udeler | Udemy Course Downloader</title>
    <link rel="stylesheet" href="assets/css/semantic.min.css" />
    <link rel="stylesheet" href="assets/css/style.css" />
  </head>
  <body>
    <div class="ui basic subtitle modal">
      <div class="ui icon header">
        <i class="closed captioning icon"></i>
        Select Subtitle
      </div>
      <div class="content">
        <div class="ui fluid selection dropdown">
          <input type="hidden" name="subtitle" />
          <i class="dropdown icon"></i>
          <div class="default text">Subtitle Language</div>
        </div>
      </div>
    </div>
    <div class="ui basic update-available modal">
      <div class="ui icon header">
        <i class="gift icon"></i>
        New Update Available
      </div>
      <div class="content">
        <p>
          <center>
            A new version of Udeler is available. You can download the latest
            version from github releases page
          </center>
        </p>
      </div>
      <div class="actions" style="text-align: center;">
        <div class="ui red cancel inverted button">
          <i class="remove icon"></i>
          Cancel
        </div>
        <div class="ui green ok inverted download-update button">
          <i class="checkmark icon"></i>
          Download
        </div>
      </div>
    </div>
    <script>
      const $ = (jQuery = require("jquery"));
    </script>
    <script src="assets/js/semantic.min.js"></script>
    <script type="text/javascript">
      const settings = require("electron-settings");
      const appVersion = require(__dirname + "/package.json").version;
      function translate(text) {
        if (
          !settings.get("general.language") ||
          settings.get("general.language") == "English"
        ) {
          return text;
        } else {
          try {
            var meta = require("./locale/meta.json");
            var locale = require(`./locale/${
              meta[settings.get("general.language")]
            }`);
            return locale[text] || text;
          } catch (e) {
            return text;
          }
        }
      }
 
      var template = `
        <div class="ui center aligned login grid">
            <div class="ui login dimmer">
              <div class="ui big text loader">${translate("Logging in")}</div>
            </div>
            <div class="ui authenticator dimmer">
              <div class="ui big text loader">
                ${translate("Awaiting Login Request")}
              </div>
            </div>
    
          <div class="row">
            <div class="ten wide column">
                    <h2 class="ui icon grey login header">
                      <i class="circular green user icon"></i>
                      ${translate("Udemy Login")}
                    </h2>
            </div>
          </div>
          <div class="row">
              <div class="ten wide column">
                <form class="ui form">
                <div class="field">                  
                   <div class="ui fluid label checkbox">
                    <input type="checkbox" name="business" id="business">
                    <label for="business">${translate(
                      "Udemy Business"
                    )} ?</label>
                  </div>
                </div>
                <div class="field">
                  <input type="text" id="subdomain" name="subdomain" placeholder="${translate(
                    "Udemy Business Name"
                  )}" style="display: none">
                </div>
              </form>
              <div class="ui horizontal divider">
                Choose Login Method
              </div>
              <button class="ui fluid green button" type="button" onclick="loginWithUdemy()">${translate(
                "Login Using Credentials"
              )}</button>
              <div class="ui horizontal divider">
                Or
              </div>
              <div class="ui fluid icon buttons">
                <button class="ui teal login disabled authenticator button"><i class="user secret icon"></i> Authenticator</button>
                <div class="or"></div>
                <button class="ui blue button" onclick="loginWithAccessToken()"><i class="key icon"></i> Access Token</button>
              </div>
              </div>
          </div>
  </div>
     <div class="ui dashboard">    
            <div class="ui logout dimmer">
              <div class="ui big text loader">${translate("Logging Out")}</div>
            </div>  
            <div class="ui courses dimmer">
              <div class="ui big text loader">${translate(
                "Loading Courses"
              )}</div>
            </div>
             <div class="ui course dimmer">
              <div class="ui big text loader">${translate("Getting Info")}</div>
            </div>
            <div class="ui about dimmer">
              <div class="ui big text loader">${translate(
                "Checking for Updates"
              )}</div>
            </div>
              <div class="ui visible fixed vertical inverted sidebar labeled icon menu ${
                settings.get("general.language") == "Arabic" ? "right" : "left"
              }">
                <a class="active red courses-sidebar item">
                  <i class="file video icon"></i>
                  ${translate("Courses")}
                </a>
                <a class="downloads-sidebar item">
                  <i class="download icon"></i>
                  ${translate("Downloads")}
                </a>
               <a class="settings-sidebar item">
                  <i class="wrench icon"></i>
                  ${translate("Settings")}
                </a>
                <a class="about-sidebar item">
                  <i class="info icon"></i>
                  ${translate("About")}
                </a>
                <a class="logout-sidebar item">
                  <i class="power off icon"></i>
                  ${translate("Logout")}
                </a>
              </div>
                  <div class="content">
                      <div class="ui courses section">
                        <form class="ui search form">
                        <div class="ui fluid search">
                          <div class="ui fluid icon input">
                            <input class="prompt" type="text" placeholder="${translate(
                              "Search Courses"
                            )}">
                            <i class="search icon"></i>
                          </div>
                        </div>
                        </form>
                        <div class="ui divided unstackable courses items">
                        </div>
                      </div>
                    <div class="ui downloads section">
                        <h5 class="ui top attached header">
                              <i class="ui download icon"></i> ${translate(
                                "Downloads"
                              )}
                        </h5>
                        <div class="ui divided unstackable courses items attached segment">
                        </div>
                      </div>
                      <div class="ui settings section">
                      <form class="ui form">
                        <h5 class="ui top attached  header">
                              <i class="ui download icon"></i> ${translate(
                                "Download Settings"
                              )}
                          </h5>
                            <div class="ui attached  segment">
                                <div class="field">
                                      <label>${translate(
                                        "Download Path"
                                      )}</label>
                                    <div class="ui action input">
                                        <input type="text" readonly name="downloadpath">
                                        <label class="ui icon button btn-file" onclick="selectDownloadPath()">
                                             <i class="folder icon"></i>
                                        </label>
                                    </div>
                                </div>        
                              <div class="field">
                                <div class="ui checkbox">
                                    <input type="checkbox" name="enabledownloadstartend">
                                    <label>${translate(
                                      "Enable Download Start/End"
                                    )}</label>
                                  </div>
                                </div>
                              <div class="two unstackable fields">
                                  <div class="field">
                                    <label>${translate(
                                      "Download Start"
                                    )}</label>
                                    <input placeholder="${translate(
                                      "Start Download at"
                                    )}" type="number" min="1" name="downloadstart">
                                  </div>
                                  <div class="field">
                                    <label>${translate("Download End")}</label>
                                    <input placeholder="${translate(
                                      "End Download at"
                                    )}" type="number" min="1" name="downloadend">
                                  </div>
                                </div>
                                  <div class="ui  divider"></div>
                                    <div class="field">
                                      <div class="ui checkbox">
                                          <input type="checkbox" name="skipattachments">
                                          <label>${translate(
                                            "Skip Attachments"
                                          )}</label>
                                        </div>
                                      </div>
                                    <div class="field">
                                      <label>${translate(
                                        "Video Quality"
                                      )}</label>
                                      <div class="ui fluid search selection dropdown">
                                          <input type="hidden" name="videoquality">
                                          <i class="dropdown icon"></i>
                                          <div class="default text"></div>
                                          <div class="menu">
                                          <div class="item" data-value="Auto">${translate(
                                            "Auto"
                                          )}</div>
                                          <div class="item" data-value="Lowest">${translate(
                                            "Lowest"
                                          )}</div>
                                          <div class="item" data-value="360p">360p</div>
                                          <div class="item" data-value="480p">480p</div>
                                          <div class="item" data-value="720p">720p</div>
                                          <div class="item" data-value="1080p">1080p</div>
                                          <div class="item" data-value="Highest">${translate(
                                            "Highest"
                                          )}</div>
                                        </div>
                                         </div>
                                    </div>
                                    <div class="field">
                                      <div class="ui checkbox">
                                          <input type="checkbox" name="skipsubtitles">
                                          <label>${translate(
                                            "Skip Subtitles"
                                          )}</label>
                                        </div>
                                      </div>
                                      <div class="field">
                                      <div class="ui checkbox">
                                          <input type="checkbox" name="autoretry">
                                          <label>${translate(
                                            "Auto Retry on Error (Experimental)"
                                          )}</label>
                                        </div>
                                      </div>
                              </div>
                          <h5 class="ui top attached  header">
                              <i class="ui setting icon"></i> ${translate(
                                "Application Settings"
                              )}
                          </h5>
                          <div class="ui attached segment">
                             <div class="field">
                                      <label>${translate(
                                        "Language (Requires App Restart)"
                                      )}</label>
                                      <div class="ui fluid search selection language dropdown">
                                          <input type="hidden" name="language">
                                          <i class="dropdown icon"></i>
                                          <div class="default text"></div>
                                          <div class="menu">
                                          <div class="item" data-value="English">English</div>
                                        </div>
                                      </div>
                                </div>
                            </div>
                              <div class="ui horizontal divider"></div>
                              <button class="ui fluid green button" type="submit">${translate(
                                "Save"
                              )}</button>
                          </form>
                      </div>
                      <div class="ui about section">  
                          <div class="ui segment">
                            <h4 class="ui center aligned icon header">
                              <i class="grey file code outline icon"></i>
                              Udeler v${appVersion}
                            </h4>
                            <button class="ui tiny fluid basic check-updates button">${translate(
                              "Check for updates"
                            )}</button>
                            <h3 class="ui header">${translate("Links")}</h3>
                            <div class="ui relaxed divided list">
                              <div class="item">
                                <i class="large github middle aligned icon"></i>
                                <div class="content">
                                  <a class="header" href="https://github.com/FaisalUmair/udemy-downloader-gui">FaisalUmair/udemy-downloader-gui</a>
                                  <div class="description">${translate(
                                    "Repository"
                                  )}</div>
                                </div>
                              </div>
                              <div class="item">
                                <i class="large github middle aligned icon"></i>
                                <div class="content">
                                  <a class="header" href="https://github.com/FaisalUmair">FaisalUmair</a>
                                  <div class="description">${translate(
                                    "Developer"
                                  )}</div>
                                </div>
                              </div>
                              <div class="item">
                                <i class="large world middle aligned icon"></i>
                                <div class="content">
                                  <a class="header" href="http://thewebartisans.net/">thewebartisans.net</a>
                                  <div class="description">${translate(
                                    "Website"
                                  )}</div>
                                </div>
                              </div>
                            </div>
                            <h3 class="ui header">${translate(
                              "Development"
                            )}</h3>
                              <div class="ui relaxed divided list">
                                <div class="item">
                                  <i class="large github middle aligned icon"></i>
                                  <div class="content">
                                    <a class="header" href="https://github.com/FaisalUmair/udemy-downloader-gui/issues">udemy-downloader-gui/issues</a>
                                    <div class="description">${translate(
                                      "Report Bug"
                                    )}</div>
                                  </div>
                                </div>
                                <div class="item">
                                  <i class="large github middle aligned icon"></i>
                                  <div class="content">
                                    <a class="header" href="https://github.com/FaisalUmair/udemy-downloader-gui/pulls">udemy-downloader-gui/pulls</a>
                                    <div class="description">${translate(
                                      "Contribute"
                                    )}</div>
                                  </div>
                                </div>
                              </div>
                            <h3 class="ui header">${translate("Donate")}</h3>
                              <p>
                              ${translate(
                                "Udeler is free and without any ads. If you appreciate that, please consider donating to the Developer."
                              )}
                              </p>
                              <br>
                              <a href="https://www.udeler.com/donate" class="ui centered donate grid">
                                <img src="assets/images/donate.png" alt="Donate"/>
                              </a>
                          </div>
                      </div>
                </div>
     </div>
`;
 
      $("body").prepend(template);
 
      if (settings.get("general.language") == "Arabic") {
        $(".ui.dashboard .content")
          .css("margin-left", "10px")
          .css("width", "80%");
      }
 
      var $languageDropdown = $(".language.dropdown .menu");
      $.getJSON("locale/meta.json", function(data) {
        $.each(data, function(key) {
          $languageDropdown.append(
            `<div class="item" data-value=${key}>${key}</div>`
          );
        });
      });
    </script>
    <script src="assets/js/app.js"></script>
  </body>
</html>

const { app, BrowserWindow, Menu, ipcMain } = require("electron");
const path = require("path");
const url = require("url");
var downloadsSaved = false;
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;
 
function createWindow() {
  // Create the browser window.
  win = new BrowserWindow({
    width: 550,
    height: 700,
    icon: __dirname + "/assets/images/build/icon.png",
    resizable: false,
    webPreferences: {
      nodeIntegration: true
    }
  });
  // and load the index.html of the app.
  win.loadURL(
    url.format({
      pathname: path.join(__dirname, "index.html"),
      protocol: "file:",
      slashes: true
    })
  );
 
  // Open the DevTools.
  // win.webContents.openDevTools();
 
  win.on("close", event => {
    if (!downloadsSaved) {
      event.preventDefault();
      win.webContents.send("saveDownloads");
    }
  });
 
  // Emitted when the window is closed.
  win.on("closed", () => {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    win = null;
  });
 
  const template = [
    {
      label: "Edit",
      submenu: [
        { role: "undo" },
        { role: "redo" },
        { type: "separator" },
        { role: "cut" },
        { role: "copy" },
        { role: "paste" },
        { role: "pasteandmatchstyle" },
        { role: "delete" },
        { role: "selectall" }
      ]
    }
  ];
 
  if (process.platform === "darwin") {
    template.unshift({
      label: app.name,
      submenu: [
        { role: "about" },
        { type: "separator" },
        { role: "services", submenu: [] },
        { type: "separator" },
        { role: "hide" },
        { role: "hideothers" },
        { role: "unhide" },
        { type: "separator" },
        { role: "quit" }
      ]
    });
 
    template[1].submenu.push(
      { type: "separator" },
      {
        label: "Speech",
        submenu: [{ role: "startspeaking" }, { role: "stopspeaking" }]
      }
    );
  }
  Menu.setApplicationMenu(Menu.buildFromTemplate(template));
}
 
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on("ready", createWindow);
 
// Quit when all windows are closed.
app.on("window-all-closed", () => {
  app.quit();
});
 
app.on("activate", () => {
  // On macOS it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (win === null) {
    createWindow();
  }
});
 
ipcMain.on("quitApp", function() {
  downloadsSaved = true;
  app.quit();
});
 
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

Ranjith

Hi, I'm Manoj a full-time Blogger, YouTuber, Affiliate Marketer, & founder of Coding Diksha. Here, I post about programming to help developers.

Leave a Reply