text:
const __ = require('./translateProvider')
const systemInfo = require('../utils/systemInfo')
const infoPlayerProvider = require('../providers/infoPlayerProvider')
const path = require('path')
const settingsProvider = require('./settingsProvider')

function mediaPlayPauseTrack(mainWindow) {
    mainWindow.webContents.sendInputEvent({ type: 'keydown', keyCode: ';' })
}

function mediaStopTrack(mainWindow) {
    mainWindow.webContents.sendInputEvent({ type: 'keydown', keyCode: ';' })
}

function mediaNextTrack(mainWindow) {
    mainWindow.webContents.sendInputEvent({ type: 'keydown', keyCode: 'j' })
}

function mediaPreviousTrack(mainWindow) {
    mainWindow.webContents.sendInputEvent({ type: 'keydown', keyCode: 'k' })
}

function mediaUpVote(mainWindow) {
    mainWindow.webContents.sendInputEvent({ type: 'keydown', keyCode: '+' })
}

function mediaDownVote(mainWindow) {
    mainWindow.webContents.sendInputEvent({ type: 'keydown', keyCode: '_' })
}

function mediaVolumeUp(mainWindow) {
    if (settingsProvider.get('settings-decibel-volume')) {
        let percent = infoPlayerProvider.getPlayerInfo().volumePercent
        infoPlayerProvider.setVolume(
            mainWindow.webContents,
            decibelToPercent(percentToDecibel(percent) + 1.5)
        )
    } else
        mainWindow.webContents.sendInputEvent({ type: 'keydown', keyCode: '=' })
}

function mediaVolumeDown(mainWindow) {
    if (settingsProvider.get('settings-decibel-volume')) {
        let percent = infoPlayerProvider.getPlayerInfo().volumePercent
        infoPlayerProvider.setVolume(
            mainWindow.webContents,
            decibelToPercent(percentToDecibel(percent) - 1.5)
        )
    } else
        mainWindow.webContents.sendInputEvent({ type: 'keydown', keyCode: '-' })
}

function mediaForwardTenSeconds(mainWindow) {
    mainWindow.webContents.sendInputEvent({ type: 'keydown', keyCode: 'l' })
}

function mediaRewindTenSeconds(mainWindow) {
    mainWindow.webContents.sendInputEvent({ type: 'keydown', keyCode: 'h' })
}

function mediaRepeat(mainWindow) {
    mainWindow.webContents.sendInputEvent({ type: 'keydown', keyCode: 'r' })
}

function mediaShuffle(mainWindow) {
    mainWindow.webContents.sendInputEvent({ type: 'keydown', keyCode: 's' })
}

function mediaChangeSeekbar(mainWindow, time) {
    infoPlayerProvider.setSeekbar(mainWindow.webContents, time)
}

function mediaChangeVolume(mainWindow, time) {
    infoPlayerProvider.setVolume(mainWindow.webContents, time)
}

async function mediaSelectQueueItem(mainWindow, index) {
    await infoPlayerProvider.setQueueItem(mainWindow.webContents, index)
}

function mediaAddToLibrary(mainWindow) {
    infoPlayerProvider.addToLibrary(mainWindow.webContents)
}

function mediaAddToPlaylist(mainWindow, index) {
    infoPlayerProvider.addToPlaylist(mainWindow.webContents, index)
}

function createThumbar(mainWindow, mediaInfo) {
    let isPaused = mediaInfo.player.isPaused
    let likeStatus = mediaInfo.player.likeStatus
    let hasId = mediaInfo.track.id

    let thumbsUp = '../assets/img/controls/thumbs-up-button-outline.png'
    let thumbsDown = '../assets/img/controls/thumbs-down-button-outline.png'
    let thumbsReverse = ''

    switch (likeStatus) {
        case 'LIKE':
            thumbsUp = '../assets/img/controls/thumbs-up-button.png'
            thumbsDown = '../assets/img/controls/thumbs-down-button-outline.png'
            thumbsReverse = 'INDIFFERENT'
            break

        case 'DISLIKE':
            thumbsUp = '../assets/img/controls/thumbs-up-button-outline.png'
            thumbsDown = '../assets/img/controls/thumbs-down-button.png'
            thumbsReverse = 'INDIFFERENT'
            break

        case 'INDIFFERENT':
            thumbsUp = '../assets/img/controls/thumbs-up-button-outline.png'
            thumbsDown = '../assets/img/controls/thumbs-down-button-outline.png'
            thumbsReverse = likeStatus === 'LIKE' ? 'DISLIKE' : 'LIKE'
            break
    }

    playOrPause = {
        tooltip: __.trans('MEDIA_CONTROL_PLAY'),
        icon: path.join(__dirname, '../assets/img/controls/play-button.png'),
        click: () => {
            mediaPlayPauseTrack(mainWindow.getBrowserView())
        },
    }

    if (isPaused === false) {
        playOrPause.tooltip = __.trans('MEDIA_CONTROL_PAUSE')
        playOrPause.icon = path.join(
            __dirname,
            '../assets/img/controls/pause-button.png'
        )
    }

    try {
        mainWindow.setThumbarButtons([
            {
                tooltip: __.trans('MEDIA_CONTROL_THUMBS_DOWN'),
                icon: path.join(__dirname, thumbsDown),
                click: () => {
                    mediaDownVote(
                        mainWindow.getBrowserView(),
                        createThumbar(mainWindow, mediaInfo)
                    )
                },
                flags: !hasId ? ['disabled'] : [],
            },
            {
                icon: path.join(__dirname, '../assets/img/null.png'),
                flags: ['disabled', 'nobackground'],
            },
            {
                tooltip: __.trans('MEDIA_CONTROL_PREVIOUS'),
                icon: path.join(
                    __dirname,
                    '../assets/img/controls/play-previous-button.png'
                ),
                click: () => {
                    mediaPreviousTrack(mainWindow.getBrowserView())
                },
                flags: !hasId ? ['disabled'] : [],
            },
            {
                tooltip: playOrPause.tooltip,
                icon: playOrPause.icon,
                click: () => {
                    mediaPlayPauseTrack(mainWindow.getBrowserView())
                },
                flags: !hasId ? ['disabled'] : [],
            },
            {
                tooltip: __.trans('MEDIA_CONTROL_NEXT'),
                icon: path.join(
                    __dirname,
                    '../assets/img/controls/play-next-button.png'
                ),
                click: () => {
                    mediaNextTrack(mainWindow.getBrowserView())
                },
                flags: !hasId ? ['disabled'] : [],
            },
            {
                icon: path.join(__dirname, '../assets/img/null.png'),
                flags: ['disabled', 'nobackground'],
            },
            {
                tooltip: __.trans('MEDIA_CONTROL_THUMBS_UP'),
                icon: path.join(__dirname, thumbsUp),
                click: () => {
                    mediaUpVote(
                        mainWindow.getBrowserView(),
                        createThumbar(mainWindow, mediaInfo)
                    )
                },
                flags: !hasId ? ['disabled'] : [],
            },
        ])
        mainWindow.setSkipTaskbar(false)
    } catch (e) {
        //console.log(e);
    }
}

function percentToDecibel(percent) {
    return Math.min(Math.max(20.0 * Math.log10(percent / 100.0), -100.0), 0.0)
}

function decibelToPercent(decibel) {
    return Math.min(
        Math.max(Math.pow(10.0, decibel / 20.0) * 100.0, 0.0),
        100.0
    )
}

function setProgress(mainWindow, progress, isPaused) {
    if (mainWindow)
        if (systemInfo.isWindows())
            mainWindow.setProgressBar(progress, {
                mode: isPaused ? 'paused' : 'normal',
            })
        else mainWindow.setProgressBar(progress)
}

function createTouchBar(mainWindow) {
    // TODO: Implement touchbar
    // mainWindow.setTouchBar();
}

const guarder = (mainWindow, f) => {
    if (mainWindow && mainWindow.webContents) f(mainWindow)
}

exports.playPauseTrack = (v) => guarder(v, mediaPlayPauseTrack)
exports.stopTrack = (v) => guarder(v, mediaStopTrack)
exports.nextTrack = (v) => guarder(v, mediaNextTrack)
exports.previousTrack = (v) => guarder(v, mediaPreviousTrack)
exports.upVote = (v) => guarder(v, mediaUpVote)
exports.downVote = (v) => guarder(v, mediaDownVote)
exports.volumeUp = (v) => guarder(v, mediaVolumeUp)
exports.volumeDown = (v) => guarder(v, mediaVolumeDown)
exports.mediaForwardTenSeconds = (v) => guarder(v, mediaForwardTenSeconds)
exports.mediaRewindTenSeconds = (v) => guarder(v, mediaRewindTenSeconds)
exports.changeSeekbar = mediaChangeSeekbar
exports.changeVolume = mediaChangeVolume
exports.selectQueueItem = mediaSelectQueueItem
exports.repeat = mediaRepeat
exports.shuffle = mediaShuffle
exports.addToLibrary = mediaAddToLibrary
exports.addToPlaylist = mediaAddToPlaylist

// For Windows
exports.createThumbar = createThumbar
exports.setProgress = setProgress
// For Mac
// exports.createTouchBar = createTouchBar;


text:
const { ipcMain } = require('electron')
const { doBehavior } = require('../utils/window')

