MarshallOfSound/Google-Play-Music-Desktop-Player-UNOFFICIAL-

View on GitHub
src/main/features/core/tray.js

Summary

Maintainability
D
1 day
Test Coverage
import { app, Menu, Tray, shell } from 'electron';
import path from 'path';

import { showDesktopSettings } from './desktopSettings';

let appIcon = null;
const mainWindow = WindowManager.getAll('main')[0];

const trayNormalPath = `${__dirname}/../../../assets/img/`;
const trayPausedPath = `${__dirname}/../../../assets/img/paused/`;
const trayPlayingPath = `${__dirname}/../../../assets/img/playing/`;

let currentIconPath = trayNormalPath;
let appIconInvert = Settings.get('appIconInvert', false);

function getAppIconFileName() {
  let appIconFileName;
  if (process.platform === 'darwin') {
    appIconFileName = 'macTemplate.png';
  } else if (WindowManager.getWindowManagerGDMName() === 'kde-plasma') {
    // TODO: Change this back to ico when electron supports it on linux
    // appIconFileName = 'main.ico';
    appIconFileName = 'main_tray_white_s.png';
  } else if (process.platform === 'linux') {
    appIconFileName = appIconInvert ? 'main_tray_black_s.png' : 'main_tray_white_s.png';
  } else {
    appIconFileName = 'main_tray_s.png';
  }
  return path.resolve(currentIconPath, appIconFileName);
}

const getTrackString = (track) => {
  let title = track.title;
  const artist = track.artist;

  if (title.length + artist.length > 40) {
    title = `${title.substring(0, 40 - (artist.length + 6))}...`;
  }

  let trackString = `${title} - ${artist}`;

  // fix display of ampersands on windows
  if (process.platform === 'win32') {
    trackString = trackString.replace('&', '&&');
  }

  return trackString;
};

let audioDeviceMenu = [
  {
    label: TranslationProvider.query('label-loading-devices'),
    enabled: false,
  },
];

appIcon = new Tray(getAppIconFileName());

Settings.onChange('appIconInvert', (newValue) => {
  appIconInvert = newValue;
  if (appIcon) appIcon.setImage(getAppIconFileName());
});

// Change the icon if the music is playing
Emitter.on('playback:isPlaying', () => {
  currentIconPath = trayPlayingPath;
  if (appIcon) appIcon.setImage(getAppIconFileName());
});

// Change the icon is the music is paused
Emitter.on('playback:isPaused', () => {
  currentIconPath = trayPausedPath;
  if (appIcon) appIcon.setImage(getAppIconFileName());
});

// Change the icon is the music is stopped
Emitter.on('playback:isStopped', () => {
  currentIconPath = trayNormalPath;
  if (appIcon) appIcon.setImage(getAppIconFileName());
});

