11
2+ import fs from 'fs' ;
23import path from 'path' ;
3- import { app , BrowserWindow , Menu , Tray , globalShortcut , ipcMain , shell , powerMonitor , dialog } from 'electron' ;
4+ import { app , BrowserWindow , Menu , Tray , globalShortcut , ipcMain , shell , powerMonitor , dialog , Notification } from 'electron' ;
45import windowStateKeeper from 'electron-window-state' ;
56import storage from 'electron-json-storage' ;
67import { autoUpdater } from 'electron-updater' ;
78import axios from 'axios' ;
9+ import nodeID3 from 'node-id3' ;
10+ import tmp from 'tmp-promise' ;
11+ import mkdirp from 'mkdirp' ;
12+ import rp from 'request-promise-native' ;
813import _debug from 'debug' ;
914
1015import pkg from './package.json' ;
@@ -13,6 +18,7 @@ import api from './server/api';
1318import usocket from './server/usocket' ;
1419
1520const _PLATFORM = process . platform ;
21+ const _DOWNLOAD_DIR = path . join ( app . getPath ( 'music' ) , pkg . name ) ;
1622
1723let debug = _debug ( 'dev:main' ) ;
1824let error = _debug ( 'dev:main:error' ) ;
@@ -462,6 +468,104 @@ function registerGlobalShortcut() {
462468 } ) ;
463469}
464470
471+ async function getCookies ( ) {
472+ return new Promise ( ( resolve , reject ) => {
473+ mainWindow . webContents . session . cookies . get (
474+ { } ,
475+ ( err , cookies ) => {
476+ if ( err ) {
477+ return resolve ( ) ;
478+ }
479+
480+ resolve ( cookies . map ( e => `${ e . name } =${ e . value } ` ) . join ( '; ' ) ) ;
481+ }
482+ ) ;
483+ } ) ;
484+ }
485+
486+ async function writeFile ( url , filepath ) {
487+ var cookies = await getCookies ( ) ;
488+ var file = fs . createWriteStream ( filepath ) ;
489+
490+ return new Promise ( ( resolve , reject ) => {
491+ try {
492+ rp ( {
493+ url,
494+ headers : {
495+ 'Cookie' : cookies ,
496+ 'Origin' : 'http://music.163.com' ,
497+ 'Referer' : 'http://music.163.com/' ,
498+ }
499+ } ) . pipe ( file ) ;
500+
501+ file . on ( 'finish' , ( ) => {
502+ file . end ( ) ;
503+ resolve ( ) ;
504+ } ) ;
505+ file . on ( 'error' , err => {
506+ throw err ;
507+ } ) ;
508+ } catch ( ex ) {
509+ reject ( ex ) ;
510+ }
511+ } ) ;
512+ }
513+
514+ async function download ( song ) {
515+ var src = song . data . src ;
516+ var imagefile = ( await tmp . file ( ) ) . path ;
517+ var trackfile = path . join (
518+ _DOWNLOAD_DIR ,
519+ `${ song . artists . map ( e => e . name ) . join ( ) } - ${ song . name } .${ src . match ( / ^ h t t p .* \. ( .* ) $ / ) [ 1 ] } `
520+ ) ;
521+ var notificationOptions = {
522+ subtitle : song . name ,
523+ body : song . artists . map ( e => e . name ) . join ( ) ,
524+ closeButtonText : 'Done'
525+ } ;
526+
527+ try {
528+ // Make sure the download directory already exists
529+ if ( fs . existsSync ( _DOWNLOAD_DIR ) === false ) {
530+ mkdirp . sync ( _DOWNLOAD_DIR ) ;
531+ }
532+
533+ await writeFile ( src , trackfile ) ;
534+ await writeFile ( song . album . cover . replace ( / \? .* / , '' ) , imagefile ) ;
535+
536+ let tags = {
537+ title : song . name ,
538+ artist : song . artists . map ( e => e . name ) . join ( ) ,
539+ album : song . album . name ,
540+ image : imagefile ,
541+ } ;
542+ let success = nodeID3 . write ( tags , trackfile ) ;
543+
544+ if ( ! success ) {
545+ throw Error ( 'Failed to write ID3 tags: \'%s\'' , trackfile ) ;
546+ }
547+
548+ let notification = new Notification ( {
549+ title : '🍉 Download Success~' ,
550+ ...notificationOptions ,
551+ } ) ;
552+
553+ notification . on ( 'click' , ( ) => {
554+ shell . showItemInFolder ( _DOWNLOAD_DIR ) ;
555+ } ) ;
556+ notification . show ( ) ;
557+ } catch ( ex ) {
558+ error ( ex ) ;
559+ fs . unlink ( trackfile ) ;
560+ fs . unlink ( imagefile ) ;
561+
562+ new Notification ( {
563+ title : '😕 Download Failed~' ,
564+ ...notificationOptions ,
565+ } ) . show ( ) ;
566+ }
567+ }
568+
465569const goodbye = ( ) => {
466570 forceQuit = true ;
467571 app . quit ( ) ;
@@ -603,6 +707,11 @@ const createMainWindow = () => {
603707 updateTray ( args . playing ) ;
604708 } ) ;
605709
710+ // Download track
711+ ipcMain . on ( 'download' , ( event , args ) => {
712+ download ( JSON . parse ( args . song ) ) ;
713+ } ) ;
714+
606715 // Show the main window
607716 ipcMain . on ( 'show' , event => {
608717 mainWindow . show ( ) ;
@@ -655,8 +764,6 @@ app.on('activate', e => {
655764app . on ( 'before-quit' , e => {
656765 e . preventDefault ( ) ;
657766
658- console . log ( 'Before quit...' ) ;
659-
660767 if ( quitting ) {
661768 return ;
662769 }
0 commit comments