let statusBarMenu = [
    {
        label: 'Edit',
        submenu: [
            {
                role: 'undo',
            },
            {
                role: 'redo',
            },
            {
                type: 'separator',
            },
            {
                role: 'cut',
            },
            {
                role: 'copy',
            },
            {
                role: 'paste',
            },
            {
                role: 'pasteandmatchstyle',
            },
            {
                role: 'delete',
            },
            {
                role: 'selectall',
            },
            {
                type: 'separator',
            },
            {
                label: 'Speech',
                submenu: [
                    {
                        role: 'startspeaking',
                    },
                    {
                        role: 'stopspeaking',
                    },
                ],
            },
        ],
    },
    {
        label: 'View',
        submenu: [
            {
                label: 'Reload',
                accelerator: 'CmdOrCtrl+R',
                click(item, focusedWindow) {
                    focusedWindow.emit('reload')
                    if (focusedWindow) focusedWindow.reload()
                },
            },
            {
                label: 'Toggle Developer Tools',
                accelerator:
                    process.platform === 'darwin'
                        ? 'Alt+Command+I'
                        : 'Ctrl+Shift+I',
                click(item, focusedWindow) {
                    if (focusedWindow)
                        focusedWindow.webContents.toggleDevTools()
                },
            },
            {
                type: 'separator',
            },
            {
                role: 'resetzoom',
            },
            {
                role: 'zoomin',
            },
            {
                role: 'zoomout',
            },
            {
                type: 'separator',
            },
            {
                role: 'togglefullscreen',
            },
        ],
    },
    {
        label: 'History',
        submenu: [
            {
                label: 'Home(YouTube Music)',
                accelerator: 'CmdOrCtrl+H',
                async click(item, focusedWindow) {
                    if (focusedWindow)
                        await focusedWindow
                            .getBrowserView()
                            .webContents.loadURL('https://music.youtube.com')
                },
            },
            {
                type: 'separator',
            },
            {
                label: 'Back',
                accelerator: 'CmdOrCtrl+[',
                click(item, focusedWindow) {
                    if (focusedWindow)
                        if (
                            focusedWindow
                                .getBrowserView()
                                .webContents.canGoBack()
                        )
                            focusedWindow.getBrowserView().webContents.goBack()
                },
            },
            {
                label: 'Forward',
                accelerator: 'CmdOrCtrl+]',
                click(item, focusedWindow) {
                    if (focusedWindow)
                        if (
                            focusedWindow
                                .getBrowserView()
                                .webContents.canGoForward()
                        )
                            focusedWindow
                                .getBrowserView()
                                .webContents.goForward()
                },
            },
        ],
    },
    {
        role: 'window',
        submenu: [
            {
                label: 'Close',
                accelerator: 'CmdOrCtrl+W',
                role: 'close',
            },
            {
                label: 'Minimize',
                accelerator: 'CmdOrCtrl+M',
                role: 'minimize',
            },
            {
                label: 'Zoom',
                role: 'zoom',
            },
            {
                type: 'separator',
            },
            {
                label: 'Bring All to Front',
                role: 'front',
            },
        ],
    },
    {
        role: 'help',
        submenu: [
            {
                label: 'Learn More',
                async click() {
                    await require('electron').shell.openExternal(
                        'http://electron.atom.io'
                    )
                },
            },
        ],
    },
]
statusBarMenu.unshift({
    label: 'YouTube Music Desktop',
    submenu: [
        {
            role: 'about',
        },
        {
            type: 'separator',
        },
        {
            role: 'services',
            submenu: [],
        },
        {
            type: 'separator',
        },
        {
            role: 'hide',
        },
        {
            role: 'hideothers',
        },
        {
            role: 'unhide',
        },
        {
            type: 'separator',
        },
        {
            role: 'quit',
        },
    ],
})

const popUpMenu = (__, saved_mainWindow, mediaControl, app) => {
    return [
        {
            label: 'YouTube Music Desktop',
            type: 'normal',
            click: () => {
                doBehavior(saved_mainWindow)
            },
        },

        { type: 'separator' },

        {
            label: __.trans('MEDIA_CONTROL_PLAY_PAUSE'),
            type: 'normal',
            click: () => {
                mediaControl.playPauseTrack(saved_mainWindow.getBrowserView())
            },
        },

        {
            label: __.trans('MEDIA_CONTROL_PREVIOUS'),
            type: 'normal',
            click: () => {
                mediaControl.previousTrack(saved_mainWindow.getBrowserView())
            },
        },

        {
            label: __.trans('MEDIA_CONTROL_NEXT'),
            type: 'normal',
            click: () => {
                mediaControl.nextTrack(saved_mainWindow.getBrowserView())
            },
        },

        { type: 'separator' },

        {
            label: __.trans('MEDIA_CONTROL_THUMBS_UP'),
            type: 'normal',
            click: () => {
                mediaControl.upVote(saved_mainWindow.getBrowserView())
            },
        },

        {
            label: __.trans('MEDIA_CONTROL_THUMBS_DOWN'),
            type: 'normal',
            click: () => {
                mediaControl.downVote(saved_mainWindow.getBrowserView())
            },
        },

        { type: 'separator' },

        {
            label: __.trans('LABEL_MINIPLAYER'),
            type: 'normal',
            click: () => {
                ipcMain.emit('window', { command: 'show-miniplayer' })
            },
        },

        {
            label: __.trans('LABEL_LYRICS'),
            type: 'normal',
            click: () => {
                ipcMain.emit('window', { command: 'show-lyrics' })
            },
        },

        {
            label: __.trans('LABEL_SETTINGS_TAB_GENERAL_SELECT_AUDIO_OUTPUT'),
            type: 'submenu',
            submenu: [],
        },

        {
            label: __.trans('LABEL_SETTINGS'),
            type: 'normal',
            click: () => {
                ipcMain.emit('window', { command: 'show-settings' })
            },
        },

        { type: 'separator' },

        {
            label: __.trans('LABEL_GUEST'),
            type: 'normal',
            click: () => {
                ipcMain.emit('window', { command: 'show-guest-mode' })
            },
        },

        { type: 'separator' },

        {
            label: __.trans('LABEL_EXIT'),
            type: 'normal',
            click: () => {
                app.exit()
            },
        },
    ]
}

module.exports = {
    statusBarMenu: statusBarMenu,
    popUpMenu: popUpMenu,
}

repo_name: ytmdesktop/ytmdesktop

repo_language: JavaScript

mime_type: text/plain


text:
const { ipcMain } = require('electron')
const isDev = require('electron-is-dev')
const i18n = require('i18n')
var http = require('https')
var fs = require('fs')
const settingsProvider = require('./settingsProvider')

const defaultLocale = settingsProvider.get('settings-app-language') || 'en'

// Use app.getPath('userData') will cause problem here and I could not figure out why
// So I add a stored value `settings-localses-path` as a workaround.
//                                                      - mingjun97
const localesPath = settingsProvider.get('settings-locales-path') + '/locales'

console.log(
    '[!] To add translation for your introduced feature, you may navigate to '
)
console.log('[!] ' + localesPath + ' to modify the your locale file.')
console.log('[!] Then kindly open a PR to ytmdesktop-locales repo. :)')

var updateLocaleFile = function (locale, cb, force = false) {
    // for developer, skip auto update to prevent data loss
    if (isDev && !force) {
        console.log('[!]Skip i18n auto-update in development mode')
        // updateLocaleFile(locale, cb, true)
        console.log(
            '[!]You may force update i18n by uncomment previous line in `src/providers/translateProvider`'
        )
        return
    }
    // console.log('downloading locale file for:' + locale);
    dest = `${localesPath}/${locale}.json`
    var file = fs.createWriteStream(dest)
    var request = http
        .get(
            `https://raw.githubusercontent.com/ytmdesktop/ytmdesktop-locales/master/locales/${locale}.json`,
            function (response) {
                let body = ''
                response.on('data', function (chunk) {
                    body += chunk
                })
                response.on('end', function () {
                    file.write(body)
                    file.close()
                })
            }
        )
        .on('error', function (err) {
            // Handle errors
            fs.unlink(dest) // Delete the file async. (But we don't check the result)
            if (cb) cb(err.message)
        })
}

i18n.configure({
    locales: ['en', 'pt'],
    directory: localesPath,
    defaultLocale: defaultLocale,
    autoReload: true,
})

// update locale file when launch
// put a slight delay in case of data racing
setTimeout(function () {
    updateLocaleFile(defaultLocale, (a) => {
        console.log('cb called', a)
    })
}, 1000)

function setLocale(locale) {
    i18n.setLocale(locale)
}

function trans(id, params) {
    params = typeof params !== 'undefined' ? params : {}
    try {
        let tmp = i18n.__(id, params)
        return tmp === id
            ? i18n.__({ phrase: id, locale: 'en' }, params) // fallback to english
            : tmp
    } catch (_) {
        return i18n.__({ phrase: id, locale: 'en' }, params) // fallback to english
    }
}

function translateHelper() {
    const prefix = 'i18n_'
    const items = []
    const i18n_items = document.getElementsByTagName('*')
    for (let i = 0; i < i18n_items.length; i++)
        //omitting undefined null check for brevity
        if (
            i18n_items[i].getAttribute('i18n') &&
            i18n_items[i].getAttribute('i18n').lastIndexOf(prefix, 0) === 0
        )
            items.push([
                i18n_items[i].getAttribute('i18n').replace('i18n_', ''),
                i18n_items[i],
            ])
    return items
}

function loadi18n() {
    translateHelper().forEach(([i18n, element]) => {
        element.innerHTML = trans(i18n)
    })
}

if (ipcMain) {
    ipcMain.on('I18N_TRANSLATE', (e, id, params) => {
        e.returnValue = trans(id, params)
    })
    // download locale file for new language
    ipcMain.on('language-updated', (e, id, params) => {
        updateLocaleFile(settingsProvider.get('settings-app-language'))
    })
}

module.exports = {
    setLocale: setLocale,
    trans: trans,
    loadi18n: loadi18n,
}


text:
const { autoUpdater } = require('electron-updater')
const settingsProvider = require('./settingsProvider')

function checkUpdate(mainWindow, view) {
    autoUpdater.checkForUpdates().catch((_) => console.log('Error on update'))

    autoUpdater.on('checking-for-update', () => {
        // tray.balloon( 'Auto Update', 'Checking for update...' );
        // mainWindow.send( 'downloaded-new-update', true );
    })

    autoUpdater.on('update-available', (_) => {
        // tray.balloon( 'Update Available', 'Auto Update' );
        mainWindow.send('have-new-update')
    })

    autoUpdater.on('update-not-available', (_) => {
        // tray.balloon( 'Update not available.', 'Auto Update' );
    })

    autoUpdater.on('error', (_) => {
        // tray.balloon( 'Error in auto-updater.', 'Auto Update' );
    })

    autoUpdater.on('update-downloaded', (_) => {
        // tray.balloon( 'Update downloaded', 'Auto Update' );
        view.webContents.send('downloaded-new-update', true)
        settingsProvider.set('has-updated', true)
    })
}