const setContextMenu = (track) => {
  const contextMenu = Menu.buildFromTemplate([
    {
      label: 'Service',
      enabled: false,
    },
    {
      label: TranslationProvider.query('tray-label-gpm'),
      click: () => {
        // DEV: default to the other service so it will switch if not set.
        const currentService = Settings.get('service', 'youtube-music');
        if (currentService !== 'google-play-music') {
          Settings.set('service', 'google-play-music');
          mainWindow.hide();
          mainWindow.reload();
        }
      },
    },
    {
      label: TranslationProvider.query('tray-label-ytm'),
      click: () => {
        // DEV: default to the other service so it will switch if not set.
        const currentService = Settings.get('service', 'google-play-music');
        if (currentService !== 'youtube-music') {
          Settings.set('service', 'youtube-music');
          mainWindow.hide();
          mainWindow.reload();
        }
      },
    },
    { type: 'separator' },
    { label: TranslationProvider.query('tray-label-show'),
      click: () => {
        mainWindow.setSkipTaskbar(false);
        mainWindow.show();
      },
    },
    { label: track ? getTrackString(track) : TranslationProvider.query('playback-os-no-track-playing'),
      enabled: false,
    },
    { type: 'separator' },
    {
      label: TranslationProvider.query('playback-label-play-pause'),
      click: () => Emitter.sendToGooglePlayMusic('playback:playPause'),
    },
    {
      label: TranslationProvider.query('playback-label-previous-track'),
      click: () => Emitter.sendToGooglePlayMusic('playback:previousTrack'),
    },
    {
      label: TranslationProvider.query('playback-label-next-track'),
      click: () => Emitter.sendToGooglePlayMusic('playback:nextTrack'),
    },
    { type: 'separator' },
    {
      label: TranslationProvider.query('playback-label-thumbs-up'),
      click: () => Emitter.sendToGooglePlayMusic('playback:thumbsUp'),
    },
    {
      label: TranslationProvider.query('playback-label-thumbs-down'),
      click: () => Emitter.sendToGooglePlayMusic('playback:thumbsDown'),
    },
    { type: 'separator' },
    {
      label: TranslationProvider.query('tray-label-audio-device'),
      submenu: audioDeviceMenu,
    },
    {
      label: TranslationProvider.query('label-help'),
      role: 'help',
      submenu: [
        {
          label: TranslationProvider.query('label-about'),
          click: () => {
            Emitter.sendToWindowsOfName('main', 'about');
            mainWindow.setSkipTaskbar(false);
            mainWindow.show();
          },
        },
        {
          label: TranslationProvider.query('label-issues'),
          click: () => shell.openExternal('https://github.com/MarshallOfSound/Google-Play-Music-Desktop-Player-UNOFFICIAL-/issues'),
        },
        {
          label: TranslationProvider.query('label-donate'),
          click: () => shell.openExternal('https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=23CZGASL6XMLJ'),
        },
        {
          label: TranslationProvider.query('label-learn-more'),
          click: () => shell.openExternal('http://www.googleplaymusicdesktopplayer.com'),
        },
      ],
    },
    { label: TranslationProvider.query('label-desktop-settings'), click: () => { showDesktopSettings(); } },
    { type: 'separator' },
    { label: TranslationProvider.query('label-quit'), click: () => { global.quitting = true; app.quit(); } },
  ]);
  if (appIcon) appIcon.setContextMenu(contextMenu);
};
setContextMenu(null);


global.wasMaximized = Settings.get('maximized', false);

// Tray icon toggle action (windows, linux)
function toggleMainWindow() {
  // the mainWindow variable will be GC'd
  // we must find the window ourselves
  const win = WindowManager.getAll('main')[0];
  if (!win) return;

  if (win.isMinimized() || !win.isVisible()) {
    win.setSkipTaskbar(false);
    win.show();
    if (global.wasMaximized) {
      win.maximize();
    }
  } else {
    global.wasMaximized = Settings.get('maximized', false);
    win.minimize();
    if (WindowManager.getWindowManagerName() === 'i3') {
      win.hide();
    }
    // Hide to tray, if configured
    if (Settings.get('minToTray', true)) {
      win.setSkipTaskbar(true);
    }
  }
}

if (appIcon) appIcon.setToolTip('Google Play Music Desktop Player');

switch (process.platform) {
  case 'darwin': // <- actually means OS-X
    // No toggle action, use the context menu.
    break;
  case 'linux':
  case 'freebsd': // <- for the hipsters
  case 'sunos':   // <- in case someone runs this in a museum
    appIcon.on('click', toggleMainWindow);
    break;
  case 'win32': // <- it's win32 also on 64-bit Windows
    appIcon.on('double-click', toggleMainWindow);
    break;
  default:
    // impossible case to satisfy Linters
}


// DEV: Keep the icon in the global scope or it gets garbage collected........
global.appIcon = appIcon;

app.on('before-quit', () => {
  appIcon.destroy();
  delete global.appIcon;
  appIcon = null;
});

Emitter.on('audiooutput:list', (event, devices) => {
  audioDeviceMenu = [];
  devices.forEach((device) => {
    if (device.kind === 'audiooutput') {
      let label = device.label;
      if (!label) {
        switch (device.deviceId) {
          case 'default':
            label = TranslationProvider.query('audio-device-default');
            break;
          case 'communications':
            label = TranslationProvider.query('audio-device-communications');
            break;
          default:
            label = TranslationProvider.query('audio-device-unknown');
            break;
        }
      }
      audioDeviceMenu.push({
        label,
        type: 'radio',
        click: () => {
          Emitter.sendToGooglePlayMusic('audiooutput:set', device.deviceId);
          Settings.set('audiooutput', label);
        },
        checked: (label === Settings.get('audiooutput')),
      });
    }
  });
  setContextMenu(PlaybackAPI.currentSong());
});

Emitter.sendToGooglePlayMusic('audiooutput:fetch');
Emitter.on('audiooutput:set', () => Emitter.sendToGooglePlayMusic('audiooutput:fetch'));

PlaybackAPI.on('change:track', (track) => {
  setContextMenu(track);
});