/* eslint-disable no-shadow */ /* global l1Player require */ /* global angular isElectron i18next i18nextHttpBackend Notyf notyf */ /* global setPrototypeOfLocalStorage */ /* eslint-disable global-require */ /* eslint-disable no-unused-vars */ /* eslint-disable no-param-reassign */ /* eslint-disable import/no-unresolved */ const sourceList = [ { name: 'netease', displayId: '_NETEASE_MUSIC', }, { name: 'qq', displayId: '_QQ_MUSIC', }, { name: 'kugou', displayId: '_KUGOU_MUSIC', }, { name: 'kuwo', displayId: '_KUWO_MUSIC', }, { name: 'bilibili', displayId: '_BILIBILI_MUSIC', searchable: false, }, { name: 'migu', displayId: '_MIGU_MUSIC', }, { name: 'taihe', displayId: '_TAIHE_MUSIC', }, ]; const main = () => { const app = angular.module('listenone', []); setPrototypeOfLocalStorage(); app.config([ '$compileProvider', ($compileProvider) => { $compileProvider.imgSrcSanitizationWhitelist( /^\s*(https?|ftp|mailto|chrome-extension|moz-extension|file):/ ); }, ]); app.run([ '$q', ($q) => { axios.Axios.prototype.request_original = axios.Axios.prototype.request; axios.Axios.prototype.request = function new_req(config) { return $q.when(this.request_original(config)); }; window.notyf = new Notyf({ duration: 5000, ripple: true, position: { x: 'center', y: 'top' }, types: [ { type: 'warning', background: 'darkorange', icon: false, }, { type: 'info', background: 'deepskyblue', icon: false, }, ], }); window.notyf.warning = (msg, replace) => { if (replace) { notyf.dismissAll(); } window.notyf.open({ type: 'warning', message: msg, }); }; window.notyf.info = (msg, replace) => { if (replace) { notyf.dismissAll(); } window.notyf.open({ type: 'info', message: msg, }); }; axios.get('images/feather-sprite.svg').then((res) => { document.getElementById('feather-container').innerHTML = res.data; }); }, ]); l1Player.injectDirectives(app); app.filter('playmode_title', () => (input) => { switch (input) { case 0: return '顺序'; case 1: return '随机'; case 2: return '单曲循环'; default: return ''; } }); app.directive('customOnChange', () => { const ret = { restrict: 'A', link: (scope, element, attrs) => { const onChangeHandler = scope.$eval(attrs.customOnChange); element.bind('change', onChangeHandler); }, }; return ret; }); app.directive('volumeWheel', () => (scope, element, attrs) => { element.bind('mousewheel', () => { l1Player.adjustVolume(window.event.wheelDelta > 0); }); }); app.directive('pagination', () => ({ restrict: 'EA', replace: false, template: ` `, })); app.directive('errSrc', () => ({ // https://stackoverflow.com/questions/16310298/if-a-ngsrc-path-resolves-to-a-404-is-there-a-way-to-fallback-to-a-default link: (scope, element, attrs) => { element.bind('error', () => { if (attrs.src !== attrs.errSrc) { attrs.$set('src', attrs.errSrc); } }); attrs.$observe('ngSrc', (value) => { if (!value && attrs.errSrc) { attrs.$set('src', attrs.errSrc); } }); }, })); app.directive('resize', ($window) => (scope, element) => { const w = angular.element($window); const changeHeight = () => { const headerHeight = 90; const footerHeight = 90; element.css('height', `${w.height() - headerHeight - footerHeight}px`); }; w.bind('resize', () => { changeHeight(); // when window size gets changed }); changeHeight(); // when page loads }); app.directive('addAndPlay', [ () => ({ restrict: 'EA', scope: { song: '=addAndPlay', }, link(scope, element, attrs) { element.bind('click', (event) => { l1Player.addTrack(scope.song); l1Player.playById(scope.song.id); }); }, }), ]); app.directive('addWithoutPlay', [ () => ({ restrict: 'EA', scope: { song: '=addWithoutPlay', }, link(scope, element, attrs) { element.bind('click', (event) => { l1Player.addTrack(scope.song); notyf.success(i18next.t('_ADD_TO_QUEUE_SUCCESS')); }); }, }), ]); app.directive('openUrl', [ '$window', ($window) => ({ restrict: 'EA', scope: { url: '=openUrl', }, link(scope, element, attrs) { element.bind('click', (event) => { if (isElectron()) { const { shell } = require('electron'); shell.openExternal(scope.url); } else { $window.open(scope.url, '_blank'); } }); }, }), ]); app.directive('windowControl', [ '$window', ($window) => ({ restrict: 'EA', scope: { action: '@windowControl', }, link(scope, element, attrs) { element.bind('click', (event) => { if (isElectron()) { const { ipcRenderer } = require('electron'); ipcRenderer.send('control', scope.action); } }); }, }), ]); app.directive('infiniteScroll', [ '$window', '$rootScope', ($window, $rootScope) => ({ restrict: 'EA', scope: { infiniteScroll: '&', contentSelector: '=contentSelector', }, link(scope, elements, attrs) { elements.bind('scroll', (event) => { if (scope.loading) { return; } const containerElement = elements[0]; const contentElement = document.querySelector(scope.contentSelector); const baseTop = containerElement.getBoundingClientRect().top; const currentTop = contentElement.getBoundingClientRect().top; const baseHeight = containerElement.offsetHeight; const offset = baseTop - currentTop; const bottom = offset + baseHeight; const height = contentElement.offsetHeight; const remain = height - bottom; if (remain < 0) { // page not shown return; } const offsetToload = 10; if (remain <= offsetToload) { $rootScope.$broadcast('infinite_scroll:hit_bottom', ''); } }); }, }), ]); /* drag drop support */ app.directive('dragDropZone', [ '$window', ($window) => ({ restrict: 'A', scope: { dragobject: '=dragZoneObject', dragtitle: '=dragZoneTitle', dragtype: '=dragZoneType', ondrop: '&dropZoneOndrop', ondragleave: '&dropZoneOndragleave', sortable: '=', }, link(scope, element, attrs) { // https://stackoverflow.com/questions/34200023/drag-drop-set-custom-html-as-drag-image element.on('dragstart', (ev) => { if (scope.dragobject === undefined) { return; } if (scope.dragtype === undefined) { return; } ev.dataTransfer.setData( scope.dragtype, JSON.stringify(scope.dragobject) ); const elem = document.createElement('div'); elem.id = 'drag-ghost'; elem.innerHTML = scope.dragtitle; elem.style.position = 'absolute'; elem.style.top = '-1000px'; elem.style.padding = '3px'; elem.style.background = '#eeeeee'; elem.style.color = '#333'; elem.style['border-radius'] = '3px'; document.body.appendChild(elem); ev.dataTransfer.setDragImage(elem, 0, 40); }); element.on('dragend', () => { const ghost = document.getElementById('drag-ghost'); if (ghost.parentNode) { ghost.parentNode.removeChild(ghost); } }); element.on('dragenter', (event) => { let dragType = ''; if (event.dataTransfer.types.length > 0) { [dragType] = event.dataTransfer.types; } if ( scope.dragtype === 'application/listen1-myplaylist' && dragType === 'application/listen1-song' ) { element[0].classList.add('dragover'); } }); element.on('dragleave', (event) => { element[0].classList.remove('dragover'); if (scope.ondragleave !== undefined) { scope.ondragleave(); } if (scope.sortable) { const target = element[0]; target.style['z-index'] = '0'; target.style['border-bottom'] = 'solid 2px transparent'; target.style['border-top'] = 'solid 2px transparent'; } }); element.on('dragover', (event) => { event.preventDefault(); const dragLineColor = '#FF4444'; let dragType = ''; if (event.dataTransfer.types.length > 0) { [dragType] = event.dataTransfer.types; } if (scope.dragtype === dragType && scope.sortable) { event.dataTransfer.dropEffect = 'move'; const bounding = event.target.getBoundingClientRect(); const offset = bounding.y + bounding.height / 2; const direction = event.clientY - offset > 0 ? 'bottom' : 'top'; const target = element[0]; if (direction === 'bottom') { target.style['border-bottom'] = `solid 2px ${dragLineColor}`; target.style['border-top'] = 'solid 2px transparent'; target.style['z-index'] = '9'; } else if (direction === 'top') { target.style['border-top'] = `solid 2px ${dragLineColor}`; target.style['border-bottom'] = 'solid 2px transparent'; target.style['z-index'] = '9'; } } else if ( scope.dragtype === 'application/listen1-myplaylist' && dragType === 'application/listen1-song' ) { event.dataTransfer.dropEffect = 'copy'; } }); element.on('drop', (event) => { if (scope.ondrop === undefined) { return; } const [dragType] = event.dataTransfer.types; const jsonString = event.dataTransfer.getData(dragType); const data = JSON.parse(jsonString); let direction = ''; const bounding = event.target.getBoundingClientRect(); const offset = bounding.y + bounding.height / 2; direction = event.clientY - offset > 0 ? 'bottom' : 'top'; // https://stackoverflow.com/questions/19889615/can-an-angular-directive-pass-arguments-to-functions-in-expressions-specified-in scope.ondrop({ arg1: data, arg2: dragType, arg3: direction }); element[0].classList.remove('dragover'); if (scope.sortable) { const target = element[0]; target.style['border-top'] = 'solid 2px transparent'; target.style['border-bottom'] = 'solid 2px transparent'; } }); }, }), ]); app.directive('draggableBar', [ '$document', '$rootScope', ($document, $rootScope) => (scope, element, attrs) => { let x; let container; const { mode } = attrs; function onMyMousedown() { if (mode === 'play') { scope.changingProgress = true; } } function onMyMouseup() { if (mode === 'play') { scope.changingProgress = false; } } function onMyUpdateProgress(progress) { if (mode === 'play') { $rootScope.$broadcast('track:myprogress', progress * 100); } if (mode === 'volume') { l1Player.setVolume(progress * 100); l1Player.unmute(); } } function onMyCommitProgress(progress) { if (mode === 'play') { l1Player.seek(progress); } if (mode === 'volume') { const current = localStorage.getObject('player-settings'); current.volume = progress * 100; localStorage.setObject('player-settings', current); } } function commitProgress(progress) { onMyCommitProgress(progress); } function updateProgress() { if (container) { if (x < 0) { x = 0; } else if (x > container.right - container.left) { x = container.right - container.left; } } const progress = x / (container.right - container.left); onMyUpdateProgress(progress); } function mousemove(event) { x = event.clientX - container.left; updateProgress(); } function mouseup() { const progress = x / (container.right - container.left); commitProgress(progress); $document.off('mousemove', mousemove); $document.off('mouseup', mouseup); onMyMouseup(); } element.on('mousedown', (event) => { onMyMousedown(); container = document.getElementById(attrs.id).getBoundingClientRect(); // Prevent default dragging of selected content event.preventDefault(); x = event.clientX - container.left; updateProgress(); $document.on('mousemove', mousemove); $document.on('mouseup', mouseup); }); }, ]); }; i18next.use(i18nextHttpBackend).init({ lng: 'zh-CN', fallbackLng: 'zh-CN', supportedLngs: ['zh-CN', 'zh-TC', 'en-US', 'fr-FR'], preload: ['zh-CN', 'zh-TC', 'en-US', 'fr-FR'], debug: false, backend: { loadPath: 'i18n/{{lng}}.json', }, }); main();