function quitAndInstall() {
    autoUpdater.quitAndInstall()
}

module.exports = {
    checkUpdate: checkUpdate,
    quitAndInstall: quitAndInstall,
}


text:
const { app, Menu, Tray, ipcMain } = require('electron')
const mediaControl = require('./mediaProvider')
const nativeImage = require('electron').nativeImage
const settingsProvider = require('./settingsProvider')
const __ = require('./translateProvider')
const { doBehavior } = require('../utils/window')
const systemInfo = require('../utils/systemInfo')
const imageToBase64 = require('image-to-base64')
const { popUpMenu } = require('./templateProvider')
const assetsProvider = require('./assetsProvider')
const { Notification } = require('electron')

let tray = null
let saved_mainWindow = null
let contextMenu = null
let iconTray = assetsProvider.getIcon('trayTemplate')

function setTooltip(tooltip) {
    try {
        if (tray) tray.setToolTip(tooltip)
    } catch (error) {
        ipcMain.emit('log', {
            type: 'warn',
            data: `Failed to setTooltip: ${error}`,
        })
    }
}

let initVanillaTray = () => {
    try {
        setTooltip('YouTube Music Desktop App')
        tray.removeAllListeners()
        tray.setContextMenu(contextMenu)
        nativeImageIcon = buildTrayIcon(iconTray)
        tray.setImage(nativeImageIcon)
        tray.addListener('click', () => {
            doBehavior(saved_mainWindow)
        })

        tray.addListener('balloon-click', function () {
            doBehavior(saved_mainWindow)
        })
    } catch (error) {
        ipcMain.emit('log', {
            type: 'warn',
            data: `Failed to initVanillaTray: ${error}`,
        })
    }
}

function createTray(mainWindow) {
    if (settingsProvider.get('settings-tray-icon')) {
        nativeImageIcon = buildTrayIcon(iconTray)
        tray = new Tray(nativeImageIcon)

        if (mainWindow) {
            saved_mainWindow = mainWindow

            contextMenu = Menu.buildFromTemplate(
                popUpMenu(__, saved_mainWindow, mediaControl, app)
            )
        }

        if (!systemInfo.isMac()) initVanillaTray()
        else setShinyTray()
    }
}

function updateTray(data) {
    try {
        if (tray) {
            const template = popUpMenu(__, saved_mainWindow, mediaControl, app)

            if (data.type === 'audioOutputs') template[11].submenu = data.data

            contextMenu = Menu.buildFromTemplate(template)

            if (!settingsProvider.get('settings-shiny-tray'))
                tray.setContextMenu(contextMenu)
        }
    } catch (error) {
        ipcMain.emit('log', {
            type: 'warn',
            data: `Failed to updateTray: ${error}`,
        })
    }
}

function updateTrayIcon(icon) {
    try {
        if (tray) {
            nativeImageIcon = buildTrayIcon(icon)
            tray.setImage(nativeImageIcon)
        }
    } catch (error) {
        ipcMain.emit('log', {
            type: 'warn',
            data: `Failed to updateTrayIcon: ${error}`,
        })
    }
}

function buildTrayIcon(icon) {
    return nativeImage.createFromPath(icon)
}

function balloon(title, content, cover, icon) {
    if (title && content && cover) {
        imageToBase64(cover)
            .then((response) => {
                _doNotification(
                    title,
                    content,
                    nativeImage.createFromDataURL(
                        `data:image/jpeg;base64,${response}`
                    )
                )
            })
            .catch((_) => {
                _doNotification(
                    title,
                    content,
                    nativeImage.createFromPath(icon)
                )
            })
    }
}

function balloonEvents(data) {
    _doNotification(data.title, data.content, data.icon)
}

function _doNotification(title, content, icon) {
    try {
        if (title && content) {
            if (systemInfo.isWindows()) {
                if (!settingsProvider.get('settings-tray-icon')) {
                    nativeImageIcon = buildTrayIcon(iconTray)
                    tray = new Tray(nativeImageIcon)
                }
                tray.displayBalloon({
                    icon: icon,
                    title: title,
                    content: content,
                    noSound: true,
                })
                if (!settingsProvider.get('settings-tray-icon'))
                    setTimeout(() => {
                        quit()
                    }, 7 * 1000)
            }
            // create a system notification and send it
            else
                new Notification({
                    title: title,
                    body: content,
                    silent: true,
                    icon: icon,
                    urgency: 'low',
                }).show()
        }
    } catch (error) {
        ipcMain.emit('log', {
            type: 'warn',
            data: `Failed to _doNotification: ${error}`,
        })
    }
}

function quit() {
    tray.destroy()
}

function setShinyTray() {
    try {
        if (systemInfo.isMac() && settingsProvider.get('settings-shiny-tray')) {
            tray.setContextMenu(null)
            tray.removeAllListeners()
            tray.on('right-click', () => {
                tray.popUpContextMenu(contextMenu)
            })
            tray.on('click', (event, bound, position) => {
                if (position.x < 32) {
                    // click at icon
                    if (!saved_mainWindow.isVisible()) {
                        saved_mainWindow.show()
                    } else if (!saved_mainWindow.isFocused()) {
                        saved_mainWindow.show()
                    } else saved_mainWindow.hide()
                } else if (position.x > 130)
                    // click play/pause button
                    mediaControl.playPauseTrack(
                        saved_mainWindow.getBrowserView()
                    )
            })
        } else {
            // Shiny tray disabled ||| on onther platform
            tray.removeAllListeners()
            initVanillaTray()
            console.log('initVanillaTray')
        }
    } catch (error) {
        ipcMain.emit('log', {
            type: 'warn',
            data: `Failed to setShinyTray: ${error}`,
        })
    }
}

function updateImage(payload) {
    try {
        if (!settingsProvider.get('settings-shiny-tray') || !tray) return
        const img =
            typeof nativeImage.createFromDataURL === 'function'
                ? nativeImage.createFromDataURL(payload) // electron v0.36+
                : nativeImage.createFromDataUrl(payload) // electron v0.30
        tray.setImage(img)
    } catch (error) {
        ipcMain.emit('log', {
            type: 'warn',
            data: `Failed to updateImage: ${error}`,
        })
    }
}

module.exports = {
    setTooltip: setTooltip,
    createTray: createTray,
    updateTray: updateTray,
    balloon: balloon,
    balloonEvents: balloonEvents,
    quit: quit,
    setShinyTray: setShinyTray,
    updateImage: updateImage,
    updateTrayIcon: updateTrayIcon,
}


text:
const {
    MediaPlaybackStatus,
    MediaPlaybackType,
    SystemMediaTransportControlsButton,
} = require('@nodert-win10-rs4/windows.media')
const { BackgroundMediaPlayer } = require('windows.media.playback')
const {
    RandomAccessStreamReference,
} = require('@nodert-win10-rs4/windows.storage.streams')
const { Uri } = require('@nodert-win10-rs4/windows.foundation')

const mediaControl = require('../providers/mediaProvider')
const settingsProvider = require('./settingsProvider')

class windowsMediaProvider {
    constructor() {
        this._view = null
        this._isInitialized = false
        this._controls =
            BackgroundMediaPlayer.current.systemMediaTransportControls

        if (!settingsProvider.get('settings-windows10-media-service-show-info'))
            this._controls.isEnabled = false

        this._controls.isChannelDownEnabled = false
        this._controls.isChannelUpEnabled = false
        this._controls.isFastForwardEnabled = false
        this._controls.isRecordEnabled = false
        this._controls.isRewindEnabled = false
        this._controls.isNextEnabled = true
        this._controls.isPauseEnabled = true
        this._controls.isPlayEnabled = true
        this._controls.isPreviousEnabled = true

        this._controls.playbackStatus = MediaPlaybackStatus.closed
        this._controls.displayUpdater.type = MediaPlaybackType.music

        this._controls.displayUpdater.musicProperties.title = 'YouTube Music'
        this._controls.displayUpdater.musicProperties.artist = ''
        this._controls.displayUpdater.thumbnail = RandomAccessStreamReference.createFromUri(
            new Uri('https://avatars1.githubusercontent.com/u/48072485?s=500')
        )

        this._controls.displayUpdater.update()

        this._controls.on('buttonpressed', (sender, eventArgs) => {
            switch (eventArgs.button) {
                case SystemMediaTransportControlsButton.play:
                    mediaControl.playPauseTrack(this._view)
                    break
                case SystemMediaTransportControlsButton.pause:
                    mediaControl.playPauseTrack(this._view)
                    break
                case SystemMediaTransportControlsButton.next:
                    mediaControl.nextTrack(this._view)
                    break
                case SystemMediaTransportControlsButton.previous:
                    mediaControl.previousTrack(this._view)
                    break
                default:
                    break
            }
        })
    }

    init(view) {
        this._view = view
        this._isInitialized = true
    }

    setPlaybackStatus(status) {
        if (this._isInitialized) {
            if (status)
                this._controls.playbackStatus = MediaPlaybackStatus.paused
            else this._controls.playbackStatus = MediaPlaybackStatus.playing

            this._controls.displayUpdater.update()
        }
    }

    setPlaybackData(title, author, cover, album) {
        if (this._isInitialized) {
            this._controls.displayUpdater.musicProperties.title = title
            this._controls.displayUpdater.musicProperties.artist = author
            this._controls.displayUpdater.thumbnail = RandomAccessStreamReference.createFromUri(
                new Uri(cover)
            )
            this._controls.displayUpdater.musicProperties.albumTitle = album
            this._controls.displayUpdater.update()
        }
    }
}

module.exports = new windowsMediaProvider()


text:
const { app } = require('electron')
const Analytics = require('electron-google-analytics')
const analytics = new Analytics.default('UA-127400126-1')
const { v4: uuid } = require('uuid')
const settingsProvider = require('./settingsProvider')
let userId = settingsProvider.get('uuid')

if (userId === undefined) {
    userId = uuid()
    settingsProvider.set('uuid', userId)
}

function setAnalyticsEvent(from, action, label, value) {
    analytics
        .event(action, from, {
            evLabel: label,
            evValue: value,
            clientID: userId,
        })
        .then()
        .catch((_) => {
            console.log('error setAnalyticsEvent')
        })
}

function setAnalyticsScreen(from) {
    analytics
        .screen(
            'YouTube Music Desktop App',
            app.getVersion(),
            'app.ytmd',
            'app.ytmd',
            from,
            userId
        )
        .then()
        .catch((_) => {
            console.log('error setAnalyticsScreen')
        })
}

module.exports = {
    setEvent: setAnalyticsEvent,
    setScreen: setAnalyticsScreen,
}


text:
const { ipcMain, app } = require('electron')
const http = require('http')
const os = require('os')
const networkInterfaces = os.networkInterfaces()
const qrcode = require('qrcode-generator')
const infoPlayerProvider = require('../providers/infoPlayerProvider')
const settingsProvider = require('../providers/settingsProvider')

const ip = '0.0.0.0'
const port = 9863
const hostname = os.hostname()

const pattIgnoreInterface = /(Loopback|lo$|virtual|wsl|vEthernet|Default Switch|VMware|Adapter|Hamachi)\w*/gim

let totalConnections = 0
let timerTotalConections
let serverInterfaces = []

function infoApp() {
    return {
        version: app.getVersion(),
    }
}
function infoServer() {
    return {
        name: hostname,
        listen: serverInterfaces,
        port: port,
        isProtected:
            settingsProvider.get('settings-companion-server-protect') || false,
        connections: totalConnections,
    }
}

function fetchNetworkInterfaces() {
    serverInterfaces = Object.entries(networkInterfaces)
        .filter(([interfaces]) => !pattIgnoreInterface.test(interfaces))
        .map(([name, value]) => {
            value = value.filter((data) => {
                return data.family === 'IPv4' && data.internal === false
            })
            return {
                name: name,
                ip: value.length ? value[0].address : '',
                isProtected: infoServer().isProtected,
            }
        })
}

const serverFunction = (req, res) => {
    if (req.url === '/') {
        let collection = ''
        let isProtected = infoServer().isProtected

        serverInterfaces.forEach((value) => {
            let qr = qrcode(0, 'H')
            value.hostname = hostname
            qr.addData(JSON.stringify(value))
            qr.make()

            // TODO: This is quite messy
            collection += `

${value.name}

${
                                                      value.ip
                                                  }

`
        })

        res.setHeader('Content-Type', 'text/html; charset=utf-8')
        res.setHeader('Access-Control-Allow-Origin', '*')
        res.writeHead(200)

        res.write(`

              <title>YTMDesktop Remote Control</title>
              <meta http-equiv="refresh" content="60">
              <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
              <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
              <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">

YTMDesktop Remote Control

${
                              infoPlayerProvider.getTrackInfo().title
                          }

                          ${infoPlayerProvider.getTrackInfo().author}

                  ${collection}

                ${
            isProtected ? 'lock' : 'lock_open'
        }

                  ${hostname}
                  devices_other${totalConnections}

      `)

        res.end()
    } else {
        res.setHeader('Content-Type', 'text/json; charset=utf-8')
        res.setHeader('Access-Control-Allow-Origin', '*')
    }

    if (req.url === '/query') {
        if (req.method === 'GET') {
            let data = {
                player: infoPlayerProvider.getPlayerInfo(),
                track: infoPlayerProvider.getTrackInfo(),
                /*queue: infoPlayerProvider.getQueueInfo(),
                playlist: infoPlayerProvider.getPlaylistInfo(),
                lyrics: infoPlayerProvider.getLyricsInfo(),*/
            }
            res.write(JSON.stringify(data))
            res.end()
        }

        if (req.method === 'POST') {
            let body = []

            req.on('data', (chunk) => {
                body.push(chunk)
            }).on('end', () => {
                try {
                    body = Buffer.concat(body).toString()
                    let { command, value } = JSON.parse(body)

                    if (
                        settingsProvider.get(
                            'settings-companion-server-protect'
                        )
                    ) {
                        try {
                            let headerAuth = req.headers.authorization
                            let authToken = headerAuth
                                .split(' ')[1]
                                .toUpperCase()

                            if (
                                authToken ===
                                settingsProvider.get(
                                    'settings-companion-server-token'
                                )
                            )
                                execCmd(command, value)
                            else {
                                res.writeHead(401)
                                res.end(
                                    JSON.stringify({ error: 'Unathorized' })
                                )
                            }
                        } catch (_) {
                            res.writeHead(400)
                            res.end(
                                JSON.stringify({ error: 'No token provided' })
                            )
                        }
                    } else execCmd(command, value)

                    res.end(body)
                } catch (_) {
                    res.end(
                        JSON.stringify({
                            error: 'error to execute command',
                        })
                    )
                }
            })
        }
    }

    if (req.url === '/query/player')
        if (req.method === 'GET') {
            res.write(JSON.stringify(infoPlayerProvider.getPlayerInfo()))
            res.end()
        }

    if (req.url === '/query/track')
        if (req.method === 'GET') {
            res.write(JSON.stringify(infoPlayerProvider.getTrackInfo()))
            res.end()
        }

    if (req.url === '/query/queue')
        if (req.method === 'GET') {
            res.write(JSON.stringify(infoPlayerProvider.getQueueInfo()))
            res.end()
        }

    if (req.url === '/query/playlist')
        if (req.method === 'GET') {
            res.write(JSON.stringify(infoPlayerProvider.getPlaylistInfo()))
            res.end()
        }

    if (req.url === '/query/lyrics')
        if (req.method === 'GET') {
            res.write(JSON.stringify(infoPlayerProvider.getLyricsInfo()))
            res.end()
        }

    if (req.url === '/info')
        if (req.method === 'GET') {
            const result = {
                app: infoApp(),
                server: infoServer(),
            }
            res.write(JSON.stringify(result))
            res.end()
        }
}

const server = http.createServer(serverFunction)

function canConnect(socket) {
    let clientPassword = socket.handshake.headers.password || ''
    let clientHost = socket.handshake.address
    let clientIsLocalhost = clientHost === '127.0.0.1'

    let serverPassword = settingsProvider.get('settings-companion-server-token')

    return !(
        infoServer().isProtected &&
        clientIsLocalhost === false &&
        clientPassword !== serverPassword
    )
}

function start() {
    try {
        server.listen(port, ip)
        const io = require('socket.io')(server)

        timerTotalConections = setInterval(() => {
            totalConnections = Object.keys(io.sockets.sockets).length

            if (totalConnections)
                io.emit('tick', infoPlayerProvider.getAllInfo())
        }, 500)

        io.on('connection', (socket) => {
            if (!canConnect(socket)) socket.disconnect()

            socket.on('media-commands', (cmd, value) => execCmd(cmd, value))

            socket.on('retrieve-info', () =>
                socket.emit('info', { app: infoApp(), server: infoServer() })
            )

            socket.on('query-player', () =>
                socket.emit('player', infoPlayerProvider.getPlayerInfo())
            )

            socket.on('query-track', () =>
                socket.emit('track', infoPlayerProvider.getTrackInfo())
            )

            socket.on('query-queue', () =>
                socket.emit('queue', infoPlayerProvider.getQueueInfo())
            )

            socket.on('query-playlist', () =>
                socket.emit('playlist', infoPlayerProvider.getPlaylistInfo())
            )

            socket.on('query-lyrics', () =>
                socket.emit('lyrics', infoPlayerProvider.getLyricsInfo())
            )
        })

        fetchNetworkInterfaces()

        ipcMain.emit('log', {
            type: 'info',
            data: `Companion Server listening on port ${port}`,
        })
    } catch (_) {
        ipcMain.emit('log', {
            type: 'warn',
            data: `Error to start server on port ${port}`,
        })
    }
}

function stop() {
    clearInterval(timerTotalConections)
    server.close()
    console.log('Companion Server has stopped')
}

function execCmd(cmd, value) {
    value = value || true

    switch (cmd) {
        case 'track-play-pause':
            ipcMain.emit('media-command', {
                command: 'media-play-pause',
                value: true,
            })
            break

        case 'track-play':
            if (infoPlayerProvider.getPlayerInfo().isPaused) {
                ipcMain.emit('media-command', {
                    command: 'media-play-pause',
                    value: true,
                })
            }
            break

        case 'track-pause':
            if (!infoPlayerProvider.getPlayerInfo().isPaused) {
                ipcMain.emit('media-command', {
                    command: 'media-play-pause',
                    value: true,
                })
            }
            break

        case 'track-next':
            ipcMain.emit('media-command', {
                command: 'media-track-next',
                value: true,
            })
            break

        case 'track-previous':
            ipcMain.emit('media-command', {
                command: 'media-track-previous',
                value: true,
            })
            break

        case 'track-thumbs-up':
            ipcMain.emit('media-command', {
                command: 'media-vote-up',
                value: true,
            })
            break

        case 'track-thumbs-down':
            ipcMain.emit('media-command', {
                command: 'media-vote-down',
                value: true,
            })
            break

        case 'player-volume-up':
            ipcMain.emit('media-command', {
                command: 'media-volume-up',
                value: true,
            })
            break

        case 'player-volume-down':
            ipcMain.emit('media-command', {
                command: 'media-volume-down',
                value: true,
            })
            break

        case 'player-forward':
            ipcMain.emit('media-command', {
                command: 'media-seekbar-forward',
                value: true,
            })
            break

        case 'player-rewind':
            ipcMain.emit('media-command', {
                command: 'media-seekbar-rewind',
                value: true,
            })
            break

        case 'player-set-seekbar':
            ipcMain.emit('media-command', {
                command: 'media-seekbar-set',
                value: value,
            })
            break

        case 'player-set-volume':
            ipcMain.emit('media-command', {
                command: 'media-volume-set',
                value: value,
            })
            break

        case 'player-set-queue':
            ipcMain.emit('media-command', {
                command: 'media-queue-set',
                value: value,
            })
            break

        case 'player-repeat':
            ipcMain.emit('media-command', {
                command: 'media-repeat',
                value: true,
            })
            break

        case 'player-shuffle':
            ipcMain.emit('media-command', {
                command: 'media-shuffle',
                value: true,
            })
            break

        case 'player-add-library':
            ipcMain.emit('media-command', {
                command: 'media-add-library',
                value: true,
            })
            break

        case 'player-add-playlist':
            ipcMain.emit('media-command', {
                command: 'media-add-playlist',
                value: value,
            })
            break

        case 'show-lyrics-hidden':
            ipcMain.emit('window', { command: 'show-lyrics-hidden' })
            break
    }
}

module.exports = {
    start: start,
    stop: stop,
}


text:
const settingsProvider = require('./settingsProvider')

let webContents, initialized

const player = {
    hasSong: false,
    isPaused: true,
    volumePercent: 0,
    seekbarCurrentPosition: 0,
    seekbarCurrentPositionHuman: '0:00',
    statePercent: 0.0,
    likeStatus: 'INDIFFERENT',
    repeatType: 'NONE',
}

const track = {
    author: '',
    title: '',
    album: '',
    cover: '',
    duration: 0,
    durationHuman: '0:00',
    url: '',
    id: '',
    isVideo: false,
    isAdvertisement: false,
    inLibrary: false,
}

let _queue = {
    automix: false,
    currentIndex: 0,
    list: [],
}

let _playlist = {
    list: [],
}

const _lyrics = {
    provider: '',
    data: '',
    hasLoaded: false,
}

function init(view) {
    webContents = view.webContents
    initialized = true
    toggleMoreActions(webContents)
    toggleMoreActions(webContents)

    initVolume()
}

function initVolume() {
    setVolume(webContents, settingsProvider.get('settings-volume'))
}

function getAllInfo() {
    return {
        player: getPlayerInfo(),
        track: getTrackInfo(),
    }
}

function getPlayerInfo() {
    if (webContents === undefined) return player

    hasSong()
    isPaused(webContents)
    getVolume(webContents)
    getSeekbarPosition(webContents)
    getLikeStatus(webContents)
    getRepeatType(webContents)
    return player
}

function getTrackInfo() {
    if (webContents === undefined) return track

    getAuthor(webContents)
    getTitle(webContents)
    getAlbum(webContents)
    getCover(webContents)
    getDuration(webContents)
    getUrl(webContents)
    setPercent(player.seekbarCurrentPosition, track.duration)
    isVideo(webContents)
    isAdvertisement(webContents)
    return track
}

function getQueueInfo() {
    return _queue
}

function updateQueueInfo() {
    if (webContents !== undefined) getQueue(webContents)
}

function getPlaylistInfo() {
    return _playlist
}

function updatePlaylistInfo() {
    if (webContents !== undefined) getPlaylist(webContents)
}

function getLyricsInfo() {
    return _lyrics
}

function hasSong() {
    player.hasSong = track.id !== ''
}

function isPaused(webContents) {
    webContents
        .executeJavaScript(`document.querySelector('video').paused;`)
        .then((isPaused) => {
            debug(`Is paused: ${isPaused}`)
            player.isPaused = isPaused
        })
        .catch((_) => console.log('error isPaused'))
}

function getTitle(webContents) {
    webContents
        .executeJavaScript(
            `document.querySelector('.title.ytmusic-player-bar').textContent;`
        )
        .then((title) => {
            debug(`Title is: ${title}`)
            track.title = title
        })
        .catch((_) => console.log('error getTitle'))
}

function getDuration(webContents) {
    webContents
        .executeJavaScript(
            `document.querySelector('#progress-bar').getAttribute('aria-valuemax');`
        )
        .then((duration) => {
            debug(`Duration is: ${parseInt(duration)}`)
            track.duration = parseInt(duration)
            track.durationHuman = convertToHuman(parseInt(duration))
        })
        .catch((_) => console.log('error getDuration'))
}

/**
 * Get Like status
 * LIKE | DISLIKE | INDIFFERENT
 * @param {*} webContents
 */
function getLikeStatus(webContents) {
    webContents
        .executeJavaScript(
            `document.querySelector('#like-button-renderer').getAttribute('like-status');`
        )
        .then((likeStatus) => {
            debug(`Like status is: ${likeStatus}`)
            player.likeStatus = likeStatus
        })
        .catch((_) => console.log('error getLikeStatus'))
}

/**
 * GET CURRENT SEEK BAR POSITION
 * @param {*} webContents
 */
function getSeekbarPosition(webContents) {
    webContents
        .executeJavaScript(
            `document.querySelector('#progress-bar').getAttribute('aria-valuenow');`
        )
        .then((position) => {
            debug(`Seekbar position is: ${parseInt(position)}`)
            player.seekbarCurrentPosition = parseInt(position)
            player.seekbarCurrentPositionHuman = convertToHuman(
                parseInt(position)
            )
        })
        .catch((_) => console.log('error getSeekbarPosition'))
}

function getVolume(webContents) {
    webContents
        .executeJavaScript(
            `document.querySelector('.volume-slider.ytmusic-player-bar').getAttribute('value');`
        )
        .then((volume) => {
            debug(`Volume % is: ${parseFloat(volume)}`)
            player.volumePercent = parseFloat(volume)
        })
        .catch((_) => console.log('error getVolume'))
}

function getAuthor(webContents) {
    webContents
        .executeJavaScript(
            `
            var bar = document.getElementsByClassName('subtitle ytmusic-player-bar')[0];

            if (bar.getElementsByClassName('yt-simple-endpoint yt-formatted-string')[0]) {
            title = bar.getElementsByClassName('yt-simple-endpoint yt-formatted-string')[0].textContent;
            } else if (bar.getElementsByClassName('byline ytmusic-player-bar')[0]) {
            title = bar.getElementsByClassName('byline ytmusic-player-bar')[0].textContent;
            }
            title;
            `
        )
        .then((author) => {
            debug(`Author is: ${author}`)
            track.author = author
        })
        .catch((_) => console.log('error getAuthor'))
}

function getAlbum(webContents) {
    webContents
        .executeJavaScript(
            `
            var album = '';
            var player_bar = document.getElementsByClassName("byline ytmusic-player-bar")[0].children;
            var arr_player_bar = Array.from(player_bar);

            arr_player_bar.forEach( function(data, index) {

            if (data.getAttribute('href') != null && data.getAttribute('href').includes('browse')) {
                album = data.innerText;
            }
            } )

            album
            `
        )
        .then((album) => {
            debug(`Album is: ${album}`)
            track.album = album
        })
        .catch((_) => console.log('error getAlbum'))
}

function getCover(webContents) {
    webContents
        .executeJavaScript(
            `
            var cover;

            var thumbnail = document.querySelector('.thumbnail.ytmusic-player.no-transition');
            var image = thumbnail.querySelector('.yt-img-shadow').src;

            cover = image;

            if (cover.includes("data:image")) {
                cover = document.querySelector(".image.ytmusic-player-bar").src;
            }

            cover;
            `
        )
        .then((cover) => {
            debug(`Cover is: ${cover}`)
            cover.split('?')[0]
            cover.replace('sddefault.jpg', 'hq720.jpg')

            track.cover = cover
        })
        .catch((_) => console.log('error getCover'))
}

function getRepeatType(webContents) {
    webContents
        .executeJavaScript(
            `document.querySelector("ytmusic-player-bar").getAttribute("repeat-mode_");`
        )
        .then((repeatType) => {
            debug(`Repeat type is: ${repeatType}`)
            player.repeatType = repeatType
        })
        .catch((_) => console.log('error getRepeatType'))
}

function getUrl(webContents) {
    webContents
        .executeJavaScript(
            `document.querySelector('.ytp-title-link.yt-uix-sessionlink').href`
        )
        .then((url) => {
            if (url) {
                track.url = url

                const newUrl = new URL(url)
                const searchParams = new URLSearchParams(newUrl.search)

                track.id = searchParams.get('v')
                debug(`Track Url: ${track.url}`)
                debug(`Track id: ${track.id}`)
            }
        })
        .catch((_) => console.log('error getUrl'))
}

function getQueue(webContents) {
    webContents
        .executeJavaScript(
            `
            var element = document.querySelector('ytmusic-player-queue #contents')
            var children = element.children

            var arrChildren = Array.from(children)

            var queue = { automix: false, currentIndex: 0, list: [] };

            arrChildren.forEach( (el, key) => {
                var songElement = el.querySelector('.song-info')

                var songCover = songElement.parentElement.querySelector('.yt-img-shadow').getAttribute('src')
                var songTitle = songElement.querySelector('.song-title').getAttribute('title')
                var songAuthor = songElement.querySelector('.byline').getAttribute('title')
                var duration = el.querySelector('.duration').getAttribute('title')

                if(el.hasAttribute('selected')) {
                    queue.currentIndex = key;
                }
                text = { cover: songCover, title: songTitle, author: songAuthor, duration: duration }
                queue.list.push(text)
            } )

            queue.automix = document.querySelector('#automix').getAttribute('aria-pressed') == 'true'
            queue
            `
        )
        .then((queue) => {
            if (queue) {
                _queue = queue
                debug(`Player Queue: ${_queue}`)
            }
        })
        .catch((_) => console.log('error getQueue'))
}

async function setQueueItem(webContents, index) {
    await webContents.executeJavaScript(
        `var element = document.querySelector('ytmusic-player-queue #contents').children[${index}].querySelector('.song-info').parentElement.querySelector('.left-items .thumbnail-overlay #play-button').click()`
    )
}

function addToLibrary(webContents) {
    webContents
        .executeJavaScript(
            `
            var popup = document.querySelector('.ytmusic-menu-popup-renderer');
            if (popup == null) {
                var middleControlsButtons = document.querySelector('.middle-controls-buttons');
                var dots = middleControlsButtons.querySelector('.dropdown-trigger')

                dots.click()
                dots.click()
            }

            setTimeout( ()=> {
                var addLibrary = Array.from(popup.children).filter( (value) => value.querySelector('g path:not([fill])').getAttribute('d') == "M20 2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7.53 12L9 10.5l1.4-1.41 2.07 2.08L17.6 6 19 7.41 12.47 14zM4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6z" || value.querySelector('g path:not([fill])').getAttribute('d') == "M4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm16-4H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-1 9h-4v4h-2v-4H9V9h4V5h2v4h4v2z" )[0]
                addLibrary.click()
            }, 100)
            `
        )
        .then(() => setTimeout(isInLibrary, 500))
        .catch((_) => console.log('error addToLibrary ' + _))
}

function getPlaylist(webContents) {
    webContents
        .executeJavaScript(
            `
            var data = { list: [] };

            new Promise( (resolve, reject) => {
                var middleControlsButtons = document.querySelector('.middle-controls-buttons');
                var dots = middleControlsButtons.querySelector('.dropdown-trigger')

                dots.click()
                dots.click()

                setTimeout( resolve, 500)
            } )
            .then((_) => {
                return new Promise( (resolve, reject) => {
                    var popup = document.querySelector('.ytmusic-menu-popup-renderer');
                    var addPlaylist = Array.from(popup.children)
                        .filter( (value) => value.querySelector('g path:not([fill])').getAttribute('d') == "M14 10H2v2h12v-2zm0-4H2v2h12V6zm4 8v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zM2 16h8v-2H2v2z" )[0].querySelector('a')
                    addPlaylist.click()
                    addPlaylist.click()

                    setTimeout( resolve, 3000);
                } ).then( (_) => {
                    var popupPlaylist = document.querySelector('ytmusic-add-to-playlist-renderer');
                    var playlists = popupPlaylist.querySelector('#playlists')

                    var titleList = playlists.querySelectorAll('#title')

                    titleList.forEach( (element, index) => {
                        data.list.push(element.textContent)
                    } )
                    return data;
                })
            })
            `
        )
        .then((playlist) => {
            _playlist = playlist
            debug(`getPlaylist: ${playlist}`)
        })
        .catch((_) => console.log('error getPlaylist ' + _))
}

function isVideo(webContents) {
    webContents
        .executeJavaScript(
            `document.querySelector('#player').hasAttribute('video-mode_')`
        )
        .then((isVideo) => {
            track.isVideo = !!isVideo
            debug(`Is video: ${track.isVideo}`)
        })
        .catch((_) => console.log('error isVideo ' + _))
}

function isAdvertisement(webContents) {
    webContents
        .executeJavaScript(
            `document.querySelector('.advertisement').hasAttribute('hidden')`
        )
        .then((isAdvertisement) => {
            track.isAdvertisement = !isAdvertisement
            debug(`Is advertisement: ${track.isAdvertisement}`)
        })
        .catch((_) => console.log('error isAdvertisement'))
}

function setVolume(webContents, vol) {
    webContents
        .executeJavaScript(
            `
        var slider = document.querySelector('#volume-slider');
        slider.value = ${vol};
        slider.dispatchEvent(new Event("change"));
        `
        )
        .then()
        .catch((_) => console.log('error changeVolume'))
}

function setSeekbar(webContents, time) {
    webContents
        .executeJavaScript(
            `
        var slider = document.querySelectorAll('.bar-container .tp-yt-paper-slider')[2];
        var sliderKnob = document.querySelectorAll('#progress-bar')[0];

        slider.click();

        sliderKnob.value = ${time};
        `
        )
        .then()
        .catch((_) => console.log('error changeSeekbar'))
}

function updateLyrics(provider, lyrics, hasLoaded) {
    _lyrics.provider = provider
    _lyrics.data = lyrics
    _lyrics.hasLoaded = hasLoaded
}

function isInLibrary() {
    webContents
        .executeJavaScript(
            `
            new Promise( (resolve, reject) => {
                var middleControlsButtons = document.querySelector('.middle-controls-buttons');
                var dots = middleControlsButtons.querySelector('.dropdown-trigger')

                dots.click()
                dots.click()

                setTimeout( resolve, 500)
            } )
            .then((_) => {
                var popup = document.querySelector('.ytmusic-menu-popup-renderer');
                var addLibrary = Array.from(popup.children)
                    .filter( (value) => value.querySelector('g path:not([fill])').getAttribute('d') == "M20 2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7.53 12L9 10.5l1.4-1.41 2.07 2.08L17.6 6 19 7.41 12.47 14zM4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6z" || value.querySelector('g path:not([fill])').getAttribute('d') == "M4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm16-4H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-1 9h-4v4h-2v-4H9V9h4V5h2v4h4v2z" )[0]

                if(addLibrary != undefined) {
                    var _d = addLibrary.querySelector('g path:not([fill])').getAttribute('d')

                    if(_d == 'M20 2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7.53 12L9 10.5l1.4-1.41 2.07 2.08L17.6 6 19 7.41 12.47 14zM4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6z') {
                        return true;
                    } else {
                        return false;
                    }
                } else {
                    return false;
                }
            })
            `
        )
        .then((inLibrary) => {
            track.inLibrary = inLibrary
            debug(`Is in Library: ${track.inLibrary}`)
        })
        .catch((_) => console.log('error isInLibrary'))
}

function addToPlaylist(webContents, index) {
    webContents
        .executeJavaScript(
            `
            new Promise( (resolve, reject) => {
                var popup = document.querySelector('.ytmusic-menu-popup-renderer');
                var addPlaylist = Array.from(popup.children)
                    .filter( (value) => value.querySelector('g path:not([fill])').getAttribute('d') == "M14 10H2v2h12v-2zm0-4H2v2h12V6zm4 8v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zM2 16h8v-2H2v2z" )[0].querySelector('a')
                addPlaylist.click()
                addPlaylist.click()

                setTimeout( resolve, 500);
            } ).then( (_) => {
                var popupPlaylist = document.querySelector('ytmusic-add-to-playlist-renderer');
                var playlists = popupPlaylist.querySelectorAll('#playlists ytmusic-playlist-add-to-option-renderer button');

                playlists[${index}].click()
            })
            `
        )
        .then()
        .catch((_) => console.log('error getPlaylist ' + _))
}

function convertToHuman(time) {
    let hours = Math.floor(time / 3600)
    time %= 3600
    let minutes = Math.floor(time / 60)
    let seconds = Math.floor(time % 60)

    let final =
        hours.toString().padStart(2, '0') +
        ':' +
        minutes.toString().padStart(2, '0') +
        ':' +
        seconds.toString().padStart(2, '0')

    final.startsWith('00:0')
        ? (final = final.slice(4))
        : final.startsWith('00:')
        ? (final = final.slice(3))
        : final.startsWith('0')
        ? (final = final.slice(1))
        : null

    return final
}

function setPercent(px, ptotal) {
    player.statePercent = px / ptotal
}

function hasInitialized() {
    return initialized
}

function firstPlay(webContents) {
    webContents
        .executeJavaScript(
            `
            var playButton = document.querySelector('.icon.ytmusic-play-button-renderer');
            playButton.click();
            `
        )
        .then()
        .catch((_) => console.log('error firstPlay'))
}

async function toggleMoreActions(webContents) {
    await webContents.executeJavaScript(
        `
            var middleControlsButtons = document.querySelector('.middle-controls-buttons');
            var moreActions = middleControlsButtons.querySelector('.dropdown-trigger')

            moreActions.click()
            `,
        true
    )
}

function debug(data) {
    // console.log(data);
}

module.exports = {
    init: init,
    getAllInfo: getAllInfo,
    getPlayerInfo: getPlayerInfo,
    getTrackInfo: getTrackInfo,
    hasInitialized: hasInitialized,
    firstPlay: firstPlay,
    isInLibrary: isInLibrary,

    getQueueInfo: getQueueInfo,
    getPlaylistInfo: getPlaylistInfo,
    getLyricsInfo: getLyricsInfo,

    setVolume: setVolume,
    setSeekbar: setSeekbar,
    setQueueItem: setQueueItem,

    updatePlaylistInfo: updatePlaylistInfo,
    updateQueueInfo: updateQueueInfo,
    updateLyrics: updateLyrics,

    addToLibrary: addToLibrary,
    addToPlaylist: addToPlaylist,
}


text:
const clientId = '495666957501071390'
const RPC = require('discord-rpc')
const settingsProvider = require('./settingsProvider')

let client
let _isStarted

function isStarted() {
    return _isStarted
}

function _setIsStarted(value) {
    _isStarted = value
}

function start() {
    client = new RPC.Client({ transport: 'ipc' })

    client.on('ready', () => _setIsStarted(true))

    client.login({ clientId }).catch(() => {
        if (!isStarted()) {
            setTimeout(() => {
                start()
            }, 10000)
        }
    })

    client.on('disconnected', () => {
        _setIsStarted(false)
        start()
    })
}

function stop() {
    client.destroy()
    _setIsStarted(false)
}

async function setActivity(info) {
    if (isStarted() && info.track.title) {
        const now = Date.now()
        const activity = {}
        const discordSettings = settingsProvider.get('discord-presence-settings')

        if (discordSettings.details) activity.details = info.track.title

        if (discordSettings.state) activity.state = info.track.author

        if (discordSettings.time) {
            if (info.player.isPaused) {
                delete activity.startTimestamp
                delete activity.endTimestamp
            } else {
                activity.startTimestamp =
                    now + info.player.seekbarCurrentPosition * 1000
                activity.endTimestamp =
                    now +
                    (info.track.duration - info.player.seekbarCurrentPosition) *
                        1000
            }
        }

        // activity.largeImageKey = 'ytm_logo_512'
        activity.largeImageKey = info.track.cover
        activity.smallImageKey = info.player.isPaused
            ? 'discordrpc-pause'
            : 'discordrpc-play'
        activity.largeImageText = 'YouTube Music'
        activity.smallImageText = info.player.isPaused ? 'Paused' : 'Playing'
        activity.instance = false
        if (discordSettings.details) {
            activity.buttons = [
                {
                    label: 'Play on YouTube Music',
                    url: 'https://music.youtube.com/watch?v=' + info.track.id,
                },
            ]
        }

        if ((!discordSettings.hideIdle && info.player.isPaused) || info.track.isAdvertisement) {
            await client.clearActivity()
        } else {
            // As of writing this discord-rpc was not updated to support buttons with setActivity
            await client.request('SET_ACTIVITY', {
                pid: process.pid,
                activity: {
                    state: activity.state,
                    details: activity.details,
                    timestamps: {
                        start: activity.startTimestamp,
                        end: activity.endTimestamp,
                    },
                    assets: {
                        large_image: activity.largeImageKey,
                        large_text: activity.largeImageText,
                        small_image: activity.smallImageKey,
                        small_text: activity.smallImageText,
                    },
                    instance: activity.instance,
                    buttons: activity.buttons,
                },
            })
        }
    }
}

module.exports = {
    isStarted: isStarted,
    start: start,
    stop: stop,
    setActivity: setActivity,
}


text:
const { ipcMain } = require('electron')
const WebSocket = require('ws')
const url = 'ws://127.0.0.1:8974'
let ws, reconnect, volumePercent, seekPosition, _isStarted

function isStarted() {
    return _isStarted
}

function _setIsStarted(value) {
    _isStarted = value
}

function start() {
    try {
        ws = new WebSocket(url, {
            perMessageDeflate: false,
        })

        ws.on('open', function open() {
            _setIsStarted(true)
        })

        ws.on('message', (data) => {
            const versionNumber = data.toLowerCase().split(':')
            if (versionNumber[0].includes('version')) {
                //Check that version number is the same major version
            }
            try {
                doAction(data)
            } catch (e) {
                ws.send('Error:' + e)
                throw e
            }
        })

        ws.on('error', (_) => {
            console.log('Failed to connect rainmeter WebNowPlaying WS')
        })

        ws.on('close', () => {
            stop()
            reconnect = setTimeout(() => {
                if (!isStarted()) start()
            }, 5000)
        })
    } catch (_) {
        console.log('error')
    }
}

function stop() {
    _setIsStarted(false)
    ws.terminate()
}

function setActivity(data) {
    if (!isStarted()) return

    ws.send(`COVER:${data.track.cover}`)
    ws.send(`TITLE:${data.track.title}`)
    ws.send(`ARTIST:${data.track.author}`)
    ws.send(`ALBUM:${data.track.album}`)
    ws.send(`STATE:${data.player.isPaused ? 2 : 1}`)
    ws.send(`DURATION:${data.track.durationHuman}`)
    ws.send(`POSITION:${data.player.seekbarCurrentPositionHuman}`)
    ws.send(`VOLUME:${data.player.volumePercent}`)
    if (data.player.likeStatus === 'LIKE') ws.send(`RATING:5`)
    else if (data.player.likeStatus === 'DISLIKE') ws.send(`RATING:1`)
    else ws.send(`RATING:0`)

    // Store the Volume Percent for the Volume changing
    volumePercent = data.player.volumePercent
}

function doAction(data) {
    const dataSplit = data.split(' ')
    let action = dataSplit.shift()
    const actionParams = dataSplit

    if (actionParams.length && action === 'SetPosition') {
        const seekValuePercent = parseFloat(actionParams[1].split(':')[0])
        if (seekValuePercent !== 0) {
            action = 'SetPositionSeekbar'
            actionParams[0] = actionParams[0].split(':')[0] / 100000
        }
    }

    switch (action) {
        case 'PlayPause':
            ipcMain.emit('media-command', {
                command: 'media-play-pause',
                value: true,
            })
            break

        case 'next':
            ipcMain.emit('media-command', {
                command: 'media-track-next',
                value: true,
            })
            break

        case 'previous':
            ipcMain.emit('media-command', {
                command: 'media-track-previous',
                value: true,
            })
            break

        case 'togglethumbsup':
            ipcMain.emit('media-command', {
                command: 'media-vote-up',
                value: true,
            })
            break

        case 'togglethumbsdown':
            ipcMain.emit('media-command', {
                command: 'media-vote-down',
                value: true,
            })
            break

        case 'SetVolume':
            // Technically this doesn't actually set the Volume to WebNowPlaying's Standards
            // as we're letting the up/down volume set decide rather than a specific value.
            if (actionParams[0] >= volumePercent)
                ipcMain.emit('media-command', {
                    command: 'media-volume-up',
                    value: true,
                })
            else
                ipcMain.emit('media-command', {
                    command: 'media-volume-down',
                    value: true,
                })

            break

        case 'SetPosition':
            const currentPosition = actionParams[0].split(':')[0]
            if (currentPosition >= seekPosition)
                ipcMain.emit('media-command', {
                    command: 'media-seekbar-forward',
                    value: true,
                })
            else
                ipcMain.emit('media-command', {
                    command: 'media-seekbar-rewind',
                    value: true,
                })
            break

        case 'SetPositionSeekbar':
            ipcMain.emit('media-command', {
                command: 'media-seekbar-set',
                value: actionParams[0],
            })
            break
    }
}

module.exports = {
    isStarted: isStarted,
    start: start,
    stop: stop,
    setActivity: setActivity,
}


text:
const { remote } = require('electron')
const scribble = require('scribble')
const settingsProvider = require('./settingsProvider')
const http = require('http')
const Base64 = require('js-base64').Base64

const apiKey = '9ab417e8b808ed071223a1b4b3c29642'
const apiSecret = '9d8830c167627e65dac63786be101964'

let Scrobbler, userLogin

function signIn() {
    userLogin = getLogin()
    if (userLogin) {
        Scrobbler = new scribble(
            apiKey,
            apiSecret,
            userLogin.username,
            userLogin.password
        )
    }
}

function setLogin(username, password) {
    settingsProvider.set('last-fm-login', {
        username: username,
        password: Base64.encode(password),
    })
}

function getLogin() {
    const login = settingsProvider.get('last-fm-login')
    if (login.username !== '') {
        login.password = Base64.decode(login.password)
        return login
    }

    return false
}

function getToken() {
    http.get(
        `http://ws.audioscrobbler.com/2.0/?method=auth.gettoken&api_key=${apiKey}&format=json`,
        function (res) {
            let rawData = ''
            res.on('data', (chunk) => {
                rawData += chunk
            })
            res.on('end', () => {
                try {
                    const parsedData = JSON.parse(rawData)
                    authorize(parsedData.token)
                } catch (e) {
                    console.error(e.message)
                }
            })
        }
    )
}

function updateTrackInfo(title, author, album) {
    if (Scrobbler === undefined) signIn()

    const track = {
        artist: author,
        track: title,
        album: album,
    }

    Scrobbler.Scrobble(track, function (_) {})
}

function updateNowPlaying(title, author, album, duration) {
    if (Scrobbler === undefined) signIn()

    const track = {
        artist: author,
        track: title,
        album: album,
        duration: duration,
    }
    Scrobbler.NowPlaying(track, function (_) {})
}

async function authorize(token) {
    let winAuthorize = new remote.BrowserWindow({
        title: 'Last.FM Authorization',
        width: 900,
        height: 500,
    })
    await winAuthorize.loadURL(
        `https://www.last.fm/api/auth?api_key=${apiKey}&token=${token}`
    )
}

module.exports = {
    getToken: getToken,
    updateTrackInfo: updateTrackInfo,
    updateNowPlaying: updateNowPlaying,
    getLogin: getLogin,
    setLogin: setLogin,
    authorize: authorize,
}


text:
const { ipcMain } = require('electron')
const mpris = require('mpris-service')

class Mpris {
    constructor() {
        this._isInitialized = false
        this.player = undefined
        this._realPlayer = undefined //we'll need the infoPlayer later to be better able to track the time.
    }

    start() {
        this.player = new mpris({
            name: 'youtube-music-desktop-app',
            identity: 'Youtube Music',
            supportedUriSchemes: ['file'],
            supportedMimeTypes: ['audio/mpeg', 'application/ogg'],
            supportedInterfaces: ['player'],
            canRaise: true,
        })

        this._setInitialEvents()

        this._isInitialized = true
    }

    setRealPlayer(infoPlayer) {
        if (this.player) {
            this._realPlayer = infoPlayer
            //Overriding this method makes it a lot easier to be able to controll the playback position.
            this.player.getPosition = () =>
                this._realPlayer.getPlayerInfo().seekbarCurrentPosition *
                1000 *
                1000
        }
    }

    setActivity(info) {
        if (this._isInitialized) {
            // 50% is represented as 50 in info.player.volumePercent
            // while mpris represents it as 0.50, so we need to convert it first
            this.player.volume = info.player.volumePercent / 100
            this.player.metadata = {
                'mpris:trackid': this.player
                    .objectPath('track/0')
                    .replaceAll('-', '_'), // replacing -'s in name with _ to meet dbus object name spec
                'mpris:length': info.track.duration * 1000 * 1000, // In microseconds
                'mpris:artUrl': info.track.cover,
                'xesam:title': info.track.title,
                'xesam:album': info.track.album,
                'xesam:artist': [info.track.author],
            }
            this.player.playbackStatus = info.player.isPaused
                ? mpris.PLAYBACK_STATUS_PAUSED
                : mpris.PLAYBACK_STATUS_PLAYING
        }
    }

    _setInitialEvents() {
        const events = {
            quit: () => process.exit(0),
            previous: 'media-track-previous',
            next: 'media-track-next',
            pause: 'media-play-pause',
            play: 'media-play-pause',
            playpause: 'media-play-pause', //KDE Connect only sends this event it looked like.
        }

        for (let [event, action] of Object.entries(events)) {
            if (typeof action === 'string')
                this.player.on(event, () => {
                    ipcMain.emit('media-command', {
                        command: action,
                        value: true,
                    })
                })
            else if (typeof action === 'function') this.player.on(event, action)
        }
        this.player.on('position', (args) => {
            // the position event sends through {trackId : ###, position : ###}
            ipcMain.emit('media-command', {
                command: 'media-seekbar-set',
                value: args.position / (1000 * 1000),
            })
        })

        this.player.on('volume', (args) => {
            if (args === undefined) return
            ipcMain.emit('media-command', {
                command: 'media-volume-set',
                // 50% is represented as 50 in info.player.volumePercent
                // while mpris represents it as 0.50, so we need to convert it first
                value: args * 100,
            })
        })

        this.player.on('raise', () => {
            ipcMain.emit('show', null)
        })

        this.player.on('seek', (offset) => {
            // the seek event sends through the difference from where we should be in microseconds, positive forward, negative backward
            ipcMain.emit('media-command', {
                command: 'media-seekbar-set',
                value: (this.player.getPosition() + offset) / (1000 * 1000),
            })
        })
    }
}

module.exports = new Mpris()


text:
const { ipcMain } = require('electron')
const http = require('http')
const os = require('os')
const url = require('url')
const networkInterfaces = os.networkInterfaces()
const settingsProvider = require('../providers/settingsProvider')

const ip = '0.0.0.0'
const port = 9864

const pattIgnoreInterface = /(Loopback|lo$|virtual|wsl|vEthernet|Default Switch|VMware|Adapter|Hamachi)\w*/gim
let serverInterfaces = []

function fetchNetworkInterfaces() {
    serverInterfaces = Object.entries(networkInterfaces)
        .filter(([interfaces]) => !pattIgnoreInterface.test(interfaces))
        .map(([name, value]) => {
            value = value.filter(
                (data) => data.family === 'IPv4' && data.internal === false
            )
            return {
                name: name,
                ip: value.length ? value[0].address : '',
            }
        })
}

const serverFunction = (req, res) => {
    const realUrl =
        (req.connection.encrypted ? 'https' : 'http') +
        '://' +
        req.headers.host +
        req.url
    const urlObj = url.parse(realUrl, true)
    if (urlObj.pathname === '/') {
        res.setHeader('Content-Type', 'text/html; charset=utf-8')
        res.setHeader('Access-Control-Allow-Origin', '*')
        res.writeHead(200)
        res.write(`

              <title>YTMDesktop Genius authenticating...</title>
              <meta name="viewport" content="width=device-width, initial-scale=1.0"/>

Authenticating..

      `)

        if (urlObj.query['access_token']) {
            console.log(urlObj.query.access_token)
            console.log(urlObj.query.token_type)
            settingsProvider.set('genius-auth', urlObj.query)
        }
        res.end()
    } else if (req.url === '/login') {
        const clientID = `KBdWh3QGsSZI1joBSRmO3KvhBkanqt5hrofKo9rHjvRAZ4VybE4Fxqj4pRqKMrI6`
        const redirectURI = `http://localhost:9864/`
        res.writeHead(301, {
            Location: `http://api.genius.com/oauth/authorize?response_type=token&client_id=${clientID}&redirect_uri=${redirectURI}`,
        })
        res.end()
    }
}

const server = http.createServer(serverFunction)

function start() {
    try {
        server.listen(port, ip)
        fetchNetworkInterfaces()
        ipcMain.emit('log', {
            type: 'info',
            data: `Genius Auth Server listening on port ${port}`,
        })
    } catch (error) {
        ipcMain.emit('log', {
            type: 'warn',
            data: `Error to start server on port ${port}.\n cause: ${error}`,
        })
    }
}

function stop() {
    server.close()
    console.log('Genius Auth Server has stopped')
}

module.exports = {
    start: start,
    stop: stop,
}


text:
/**
 * system-info.js
 * Utils for System info
 */

function isWindows() {
    return process.platform === 'win32'
}

function isLinux() {
    return (
        process.platform === 'freebsd' ||
        process.platform === 'linux' ||
        process.platform === 'openbsd'
    )
}

function isMac() {
    return process.platform === 'darwin'
}

module.exports = {
    isWindows: isWindows,
    isLinux: isLinux,
    isMac: isMac,
}


text:
const { screen, ipcMain } = require('electron')

function create() {
    // for create window
}

function checkWindowPosition(windowPosition, windowSize) {
    return new Promise((resolve, reject) => {
        try {
            if (!windowPosition || !windowSize) {
                reject(false)
                return
            }

            let nearestDisplay = screen.getDisplayMatching({
                x: windowPosition.x,
                y: windowPosition.y,
                width: windowSize.width,
                height: windowSize.height,
            })
            let nearestDisplayBounds = nearestDisplay.bounds

            var position = {
                x: windowPosition.x,
                y: windowPosition.y,
            }

            // The reason for + 64 in window sizes is because 1px inside nearest display is considered visible but not user friendly as it's quite well hidden and could prevent dragging
            if (
                windowPosition &&
                windowSize &&
                windowPosition.x - (windowSize.width + 64) >
                    nearestDisplayBounds.x
            ) {
                position.x = windowPosition.x - nearestDisplayBounds.width
            }

            if (
                windowPosition &&
                windowSize &&
                windowPosition.x + (windowSize.width + 64) <
                    nearestDisplayBounds.x
            ) {
                position.x = windowPosition.x + nearestDisplayBounds.width
            }

            if (
                windowPosition &&
                windowSize &&
                windowPosition.y - (windowSize.height + 64) >
                    nearestDisplayBounds.y
            ) {
                position.y = windowPosition.y - nearestDisplayBounds.height
            }

            if (
                windowPosition &&
                windowSize &&
                windowPosition.y + (windowSize.height + 64) <
                    nearestDisplayBounds.y
            ) {
                position.y = windowPosition.y + nearestDisplayBounds.height
            }

            resolve(position)
        } catch (err) {
            console.log('error -> checkWindowPosition', err)
            reject(false)
        }
    })
}

function doBehavior(mainWindow) {
    if (mainWindow.isVisible())
        if (mainWindow.isFocused()) mainWindow.hide()
        else mainWindow.show()
    else if (mainWindow.isFocused())
        ipcMain.emit('window', { command: 'restore-main-window' })
    else ipcMain.emit('window', { command: 'restore-main-window' })
}

module.exports = {
    create: create,
    checkWindowPosition: checkWindowPosition,
    doBehavior: doBehavior,
}


text:
const settingsProvider = require('../providers/settingsProvider')
const { isLinux } = require('./systemInfo')
const { app } = require('electron')

if (isLinux()) settingsProvider.setInitialValue('titlebar-type', 'system')
// With system title bar
else settingsProvider.setInitialValue('titlebar-type', 'nice') // Without system title bar

settingsProvider.setInitialValue('settings-page-zoom', 100) // 100

settingsProvider.setInitialValue('last-fm-login', {
    username: '',
    password: '',
}) // Empty user and pass

settingsProvider.setInitialValue('settings-app-language', 'en') // English

settingsProvider.setInitialValue('settings-miniplayer-size', '200') // Normal size

settingsProvider.setInitialValue('settings-miniplayer-resizable', false) // Not resizable

settingsProvider.setInitialValue('settings-miniplayer-show-task', false) // hide from taskbar

settingsProvider.setInitialValue('settings-miniplayer-always-top', false) // show on top always

settingsProvider.setInitialValue('settings-miniplayer-stream-config', false) // use base miniplayer

settingsProvider.setInitialValue('settings-lyrics-provider', '1') // OVH

settingsProvider.setInitialValue('settings-lyrics-always-top', false) // show on top always

settingsProvider.setInitialValue('settings-companion-server-protect', true) // Yes

settingsProvider.setInitialValue('settings-enable-player-bgcolor', false)

settingsProvider.setInitialValue(
    // Random token
    'settings-companion-server-token',
    Math.random().toString(36).substr(2, 5).toUpperCase()
)

settingsProvider.setInitialValue(
    'settings-enable-double-tapping-show-hide',
    true
) // Yes

settingsProvider.setInitialValue('settings-enable-taskbar-progressbar', true) // Yes

settingsProvider.setInitialValue('settings-accelerators', {
    'media-play-pause': 'CmdOrCtrl+Shift+Space',
    'media-track-next': 'CmdOrCtrl+Shift+PageUp',
    'media-track-previous': 'CmdOrCtrl+Shift+PageDown',
    'media-track-like': 'CmdOrCtrl+Shift+L',
    'media-track-dislike': 'CmdOrCtrl+Shift+D',
    'media-volume-up': 'CmdOrCtrl+Shift+Up',
    'media-volume-down': 'CmdOrCtrl+Shift+Down',
})

let accelerators = settingsProvider.get('settings-accelerators')
if (!accelerators['media-volume-up']) {
    accelerators['media-volume-up'] = 'CmdOrCtrl+Shift+Up'
    accelerators['media-volume-down'] = 'CmdOrCtrl+Shift+Down'
    settingsProvider.set('settings-accelerators', accelerators)
}

if (!accelerators['miniplayer-open-close']) {
    accelerators['miniplayer-open-close'] = 'CmdOrCtrl+Shift+M'
    settingsProvider.set('settings-accelerators', accelerators)
}

settingsProvider.setInitialValue('has-updated', false)

settingsProvider.setInitialValue('discord-presence-settings', {
    details: true,
    state: true,
    time: true,
    hideIdle: true,
})

settingsProvider.setInitialValue(
    'settings-disable-hardware-acceleration',
    false
)

settingsProvider.setInitialValue('settings-windows10-media-service', false)

settingsProvider.setInitialValue(
    'settings-windows10-media-service-show-info',
    false
)

settingsProvider.setInitialValue('settings-shortcut-buttons', {
    miniplayer: true,
    lyrics: true,
    'add-to-library': true,
    'add-to-playlist': true,
})

settingsProvider.setInitialValue('settings-skip-track-disliked', false)

settingsProvider.setInitialValue('settings-skip-track-shorter-than', '0')

settingsProvider.setInitialValue('settings-clipboard-always-ask-read', true)

settingsProvider.setInitialValue('settings-tray-icon', true)

settingsProvider.setInitialValue('settings-volume', 100)

settingsProvider.setInitialValue('settings-volume-media-keys', false)

settingsProvider.setInitialValue('settings-decibel-volume', true)

settingsProvider.setInitialValue(
    'settings-shiny-tray-song-title-rollable',
    true
)
settingsProvider.setInitialValue(
    'settings-locales-path',
    app.getPath('userData')
)

settingsProvider.setInitialValue('settings-pause-on-suspend', false)

settingsProvider.setInitialValue('settings-disable-analytics', false)

settingsProvider.setInitialValue('settings-surround-sound', false)

// Please note that this is a setting which is not displayed to the user, but will be used in the application.
settingsProvider.setInitialValue(
    'user-agent',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0'
)

// Update the User agent in the future via the Application side.
// if (settingsProvider.get('user-agent') === 'previous-useragent') {
// settingsProvider.setInitialValue('user-agent', 'Updated Useragent');
// }