WIP - chrome

This commit is contained in:
Egor 2017-02-15 23:44:58 -08:00
parent d11c71b5b7
commit b4bb64eba3
27 changed files with 202 additions and 1735 deletions

View file

@ -10,13 +10,11 @@ export default Controller.extend({
dimmerOn: false, dimmerOn: false,
lightsIconsOn: true, lightsIconsOn: true,
init(){ init() {
this._super(...arguments); this._super(...arguments);
let storage = new window.Locally.Store({compress: true}), let dimmerOn = chrome.storage.local.get('huegasm.dimmerOn'),
dimmerOn = storage.get('huegasm.dimmerOn'), lightsIconsOn = chrome.storage.local.get('huegasm.lightsIconsOn');
lightsIconsOn = storage.get('huegasm.lightsIconsOn');
this.set('storage', storage);
if (!isEmpty(dimmerOn) && dimmerOn) { if (!isEmpty(dimmerOn) && dimmerOn) {
this.send('toggleDimmer'); this.send('toggleDimmer');
@ -33,9 +31,9 @@ export default Controller.extend({
let lightsIconsOn = this.get('lightsIconsOn'); let lightsIconsOn = this.get('lightsIconsOn');
this.get('storage').set('huegasm.lightsIconsOn', lightsIconsOn); chrome.storage.local.set('huegasm.lightsIconsOn', lightsIconsOn);
}, },
toggleDimmer(){ toggleDimmer() {
this.toggleProperty('dimmerOn'); this.toggleProperty('dimmerOn');
let dimmerOn = this.get('dimmerOn'); let dimmerOn = this.get('dimmerOn');
@ -48,7 +46,7 @@ export default Controller.extend({
$('html').removeClass('dimmerOn'); $('html').removeClass('dimmerOn');
} }
this.get('storage').set('huegasm.dimmerOn', dimmerOn); chrome.storage.local.set('huegasm.dimmerOn', dimmerOn);
} }
} }
}); });

View file

@ -1,3 +1 @@
{{huegasm-app toggleLightsIcons="toggleLightsIcons" toggleDimmer="toggleDimmer" dimmerOn=dimmerOn lightsIconsOn=lightsIconsOn storage=storage}} {{huegasm-app toggleLightsIcons="toggleLightsIcons" toggleDimmer="toggleDimmer" dimmerOn=dimmerOn lightsIconsOn=lightsIconsOn}}
{{huegasm-footer action="toggleDimmer" dimmerOn=dimmerOn storage=storage}}

View file

@ -61,7 +61,7 @@ export default Component.extend({
if (status === 'success' && result.length === 1) { if (status === 'success' && result.length === 1) {
this.set('bridgeIp', result[0].internalipaddress); this.set('bridgeIp', result[0].internalipaddress);
this.get('storage').set('huegasm.bridgeIp', result[0].internalipaddress); chrome.storage.local.set('huegasm.bridgeIp', result[0].internalipaddress);
bridgeFindStatus = 'success'; bridgeFindStatus = 'success';
} else if (result.length > 1) { } else if (result.length > 1) {
let multipleBridgeIps = this.get('multipleBridgeIps'); let multipleBridgeIps = this.get('multipleBridgeIps');
@ -99,7 +99,7 @@ export default Component.extend({
if (status === 'success' && !result[0].error) { if (status === 'success' && !result[0].error) {
this.clearBridgePingIntervalHandle(); this.clearBridgePingIntervalHandle();
this.get('storage').set('huegasm.bridgeUsername', result[0].success.username); chrome.storage.local.set('huegasm.bridgeUsername', result[0].success.username);
this.set('bridgeUsername', result[0].success.username); this.set('bridgeUsername', result[0].success.username);
} }
} }
@ -122,7 +122,7 @@ export default Component.extend({
}, },
chooseBridge(bridge) { chooseBridge(bridge) {
this.set('bridgeIp', bridge); this.set('bridgeIp', bridge);
this.get('storage').set('huegasm.bridgeIp', bridge); chrome.storage.local.set('huegasm.bridgeIp', bridge);
}, },
findBridgeByIp() { findBridgeByIp() {
let manualBridgeIp = this.get('manualBridgeIp'); let manualBridgeIp = this.get('manualBridgeIp');

View file

@ -78,8 +78,8 @@ export default Component.extend({
setInterval(this.updateLightData.bind(this), 2000); setInterval(this.updateLightData.bind(this), 2000);
} }
if (!isNone(this.get('storage').get('huegasm.selectedTab'))) { if (!isNone(chrome.storage.local.get('huegasm.selectedTab'))) {
this.set('selectedTab', this.get('storage').get('huegasm.selectedTab')); this.set('selectedTab', chrome.storage.local.get('huegasm.selectedTab'));
} }
}, },
@ -112,12 +112,11 @@ export default Component.extend({
changeTab(tabName) { changeTab(tabName) {
let index = this.get('tabList').indexOf(tabName); let index = this.get('tabList').indexOf(tabName);
this.set('selectedTab', index); this.set('selectedTab', index);
this.get('storage').set('huegasm.selectedTab', index); chrome.storage.local.set('huegasm.selectedTab', index);
}, },
clearBridge() { clearBridge() {
let storage = this.get('storage'); chrome.storage.local.remove('huegasm.bridgeUsername');
storage.remove('huegasm.bridgeUsername'); chrome.storage.local.remove('huegasm.bridgeIp');
storage.remove('huegasm.bridgeIp');
location.reload(); location.reload();
}, },
toggleDimmer() { toggleDimmer() {
@ -127,119 +126,8 @@ export default Component.extend({
this.sendAction('toggleLightsIcons'); this.sendAction('toggleLightsIcons');
}, },
clearAllSettings() { clearAllSettings() {
this.get('storage').clear(); chrome.storage.local.clear();
location.reload(); location.reload();
},
startIntro() {
let intro = introJs(),
playerBottom = $('#player-bottom');
if (this.get('dimmerOn')) {
this.send('toggleDimmer');
}
intro.setOptions({
steps: [
{
intro: 'Welcome! This short tutorial will introduce you to Huegasm.'
},
{
element: '#music-tab',
intro: 'This is the music player. You\'ll use this to play music and synchronize it with your active lights.<br><br>' +
'<i><b>TIP</b>: Control which lights are active through the <b>Lights</b> tab.</i>'
},
{
element: '#playlist',
intro: 'You can add and select music to play from your playlist here. You may listen to local audio files, stream music from soundcloud or stream directly from a connected microphone.<br><br>' +
'<i><b>TIP</b>: Songs added through Soundcloud will be saved for when you visit this page again.</i>'
},
{
element: $('#playlist md-menu')[0],
intro: '<img src="/assets/images/soundcloudUrl.png" id="soundcloud-tutorial">You can add songs from SoundCloud by copy and pasting the URL shown here'
},
{
element: '#player-area',
intro: 'The audio playback may be controlled with the controls here. Basic music visualization effects may be shown here by selecting them from the menu ( eyeball icon in the bottom right ).'
},
{
element: '#beat-option-row',
intro: 'These are the settings for the music tab:<br>' +
'<b>Sensitivity</b> - The sensitivity of the beat detector ( more sensitivity results in more registered beats )<br>' +
'<b>Hue Range</b> - The hue range that the lights may change to on beat.<br>' +
'<b>Brightness Range</b> - The minimum ( off-beat ) and maximum ( on-beat ) brightness of the lights.<br>' +
'<b>Flashing Transitions</b> - Quickly flash the lights on beat<br>' +
'<b>Colorloop</b> - Slowly cycle the lights through all the colors while the music is playing<br>' +
'<i><b>TIP</b>: Your sensitivity settings are saved per song as indicated by the red star icon in the top left corner. These settings they will be restored if you ever listen to the same song again.</i>',
position: 'top'
},
{
element: '#beat-container',
intro: 'An interactive speaker that will bump when a beat is registered. <br><br>' +
'<i><b>TIP</b>: Click on the center of the speaker to simulate a beat.</i>',
position: 'top'
},
{
element: '#lights-tab',
intro: 'This is the lights tab. Here you\'ll be able to change various light properties:<br>' +
'<b>Power</b> - Turn the selected lights on/off<br>' +
'<b>Brightness</b> - The brightness level of the selected lights<br>' +
'<b>Color</b> - The color of the selected lights<br>' +
'<b>Strobe</b> - Selected lights will flash in sequential order<br>' +
'<b>Colorloop</b> - Selected lights will slowly cycle through all the colors<br>'
},
{
element: '#active-lights',
intro: 'These icons represent the hue lights in your system. Active lights will be controlled by the application while the inactive lights will have a red X over them and will not be controlled.<br>' +
'You may toggle a light\'s state by clicking on it.'
},
{
element: $('#navigation .ember-basic-dropdown-trigger')[0],
intro: 'A few miscellaneous settings can be found here.<br><br>' +
'<b>WARNING</b>: clearing application settings will restore the application to its original state. This will even delete your playlist and any saved song beat preferences.'
},
{
intro: 'And that\'s it...Hope you enjoy the application. ;)'
}
]
});
intro.onexit(() => {
$('body').velocity('scroll', { duration: 200 });
});
intro.onchange((element) => {
if (element.id === '' || element.id === 'music-tab' || element.id === 'playlist' || element.id === 'player-area' || element.id === 'beat-option-row' || element.id === 'beat-option-button-group' || element.id === 'beat-container' || element.id === 'using-mic-audio-tooltip' || element.nodeName === 'MD-MENU') {
$('.navigation-item').eq(1).click();
} else {
$('.navigation-item').eq(0).click();
}
if (element.id === 'music-tab' || element.id === 'playlist' || element.id === 'player-area') {
playerBottom.hide();
} else if (element.id === 'beat-option-row' || element.id === 'beat-option-button-group' || element.id === 'beat-container') {
playerBottom.show();
} else if (element.id === 'dimmer') {
$(document).click();
}
});
// skip hidden/missing elements
intro.onafterchange((element) => {
let elem = $(element);
if (elem.html() === '<!---->') {
$('.introjs-nextbutton').click();
}
if (element.id === '') {
later(this, () => {
$('body').velocity('scroll');
}, 500);
} else {
later(this, () => {
$('.introjs-tooltip').velocity('scroll', { offset: -100 });
}, 500);
}
}).start();
} }
} }
}); });

View file

@ -11,23 +11,19 @@
{{/paper-button}} {{/paper-button}}
{{/menu.trigger}} {{/menu.trigger}}
{{#menu.content width=3 as |content|}} {{#menu.content width=3 as |content|}}
{{#content.menu-item onClick="toggleDimmer"}} {{#content.menu-item onClick="toggleDimmer" }}
{{paper-icon "highlight" class=dimmerOnClass}} Dark Mode: <strong>{{if dimmerOn "On" "Off"}}</strong> {{paper-icon "highlight" class=dimmerOnClass}} Dark Mode: <strong>{{if dimmerOn "On" "Off"}}</strong>
{{/content.menu-item}} {{/content.menu-item}}
{{#content.menu-item onClick="toggleLightsIcons"}} {{#content.menu-item onClick="toggleLightsIcons" }}
{{paper-icon "lightbulb outline" class=dimmerOnClass}} Active Lights: <strong>{{if lightsIconsOn "Icons" "Text"}}</strong> {{paper-icon "lightbulb outline" class=dimmerOnClass}} Active Lights: <strong>{{if lightsIconsOn "Icons" "Text"}}</strong>
{{/content.menu-item}} {{/content.menu-item}}
{{#content.menu-item onClick="clearBridge"}} {{#content.menu-item onClick="clearBridge" }}
{{paper-icon "compare arrows" class=dimmerOnClass}} Switch bridge {{paper-icon "compare arrows" class=dimmerOnClass}} Switch bridge
{{/content.menu-item}} {{/content.menu-item}}
{{#content.menu-item onClick="startIntro"}} {{#content.menu-item onClick="clearAllSettings" }}
{{paper-icon "cached" class=dimmerOnClass}} Restart tutorial
{{/content.menu-item}}
{{#content.menu-item onClick="clearAllSettings"}}
{{paper-icon "settings backup restore" class=dimmerOnClass}} Reset settings {{paper-icon "settings backup restore" class=dimmerOnClass}} Reset settings
{{/content.menu-item}} {{/content.menu-item}}
{{/menu.content}} {{/menu.content}}
@ -35,12 +31,13 @@
</div> </div>
</div> </div>
{{light-group lightsData=lightsData activeLights=activeLights syncLight=syncLight apiURL=apiURL dimmerOn=dimmerOn lightsIconsOn=lightsIconsOn storage=storage}} {{light-group lightsData=lightsData activeLights=activeLights syncLight=syncLight apiURL=apiURL dimmerOn=dimmerOn lightsIconsOn=lightsIconsOn}}
<div id="huegasm-content" class="row"> <div id="huegasm-content" class="row">
{{lights-tab active=(eq selectedTab 0) apiURL=apiURL lightsData=lightsData activeLights=activeLights syncLight=syncLight trial=trial colorLoopOn=colorLoopOn dimmerOn=dimmerOn playing=playing pauseLightUpdates=pauseLightUpdates}} {{lights-tab active=(eq selectedTab 0) apiURL=apiURL lightsData=lightsData activeLights=activeLights syncLight=syncLight
trial=trial colorLoopOn=colorLoopOn dimmerOn=dimmerOn playing=playing pauseLightUpdates=pauseLightUpdates}} {{music-tab
{{music-tab active=(eq selectedTab 1) apiURL=apiURL lightsData=lightsData activeLights=activeLights pauseLightUpdates=pauseLightUpdates dimmerOn=dimmerOn storage=storage colorLoopOn=colorLoopOn playing=playing action="startIntro"}} active=(eq selectedTab 1) apiURL=apiURL lightsData=lightsData activeLights=activeLights pauseLightUpdates=pauseLightUpdates
dimmerOn=dimmerOn colorLoopOn=colorLoopOn playing=playing action="startIntro"}}
</div> </div>
{{else}} {{else}}
{{paper-progress-circular diameter=100}} {{paper-progress-circular diameter=100}}

View file

@ -15,12 +15,10 @@ export default Component.extend({
init() { init() {
this._super(...arguments); this._super(...arguments);
let storage = this.get('storage'); if (!isEmpty(chrome.storage.local.get('huegasm.bridgeIp')) && !isEmpty(chrome.storage.local.get('huegasm.bridgeUsername'))) {
if (!isEmpty(storage.get('huegasm.bridgeIp')) && !isEmpty(storage.get('huegasm.bridgeUsername'))) {
this.setProperties({ this.setProperties({
bridgeIp: storage.get('huegasm.bridgeIp'), bridgeIp: chrome.storage.local.get('huegasm.bridgeIp'),
bridgeUsername: storage.get('huegasm.bridgeUsername') bridgeUsername: chrome.storage.local.get('huegasm.bridgeUsername')
}); });
} }
}, },

View file

@ -1,6 +1,6 @@
{{#if bridgeUsername}} {{#if bridgeUsername}}
{{hue-controls bridgeIp=bridgeIp bridgeUsername=bridgeUsername trial=trial dimmerOn=dimmerOn lightsIconsOn=lightsIconsOn {{hue-controls bridgeIp=bridgeIp bridgeUsername=bridgeUsername trial=trial dimmerOn=dimmerOn lightsIconsOn=lightsIconsOn
storage=storage toggleDimmer="toggleDimmer" toggleLightsIcons="toggleLightsIcons"}} toggleDimmer="toggleDimmer" toggleLightsIcons="toggleLightsIcons"}}
{{else}} {{else}}
{{bridge-finder bridgeIp=bridgeIp bridgeUsername=bridgeUsername trial=trial storage=storage}} {{bridge-finder bridgeIp=bridgeIp bridgeUsername=bridgeUsername trial=trial}}
{{/if}} {{/if}}

View file

@ -1,21 +0,0 @@
import Ember from 'ember';
const {
Component,
computed
} = Ember;
export default Component.extend({
tagName: 'footer',
classNames: ['footer'],
year: computed(function(){
return new Date().getFullYear();
}),
actions: {
toggleDimmer(){
this.sendAction();
}
}
});

View file

@ -1,13 +0,0 @@
<div class="logo" {{action "toggleDimmer"}}></div>
<div class="footer-text">
© {{year}}
<a href="http://www.egorphilippov.me" target="_blank" rel="noopener noreferrer">
Egor Philippov
</a>
</div>
<a href="https://play.google.com/store/apps/details?id=com.hoboman313.huegasm" target="_blank" rel="noopener noreferrer">
<img src="assets/images/google-play-badge.png" alt="Get it on the Google Play Store">
</a>

View file

@ -17,7 +17,7 @@ export default Component.extend({
activeLights: A(), activeLights: A(),
// list of all the lights in the hue system // list of all the lights in the hue system
lightsList: computed('lightsData', 'activeLights.[]', 'dimmerOn', function(){ lightsList: computed('lightsData', 'activeLights.[]', 'dimmerOn', function () {
let lightsData = this.get('lightsData'), let lightsData = this.get('lightsData'),
activeLights = this.get('activeLights'), activeLights = this.get('activeLights'),
dimmerOn = this.get('dimmerOn'), dimmerOn = this.get('dimmerOn'),
@ -29,7 +29,7 @@ export default Component.extend({
activeClass = 'light-active'; activeClass = 'light-active';
if (lightsData.hasOwnProperty(key) && lightsData[key].state.reachable) { if (lightsData.hasOwnProperty(key) && lightsData[key].state.reachable) {
switch(lightsData[key].modelid){ switch (lightsData[key].modelid) {
case 'LCT001': case 'LCT001':
type = 'a19'; type = 'a19';
break; break;
@ -61,7 +61,7 @@ export default Component.extend({
type = 'storylight'; type = 'storylight';
break; break;
case 'LWB004': case 'LWB004':
type ='a19'; type = 'a19';
break; break;
case 'LLC020': case 'LLC020':
type = 'huego'; type = 'huego';
@ -70,34 +70,34 @@ export default Component.extend({
type = 'a19'; type = 'a19';
} }
if(dimmerOn){ if (dimmerOn) {
type += 'w'; type += 'w';
} }
if(!activeLights.includes(key)){ if (!activeLights.includes(key)) {
activeClass = 'light-inactive'; activeClass = 'light-inactive';
} }
lightsList.push({type: type, name: lightsData[key].name, id: key, data: lightsData[key], activeClass: activeClass}); lightsList.push({ type: type, name: lightsData[key].name, id: key, data: lightsData[key], activeClass: activeClass });
} }
} }
return lightsList; return lightsList;
}), }),
onActiveLightsChange: observer('activeLights.[]', function(){ onActiveLightsChange: observer('activeLights.[]', function () {
this.get('storage').set('huegasm.activeLights', this.get('activeLights')); chrome.storage.local.set('huegasm.activeLights', this.get('activeLights'));
}), }),
init(){ init() {
this._super(...arguments); this._super(...arguments);
let lightsData = this.get('lightsData'), let lightsData = this.get('lightsData'),
activeLights = this.get('activeLights'), activeLights = this.get('activeLights'),
activeLightsCache = this.get('storage').get('huegasm.activeLights'); activeLightsCache = chrome.storage.local.get('huegasm.activeLights');
if(!isNone(activeLightsCache)){ if (!isNone(activeLightsCache)) {
activeLightsCache.forEach(function(i){ activeLightsCache.forEach(function (i) {
if (!isNone(lightsData) && lightsData.hasOwnProperty(i) && lightsData[i].state.reachable) { if (!isNone(lightsData) && lightsData.hasOwnProperty(i) && lightsData[i].state.reachable) {
activeLights.pushObject(i); activeLights.pushObject(i);
} }
@ -112,26 +112,26 @@ export default Component.extend({
}, },
actions: { actions: {
clickLight(id){ clickLight(id) {
let activeLights = this.get('activeLights'), let activeLights = this.get('activeLights'),
lightId = activeLights.indexOf(id); lightId = activeLights.indexOf(id);
if(lightId !== -1){ if (lightId !== -1) {
activeLights.removeObject(id); activeLights.removeObject(id);
} else { } else {
activeLights.pushObject(id); activeLights.pushObject(id);
this.set('syncLight', id); this.set('syncLight', id);
} }
}, },
lightStartHover(id){ lightStartHover(id) {
if(!window.matchMedia || (window.matchMedia("(min-width: 768px)").matches)){ if (!window.matchMedia || (window.matchMedia("(min-width: 768px)").matches)) {
let hoveredLight = this.get('lightsList').filter(function(light){ let hoveredLight = this.get('lightsList').filter(function (light) {
return light.activeClass !== 'unreachable' && light.id === id[0]; return light.activeClass !== 'unreachable' && light.id === id[0];
}); });
if(!isEmpty(hoveredLight) && this.get('noHover') !== true){ if (!isEmpty(hoveredLight) && this.get('noHover') !== true) {
$.ajax(this.get('apiURL') + '/lights/' + id + '/state', { $.ajax(this.get('apiURL') + '/lights/' + id + '/state', {
data: JSON.stringify({"alert": "lselect"}), data: JSON.stringify({ "alert": "lselect" }),
contentType: 'application/json', contentType: 'application/json',
type: 'PUT' type: 'PUT'
}); });
@ -140,15 +140,15 @@ export default Component.extend({
this.set('isHovering', true); this.set('isHovering', true);
} }
}, },
lightStopHover(id){ lightStopHover(id) {
if(!window.matchMedia || (window.matchMedia("(min-width: 768px)").matches)){ if (!window.matchMedia || (window.matchMedia("(min-width: 768px)").matches)) {
let hoveredLight = this.get('lightsList').filter(function(light){ let hoveredLight = this.get('lightsList').filter(function (light) {
return light.activeClass !== 'unreachable' && light.id === id[0]; return light.activeClass !== 'unreachable' && light.id === id[0];
}); });
if(!isEmpty(hoveredLight) && this.get('noHover') !== true){ if (!isEmpty(hoveredLight) && this.get('noHover') !== true) {
$.ajax(this.get('apiURL') + '/lights/' + id + '/state', { $.ajax(this.get('apiURL') + '/lights/' + id + '/state', {
data: JSON.stringify({"alert": "none"}), data: JSON.stringify({ "alert": "none" }),
contentType: 'application/json', contentType: 'application/json',
type: 'PUT' type: 'PUT'
}); });

View file

@ -1,46 +0,0 @@
import Ember from 'ember';
const {
Component,
observer,
computed,
isEmpty,
isNone,
run: { later },
$
} = Ember;
export default Component.extend({
url: null,
onIsShowingModalChange: observer('isShowingModal', function(){
if(this.get('isShowingModal')){
this.set('url', null);
later(function(){
$('md-input-container input').focus();
}, 500);
}
}),
saveDisabled: computed('url', function(){
return isNone(this.get('url')) || isEmpty(this.get('url').trim());
}),
didInsertElement: function() {
$(document).keypress((event)=>{
if(!this.get('saveDisabled') && event.which === 13) {
this.send('add');
}
});
},
actions: {
close () {
this.sendAction();
},
add (){
this.sendAction('action', this.get('url'));
}
}
});

View file

@ -1,14 +0,0 @@
{{#if isShowingModal}}
{{#modal-dialog close="close" alignment="center" translucentOverlay=true attachment="center" targetAttachment="center"}}
<p>Enter a <a href="https://soundcloud.com" target="_blank" rel="noopener noreferrer">SoundCloud</a> track or playlist/set URL</p>
<p>( ex. https://soundcloud.com/mrsuicidesheep/tracks )</p>
{{paper-input label="SoundCloud URL" icon="search" value=url onChange=(action (mut url))}}
<div>
{{paper-button onClick=(action "close") label="Close"}}
{{paper-button class="pull-right" onClick=(action "add") disabled=saveDisabled primary=true label="Add Music"}}
</div>
{{/modal-dialog}}
{{/if}}

View file

@ -1,118 +1,128 @@
import Ember from 'ember'; import Ember from 'ember';
import helperMixin from './mixins/helpers';
import visualizerMixin from './mixins/visualizer';
const { const {
A,
Component, Component,
observer, observer,
isEmpty, isEmpty,
isNone, isNone,
$, $,
inject: { service },
run: { later, next } run: { later, next }
} = Ember; } = Ember;
export default Component.extend(helperMixin, visualizerMixin, { export default Component.extend({
updatePageTitle: observer('playQueuePointer', function () { classNames: ['col-sm-10', 'col-sm-offset-1', 'col-xs-12'],
let title = 'Huegasm', classNameBindings: ['active::hidden'],
playQueuePointer = this.get('playQueuePointer'), elementId: 'music-tab',
playQueue = this.get('playQueue');
if (playQueuePointer !== -1) { dancer: null,
let song = playQueue[playQueuePointer];
if (song.title) {
title = song.title;
if (song.artist) { notify: service(),
title += (' - ' + song.artist);
} beatOptions: {
threshold: {
range: { min: 0, max: 0.5 },
step: 0.01,
defaultValue: 0.3,
pips: {
mode: 'values',
values: [0, 0.25, 0.5],
density: 10,
format: {
to: function (value) {
if (value === 0) {
value = 'More';
} else if (value === 0.25) {
value = '';
} else { } else {
title = song.fileName; value = 'Less';
} }
title += '- Huegasm'; return value;
},
from: function (value) { return value; }
}
}
},
hueRange: {
range: { min: 0, max: 65535 },
step: 1,
defaultValue: 0.3,
pips: {
mode: 'values',
values: [0, 25500, 46920, 65535],
density: 10,
format: {
to: function (value) {
if (value === 0 || value === 65535) {
value = 'Red';
} else if (value === 25500) {
value = 'Green';
} else {
value = 'Blue';
} }
document.title = title; return value;
}), },
from: function (value) { return value; }
}
}
},
brightnessRange: {
range: { min: 1, max: 254 },
step: 1,
defaultValue: 0,
pips: {
mode: 'values',
values: [1, 50, 100, 150, 200, 254],
density: 10,
format: {
to: function (value) { return value; },
from: function (value) { return value; }
}
}
}
},
changePlayerControl(name, value, saveBeatPrefs) { threshold: 0.3,
hueRange: [0, 65535],
brightnessRange: [1, 254],
oldThreshold: null,
lastLightBopIndex: 0,
playerBottomDisplayed: true,
audioStream: null,
dimmerOn: false,
colorloopMode: false,
flashingTransitions: false,
// 0 - no repeat, 1 - repeat all, 2 - repeat one
repeat: 0,
shuffle: false,
volumeMuted: false,
volume: 100,
// beat detection related pausing
paused: false,
songBeatPreferences: {},
usingBeatPreferences: false,
oldBeatPrefCache: null,
firstVisit: true,
// noUiSlider connection specification
filledConnect: [true, false],
hueRangeConnect: [false, true, false],
changePlayerControl(name, value) {
this.set(name, value); this.set(name, value);
if (name === 'threshold') { if (name === 'threshold') {
this.get('kick').set({ threshold: value }); this.get('kick').set({ threshold: value });
} }
if (saveBeatPrefs && this.get('playQueuePointer') !== -1) { chrome.storage.local.set('huegasm.' + name, value);
this.saveSongBeatPreferences();
}
this.get('storage').set('huegasm.' + name, value);
},
saveSongBeatPreferences() {
let song = this.get('playQueue')[this.get('playQueuePointer')];
if (song) {
let title = isEmpty(song.artist) ? song.fileName : song.artist + '-' + song.title,
songBeatPreferences = this.get('songBeatPreferences');
songBeatPreferences[title] = { threshold: this.get('threshold') };
this.set('usingBeatPreferences', true);
this.get('storage').set('huegasm.songBeatPreferences', songBeatPreferences);
}
},
loadSongBeatPreferences() {
let song = this.get('playQueue')[this.get('playQueuePointer')],
title = isEmpty(song.artist) ? song.fileName : song.artist + '-' + song.title,
songBeatPreferences = this.get('songBeatPreferences'),
preference = songBeatPreferences[title],
oldBeatPrefCache = this.get('oldBeatPrefCache'),
newOldBeatPrefCache = null;
if (!isNone(preference)) { // load existing beat prefs
newOldBeatPrefCache = { threshold: this.get('threshold') };
this.changePlayerControl('threshold', preference.threshold);
this.set('usingBeatPreferences', true);
} else if (!isNone(oldBeatPrefCache)) { // revert to using beat prefs before the remembered song
this.changePlayerControl('threshold', oldBeatPrefCache.threshold);
this.set('usingBeatPreferences', false);
}
this.set('oldBeatPrefCache', newOldBeatPrefCache);
},
clearCurrentAudio(resetPointer) {
let dancer = this.get('dancer');
if (dancer.audio.pause) {
dancer.pause();
}
if (resetPointer) {
this.set('playQueuePointer', -1);
}
this.setProperties({
timeElapsed: 0,
timeTotal: 0,
playing: false
});
},
dragOver() {
let dragLeaveTimeoutHandle = this.get('dragLeaveTimeoutHandle');
this.set('dragging', true);
if (dragLeaveTimeoutHandle) {
clearTimeout(dragLeaveTimeoutHandle);
}
},
dragLeave() {
// need to delay the dragLeave notification to avoid flickering ( hovering over some page elements causes this event to be sent )
this.set('dragLeaveTimeoutHandle', setTimeout(() => { this.set('dragging', false); }, 500));
}, },
simulateKick(/*mag, ratioKickMag*/) { simulateKick(/*mag, ratioKickMag*/) {
@ -196,7 +206,6 @@ export default Component.extend(helperMixin, visualizerMixin, {
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
let dancer = new Dancer(), let dancer = new Dancer(),
storage = this.get('storage'),
kick = dancer.createKick({ kick = dancer.createKick({
threshold: this.get('threshold'), threshold: this.get('threshold'),
onKick: (mag, ratioKickMag) => { onKick: (mag, ratioKickMag) => {
@ -213,9 +222,9 @@ export default Component.extend(helperMixin, visualizerMixin, {
kick: kick kick: kick
}); });
['volume', 'shuffle', 'repeat', 'volumeMuted', 'threshold', 'playerBottomDisplayed', 'songBeatPreferences', 'firstVisit', 'currentVisName', 'playQueue', 'playQueuePointer', 'flashingTransitions', 'colorloopMode', 'hueRange', 'brightnessRange'].forEach((item) => { ['threshold', 'playerBottomDisplayed', 'flashingTransitions', 'colorloopMode', 'hueRange', 'brightnessRange'].forEach((item) => {
if (!isNone(storage.get('huegasm.' + item))) { if (!isNone(chrome.storage.local.get('huegasm.' + item))) {
let itemVal = storage.get('huegasm.' + item); let itemVal = chrome.storage.local.get('huegasm.' + item);
if (isNone(this.actions[item + 'Changed'])) { if (isNone(this.actions[item + 'Changed'])) {
this.set(item, itemVal); this.set(item, itemVal);
@ -224,12 +233,6 @@ export default Component.extend(helperMixin, visualizerMixin, {
} }
} }
}); });
this.set('oldPlayQueueLength', this.get('playQueue.length'));
SC.initialize({
client_id: this.get('SC_CLIENT_ID')
});
}, },
didInsertElement() { didInsertElement() {
@ -237,423 +240,23 @@ export default Component.extend(helperMixin, visualizerMixin, {
let self = this; let self = this;
// file input code
$('#file-input').on('change', function () {
let files = this.files;
self.send('handleNewFiles', files);
this.value = null; // reset in case upload the second file again
});
$(document).on('click', '.alert', (event) => {
$(event.target).addClass('removed');
});
// prevent space/text selection when the user repeatedly clicks on the center // prevent space/text selection when the user repeatedly clicks on the center
$('#beat-container').on('mousedown', '#beat-speaker-center-inner', function (event) { $('#beat-container').on('mousedown', '#beat-speaker-center-inner', function (event) {
event.preventDefault(); event.preventDefault();
}); });
$(document).keypress((event) => {
if (event.which === 32 && event.target.type !== 'text') {
this.send('play');
}
});
this.$().on('drop', '#play-list-area', (event) => {
this.send('dropFiles', event.dataTransfer.files);
});
// control the volume by scrolling up/down
$('#player-area').on('mousewheel', (event) => {
if (this.get('playQueueNotEmpty')) {
let scrollSize = 5;
if (event.deltaY < 0) {
scrollSize *= -1;
}
let newVolume = this.get('volume') + scrollSize;
this.send('volumeChanged', newVolume < 0 ? 0 : newVolume);
event.preventDefault();
}
});
// demo tracks
if (this.get('firstVisit')) {
this.send('handleNewSoundCloudURL', 'https://soundcloud.com/mrsuicidesheep/candyland-speechless-feat-rkcb');
this.send('handleNewSoundCloudURL', 'https://soundcloud.com/dillistone/dillistone-lili-n-rude');
this.send('handleNewSoundCloudURL', 'https://soundcloud.com/mrsuicidesheep/vallis-alps-young-feki-remix');
this.send('handleNewSoundCloudURL', 'https://soundcloud.com/mrsuicidesheep/andrew-luce-when-to-love-you-feat-chelsea-cutler');
this.send('handleNewSoundCloudURL', 'https://soundcloud.com/mrsuicidesheep/ahh-ooh-carefree-with-me');
this.send('handleNewSoundCloudURL', 'https://soundcloud.com/mrsuicidesheep/crywolf-slow-burn');
this.send('handleNewSoundCloudURL', 'https://soundcloud.com/mrsuicidesheep/clozee-red-forest');
this.send('handleNewSoundCloudURL', 'https://soundcloud.com/mrsuicidesheep/elo-method-subranger-solace');
this.send('handleNewSoundCloudURL', 'https://soundcloud.com/mrsuicidesheep/90-pounds-of-pete-waited-too-long-feat-devon-baldwin');
this.send('handleNewSoundCloudURL', 'https://soundcloud.com/mrsuicidesheep/draper-eyes-open');
this.send('handleNewSoundCloudURL', 'https://soundcloud.com/itspapaya/sunny');
this.send('handleNewSoundCloudURL', 'https://soundcloud.com/stonesthrow/nxworries-anderson-paak-knxwledge-suede');
this.get('storage').set('huegasm.firstVisit', false);
this.sendAction();
}
if (!this.get('playerBottomDisplayed')) { if (!this.get('playerBottomDisplayed')) {
$('#player-bottom').hide(); $('#player-bottom').hide();
} }
}, },
actions: { actions: {
clearPlaylist() {
this.get('playQueue').clear();
},
setVisName(name) {
this.set('currentVisName', name);
},
hideTooltip() {
$('.bootstrap-tooltip').tooltip('hide');
},
gotoSCURL(URL) {
// need to pause the music since soundcloud is going to start playing this song anyways
if (this.get('playing')) {
this.send('play');
}
this.send('gotoURL', URL);
},
gotoURL(URL) {
$('.tooltip').remove();
window.open(URL, '_blank');
},
handleNewSoundCloudURL(URL) {
if (URL) {
SC.resolve(URL).then((resultObj) => {
let processResult = (result) => {
if (result.kind === 'user') {
this.get('notify').alert({ html: this.get('scUserNotSupportedHtml') });
} else if (result.kind === 'track') {
if (result.streamable === true) {
let picture = null;
if (result.artwork_url) {
picture = result.artwork_url.replace('large', 't67x67');
} else if (result.user.avatar_url) {
picture = result.user.avatar_url;
}
$.get(picture)
.done(() => {
this.get('playQueue').pushObject({ url: result.stream_url + '?client_id=' + this.get('SC_CLIENT_ID'), fileName: result.title + ' - ' + result.user.username, artist: result.user.username, scUrl: result.permalink_url, title: result.title, picture: picture });
}).fail(() => { // no picture
this.get('playQueue').pushObject({ url: result.stream_url + '?client_id=' + this.get('SC_CLIENT_ID'), fileName: result.title + ' - ' + result.user.username, artist: result.user.username, scUrl: result.permalink_url, title: result.title });
});
} else {
failedSongs.push(result.title);
}
} else if (result.kind === 'playlist') {
if (result.streamable === true) {
result.tracks.forEach(processResult);
} else {
failedSongs.push(result.title);
}
}
},
failedSongs = [];
if (resultObj instanceof Array) {
resultObj.forEach(processResult);
} else {
processResult(resultObj);
}
if (failedSongs.length > 0) {
this.get('notify').alert({ html: this.get('notStreamableHtml')(failedSongs) });
}
if (this.get('playQueuePointer') === -1) {
if (this.get('firstVisit')) {
this.send('goToSong', 0);
} else {
this.send('next');
}
}
}, () => {
this.get('notify').alert({ html: this.get('urlNotFoundHtml')(URL) });
});
}
this.set('isShowingAddSoundCloudModal', false);
},
toggleIsShowingAddSoundCloudModal() {
this.toggleProperty('isShowingAddSoundCloudModal');
},
slideTogglePlayerBottom() { slideTogglePlayerBottom() {
let elem = this.$('#player-bottom'); let elem = this.$('#player-bottom');
elem.velocity(elem.is(':visible') ? 'slideUp' : 'slideDown', { duration: 300 }); elem.velocity(elem.is(':visible') ? 'slideUp' : 'slideDown', { duration: 300 });
this.changePlayerControl('playerBottomDisplayed', !this.get('playerBottomDisplayed')); this.changePlayerControl('playerBottomDisplayed', !this.get('playerBottomDisplayed'));
}, },
goToSong(index, playSong, scrollToSong) {
let dancer = this.get('dancer'), playQueue = this.get('playQueue');
if (dancer.audio) {
this.clearCurrentAudio(true);
}
if (!isNone(playQueue[index])) {
let audio = new Audio();
audio.src = this.get('playQueue')[index].url;
audio.crossOrigin = "anonymous";
audio.oncanplay = () => {
this.set('timeTotal', Math.floor(audio.duration));
this.set('soundCloudFuckUps', 0);
};
audio.onerror = (event) => {
let playQueuePointer = this.get('playQueuePointer'),
song = this.get('playQueue')[playQueuePointer];
if (this.get('soundCloudFuckUps') >= this.get('maxSoundCloudFuckUps')) {
this.get('notify').alert({ html: this.get('tooManySoundCloudFuckUps') });
this.send('play');
this.set('soundCloudFuckUps', 0);
} else {
if (song.local) {
this.send('removeAudio', playQueuePointer);
} else {
this.send('next', true);
}
if (event.target.error.code === 2) {
this.get('notify').alert({ html: this.get('failedToDecodeFileHtml')(song.fileName) });
} else {
this.get('notify').alert({ html: this.get('failedToPlayFileHtml')(song.fileName) });
}
this.set('usingBeatPreferences', false);
this.incrementProperty('soundCloudFuckUps');
}
};
audio.ontimeupdate = () => {
this.set('timeElapsed', Math.floor(audio.currentTime));
};
audio.onended = () => {
this.send('next');
};
dancer.load(audio, 1);
this.set('playQueuePointer', index);
this.loadSongBeatPreferences();
if (playSong) {
this.send('play');
}
if (scrollToSong) {
// this is just a bad workaround to make sure that the track has been rendered to the playlist
next(this, () => {
$('.track' + index).velocity('scroll', { container: $('#play-list-area'), duration: 200 });
});
}
}
},
removeAudio(index) {
this.get('playQueue').removeAt(index);
// need to manually remove the tooltip
$('body .tooltip').remove();
if (index === this.get('playQueuePointer')) {
this.send('goToSong', index, true, true);
}
},
playerAreaPlay() {
if (isEmpty($('#player-controls:hover')) && this.get('playQueuePointer') !== -1) {
this.send('play');
$('#play-notification').velocity({ opacity: 0.8, scale: 1 }, 0).velocity({ opacity: 0, scale: 3 }, 500);
}
},
play(replayPause) {
let dancer = this.get('dancer'),
playQueuePointer = this.get('playQueuePointer'),
playing = this.get('playing'),
lightsData = this.get('lightsData');
if (playQueuePointer !== -1) {
if (playing) {
dancer.pause();
let preMusicLightsDataCache = this.get('preMusicLightsDataCache'),
updateLight = (lightIndex) => {
$.ajax(this.get('apiURL') + '/lights/' + lightIndex + '/state', {
data: JSON.stringify({
'on': preMusicLightsDataCache[lightIndex].state.on,
'hue': preMusicLightsDataCache[lightIndex].state.hue,
'bri': preMusicLightsDataCache[lightIndex].state.bri
}),
contentType: 'application/json',
type: 'PUT'
});
};
for (let key in lightsData) {
if (lightsData.hasOwnProperty(key)) {
later(this, updateLight, key, 1000);
}
}
if (!replayPause) {
this.set('timeElapsed', Math.floor(dancer.getTime()));
}
} else {
let timeTotal = this.get('timeTotal');
if (this.get('volumeMuted')) {
dancer.setVolume(0);
} else {
dancer.setVolume(this.get('volume') / 100);
}
// replay song
if (this.get('timeElapsed') === timeTotal && timeTotal !== 0) {
this.send('next', true);
return;
}
$(window).trigger('resize'); // workaround to redraw the canvas for the vitualizer
this.set('preMusicLightsDataCache', lightsData);
dancer.play();
}
this.set('pauseLightUpdates', !playing);
this.onColorloopModeChange();
this.toggleProperty('playing');
}
},
volumeChanged(value) {
this.changePlayerControl('volume', value);
if (this.get('playing')) {
this.get('dancer').setVolume(value / 100);
}
if (this.get('volume') > 0 && this.get('volumeMuted')) {
this.changePlayerControl('volumeMuted', false);
}
},
next(repeatAll) {
let playQueuePointer = this.get('playQueuePointer'),
playQueue = this.get('playQueue'),
nextSong = (playQueuePointer + 1),
repeat = this.get('repeat'),
shuffle = this.get('shuffle');
if (repeat === 2) { // repeating one song takes precedence over shuffling
if (playQueuePointer === -1 && playQueue.length > 0) {
nextSong = 0;
} else {
nextSong = playQueuePointer;
}
} else if (shuffle) { // next shuffle song
let shufflePlayed = this.get('shufflePlayed');
// played all the song in shuffle mode
if (shufflePlayed.length === playQueue.length) {
shufflePlayed.clear();
this.send('play', true);
return;
}
// we're going to assume that the song URL is the id
do {
nextSong = Math.floor(Math.random() * playQueue.length);
} while (shufflePlayed.includes(playQueue[nextSong].url));
shufflePlayed.pushObject(playQueue[nextSong].url);
} else if (nextSong > playQueue.length - 1) {
if (repeat === 1 || repeatAll) {
nextSong = nextSong % playQueue.length;
} else {
this.send('play', true);
return;
}
}
this.send('goToSong', nextSong, true, true);
},
previous() {
if (this.get('timeElapsed') > 5) {
this.send('seekChanged', 0);
} else {
let nextSong = this.get('playQueuePointer'),
playQueue = this.get('playQueue');
if (this.get('shuffle') && !isNone(playQueue[nextSong])) { // go to the previously shuffled song
let shufflePlayed = this.get('shufflePlayed'),
shuffledSongIndx = this.get('shufflePlayed').indexOf(playQueue[nextSong].url),
i = 0;
if (shufflePlayed.length > 0 && shuffledSongIndx !== -1) { // only if there was one
nextSong = shuffledSongIndx - 1;
if (nextSong < 0) {
nextSong = shufflePlayed.length - 1;
}
playQueue.some(function (item) { // try to find the previous song id
if (item.url === shufflePlayed[nextSong]) {
nextSong = i;
return true;
}
i++;
return false;
});
}
} else {
nextSong--;
if (nextSong < 0) {
nextSong = playQueue.length - 1;
}
}
this.send('goToSong', nextSong, true, true);
}
},
seekChanged(position) {
let dancer = this.get('dancer');
if (dancer.audio) {
dancer.audio.currentTime = Math.floor(this.get('timeTotal') * position / 100);
}
},
volumeMutedChanged(value) {
let dancer = this.get('dancer'),
volumeMuted = isNone(value) ? !this.get('volumeMuted') : value;
this.changePlayerControl('volumeMuted', volumeMuted);
if (this.get('playing')) {
if (volumeMuted) {
dancer.setVolume(0);
} else {
dancer.setVolume(this.get('volume') / 100);
}
}
},
addLocalAudio: function () {
$('#file-input').click();
},
shuffleChanged(value) {
this.changePlayerControl('shuffle', isNone(value) ? !this.get('shuffle') : value);
},
repeatChanged(value) {
this.changePlayerControl('repeat', isNone(value) ? (this.get('repeat') + 1) % 3 : value);
},
playerBottomDisplayedChanged(value) { playerBottomDisplayedChanged(value) {
this.changePlayerControl('playerBottomDisplayed', value); this.changePlayerControl('playerBottomDisplayed', value);
}, },
@ -666,70 +269,9 @@ export default Component.extend(helperMixin, visualizerMixin, {
hueRangeChanged(value) { hueRangeChanged(value) {
this.changePlayerControl('hueRange', value); this.changePlayerControl('hueRange', value);
}, },
playQueuePointerChanged(value) {
this.send('goToSong', value, false, true);
},
clickSpeaker() { clickSpeaker() {
this.simulateKick(1); this.simulateKick(1);
}, },
dropFiles(files) {
this.setProperties({
dragging: false,
draggingOverPlayListArea: false
});
this.send('handleNewFiles', files);
},
playerListAreaDragOver() {
this.set('draggingOverPlayListArea', true);
},
playerListAreaDragLeave() {
this.set('draggingOverPlayListArea', false);
},
handleNewFiles(files) {
let self = this,
playQueue = this.get('playQueue'),
updatePlayQueue = function () {
let tags = ID3.getAllTags("local"),
picture = null;
if (tags.picture) {
let base64String = "";
for (let i = 0; i < tags.picture.data.length; i++) {
base64String += String.fromCharCode(tags.picture.data[i]);
}
picture = "data:" + tags.picture.format + ";base64," + window.btoa(base64String);
}
playQueue.pushObject({
fileName: this.name.replace(/\.[^/.]+$/, ""),
url: URL.createObjectURL(this),
artist: tags.artist,
title: tags.title,
picture: picture,
local: true
});
ID3.clearAll();
if (self.get('playQueuePointer') === -1) {
self.send('next');
}
};
for (let key in files) {
if (files.hasOwnProperty(key)) {
let file = files[key];
if (file.type.startsWith('audio')) {
ID3.loadTags("local", updatePlayQueue.bind(file), {
dataReader: new FileAPIReader(file),
tags: ['title', 'artist', 'album', 'track', 'picture']
});
}
}
}
},
toggleDimmer() { toggleDimmer() {
this.sendAction('toggleDimmer'); this.sendAction('toggleDimmer');
} }

View file

@ -1,412 +0,0 @@
import Ember from 'ember';
const {
Mixin,
observer,
computed,
isNone,
run,
$,
inject,
on,
A
} = Ember;
export default Mixin.create({
classNames: ['col-sm-10', 'col-sm-offset-1', 'col-xs-12'],
classNameBindings: ['active::hidden'],
elementId: 'music-tab',
dancer: null,
notify: inject.service(),
beatOptions: {
threshold: {
range: {min: 0, max: 0.5},
step: 0.01,
defaultValue: 0.3,
pips: {
mode: 'values',
values: [0, 0.25, 0.5],
density: 10,
format: {
to: function ( value ) {
if(value === 0) {
value = 'More';
} else if(value === 0.25) {
value = '';
} else {
value = 'Less';
}
return value;
},
from: function ( value ) { return value; }
}
}
},
hueRange: {
range: {min: 0, max: 65535},
step: 1,
defaultValue: 0.3,
pips: {
mode: 'values',
values: [0, 25500, 46920, 65535],
density: 10,
format: {
to: function ( value ) {
if(value === 0 || value === 65535) {
value = 'Red';
} else if(value === 25500 ) {
value = 'Green';
} else {
value = 'Blue';
}
return value;
},
from: function ( value ) { return value; }
}
}
},
brightnessRange: {
range: {min: 1, max: 254},
step: 1,
defaultValue: 0,
pips: {
mode: 'values',
values: [1, 50, 100, 150, 200, 254],
density: 10,
format: {
to: function ( value ) { return value; },
from: function ( value ) { return value; }
}
}
}
},
threshold: 0.3,
hueRange: [0, 65535],
brightnessRange: [1, 254],
oldThreshold: null,
playQueuePointer: -1,
playQueue: A(),
timeElapsed: 0,
timeTotal: 0,
lastLightBopIndex: 0,
playerBottomDisplayed: true,
dragging: false,
draggingOverPlayListArea: false,
dragLeaveTimeoutHandle: null,
audioStream: null,
dimmerOn: false,
isShowingAddSoundCloudModal: false,
colorloopMode: false,
flashingTransitions: false,
// 0 - no repeat, 1 - repeat all, 2 - repeat one
repeat: 0,
shuffle: false,
volumeMuted: false,
volume: 100,
// beat detection related pausing
paused: false,
// audio: playing or paused
playing: false,
songBeatPreferences: {},
usingBeatPreferences: false,
oldBeatPrefCache: null,
storage: null,
firstVisit: true,
soundCloudFuckUps: 0,
maxSoundCloudFuckUps: 3,
// used to insure that we don't replay the same thing multiple times in shuffle mode
shufflePlayed: [],
// noUiSlider connection specification
filledConnect: [true, false],
hueRangeConnect: [false, true, false],
SC_CLIENT_ID: 'aeec0034f58ecd85c2bd1deaecc41594',
scUserNotSupportedHtml: '<div class="alert alert-danger" role="alert">SoundCloud user URLs are not supported.</div>',
tooManySoundCloudFuckUps: '<div class="alert alert-danger" role="alert">The SoundCloud API is not seving the audio properly. More details <a href="https://www.soundcloudcommunity.com/soundcloud/topics/some-soundcloud-cdn-hosted-tracks-dont-have-access-control-allow-origin-header" target="_blank" rel="noopener noreferrer">HERE</a>.</div>',
notStreamableHtml(fileNames){
let html = '<div class="alert alert-danger" role="alert">The following file(s) could not be added because they are not allowed to be streamed:<br>' + fileNames.toString().replace(/,/g, '<br>') + '</div>';
return html;
},
urlNotFoundHtml(url){
return '<div class="alert alert-danger" role="alert">The URL ( ' + url + ' ) could not be resolved.</div>';
},
failedToPlayFileHtml(fileName){
return '<div class="alert alert-danger" role="alert">Failed to play file ( ' + fileName + ' ).</div>';
},
failedToDecodeFileHtml(fileName){
return '<div class="alert alert-danger" role="alert">Failed to decode file ( ' + fileName + ' ).</div>';
},
scUrl: computed('playQueuePointer', 'playQueue.[]', function(){
let rtn = null,
currentSong = this.get('playQueue')[this.get('playQueuePointer')];
if(currentSong && currentSong.scUrl){
rtn = currentSong.scUrl;
}
return rtn;
}),
playQueueEmpty: computed.empty('playQueue'),
playQueueNotEmpty: computed.notEmpty('playQueue'),
playQueueMultiple: computed('playQueue.[]', function(){
return this.get('playQueue').length > 1;
}),
seekPosition: computed('timeElapsed', 'timeTotal', function(){
let timeTotal = this.get('timeTotal'),
timeElapsed = this.get('timeElapsed');
if (timeTotal === 0) {
return 0;
}
return timeElapsed/timeTotal*100;
}),
largeArtworkPic: computed('playQueuePointer', 'currentVisName', function(){
let pic = '',
currentVisName = this.get('currentVisName'),
playQueuePointer = this.get('playQueuePointer'),
playQueue = this.get('playQueue');
if(playQueuePointer !== -1 && currentVisName === 'None'){
let song = playQueue[playQueuePointer];
if(!isNone(song.picture)){
pic = song.picture;
if(song.scUrl){
pic = pic.replace('67x67', '500x500');
}
}
}
return pic;
}),
repeatIcon: computed('repeat', function() {
if(this.get('repeat') === 2) {
return 'repeat-one';
}
return 'repeat';
}),
playingIcon: computed('playing', function() {
if(this.get('playing')){
return 'pause';
} else if(this.get('timeElapsed') === this.get('timeTotal') && this.get('timeTotal') !== 0){
return 'replay';
} else {
return 'play-arrow';
}
}),
playerAreaClickIcon: computed('playing', function() {
if(this.get('playing')){
return 'play-arrow';
} else {
return 'pause';
}
}),
playListAreaClass: computed('dragging', 'draggingOverPlayListArea', 'dimmerOn', function(){
let classes = 'pointer';
if(this.get('dragging')){
classes += ' drag-here-highlight';
}
if(this.get('draggingOverPlayListArea')){
classes += ' dragging-over';
}
if(this.get('dimmerOn')){
classes += ' dimmerOn';
}
return classes;
}),
dimmerOnClass: computed('dimmerOn', function(){
return this.get('dimmerOn') ? 'dimmerOn' : null;
}),
volumeMutedClass: computed('volumeMuted', function(){
let classes = 'player-control-icon volumeButton';
if(this.get('volumeMuted')){
classes += ' active';
}
return classes;
}),
repeatClass: computed('repeat', function(){
return this.get('repeat') !== 0 ? 'player-control-icon active' : 'player-control-icon';
}),
shuffleClass: computed('shuffle', function(){
return this.get('shuffle') ? 'player-control-icon active' : 'player-control-icon';
}),
volumeIcon: computed('volumeMuted', 'volume', function() {
let volume = this.get('volume');
if (this.get('volumeMuted')) {
return "volume-off";
} else if (volume >= 70) {
return "volume-up";
} else if (volume > 10) {
return "volume-down";
} else {
return 'volume-mute';
}
}),
beatDetectionAreaArrowIcon: computed('playerBottomDisplayed', function(){
if(!this.get('playerBottomDisplayed')){
return 'keyboard-arrow-down';
} else {
return 'keyboard-arrow-up';
}
}),
timeElapsedTxt: computed('timeElapsed', function(){
return this.formatTime(this.get('timeElapsed'));
}),
timeTotalTxt: computed('timeTotal', function() {
return this.formatTime(this.get('timeTotal'));
}),
onPlayQueueChange: observer('playQueue.length', function(){
let playQueueLength = this.get('playQueue.length');
if(playQueueLength > this.get('oldPlayQueueLength')){
run.once(this, ()=>{
run.next(this, function() {
$(`.track${playQueueLength-1}`).velocity('scroll', { container: $('#play-list-area'), duration: 200 });
});
});
}
this.set('oldPlayQueueLength', playQueueLength);
}),
onColorloopModeChange: observer('colorloopMode', 'playing', function(){
this.set('colorLoopOn', this.get('playing') && this.get('colorloopMode'));
}),
onOptionChange: observer('flashingTransitions', 'playQueue.[]', 'playQueuePointer', 'colorloopMode', function(self, option){
option = option.replace('.[]', '');
let value = this.get(option);
// can't really save local music
if(option === 'playQueue'){
value = value.filter((song)=>{
return !song.url.startsWith('blob:');
});
}
this.get('storage').set('huegasm.' + option, value);
}),
onRepeatChange: on('init', observer('repeat', function () {
let tooltipTxt = 'Repeat all', type = 'repeat';
if (this.get(type) === 1) {
tooltipTxt = 'Repeat one';
} else if (this.get(type) === 2) {
tooltipTxt = 'Repeat off';
}
this.changeTooltipText(type, tooltipTxt);
})),
onShuffleChange: on('init', observer('shuffle', function () {
let tooltipTxt = 'Shuffle', type = 'shuffle';
if (this.get(type)) {
this.get('shufflePlayed').clear();
tooltipTxt = 'Unshuffle';
}
this.changeTooltipText(type, tooltipTxt);
})),
onVolumeMutedChange: on('init', observer('volumeMuted', function() {
let tooltipTxt = 'Mute', type = 'volumeMuted',
volumeMuted = this.get(type), dancer = this.get('dancer'),
volume=0;
if (volumeMuted) {
tooltipTxt = 'Unmute';
volume = 0;
} else {
volume = this.get('volume')/100;
}
if(this.get('playing')){
dancer.setVolume(volume);
}
this.changeTooltipText(type, tooltipTxt);
})),
onPrevChange: on('init', observer('timeElapsed', 'playQueueNotEmpty', 'playQueue.[]', function() {
if(this.get('playQueueNotEmpty')){
let tooltipTxt = 'Previous', type = 'prev';
if(this.get('timeElapsed') > 5 || this.get('playQueue').length === 1) {
tooltipTxt = 'Replay';
}
this.changeTooltipText(type, tooltipTxt);
}
})),
onPlayingChange: on('init', observer('playing', function () {
let tooltipTxt = 'Play', type = 'playing';
if (this.get(type)) {
tooltipTxt = 'Pause';
} else if(this.get('timeElapsed') === this.get('timeTotal') && this.get('timeTotal') !== 0){
tooltipTxt = 'Replay';
}
this.changeTooltipText(type, tooltipTxt);
})),
changeTooltipText(type, text) {
// change the tooltip text if it's already visible
$('#' + type + 'Tooltip + .tooltip .tooltip-inner').html(text);
//change the tooltip text for hover
$('#' + type + 'Tooltip').attr('data-original-title', text);
if(isNone(this.get(type + 'TooltipTxt'))) {
this.set(type + 'TooltipTxt', text);
}
},
formatTime(time){
return this.pad(Math.floor(time/60), 2) + ':' + this.pad(time%60, 2);
},
pad(num, size){ return ('000000000' + num).substr(-size); }
});

View file

@ -1,94 +0,0 @@
import Ember from 'ember';
const {
Mixin,
observer,
$
} = Ember;
export default Mixin.create({
currentVisName: 'None',
visNames: ['None', 'Bars', 'Wave'],
onCurrentVisNameChange: observer('currentVisName', function () {
let currentVisName = this.get('currentVisName');
if(currentVisName === 'None'){
let canvasEl = $('#visualization')[0],
ctx = canvasEl.getContext('2d');
ctx.clearRect(0, 0, canvasEl.width, canvasEl.height);
}
this.get('storage').set('huegasm.currentVisName', currentVisName);
}),
didInsertElement(){
let dancer = this.get('dancer'),
canvas = $('#visualization')[0],
playerArea = $('#player-area'),
ctx = canvas.getContext('2d'),
spacing = 2,
h = playerArea.height(), w;
canvas.height = h;
// must be done to preserver resolution so that things don't appear blurry
// note that the height is set to 400px via css so it doesn't need to be recalculated
let syncCanvasHeight = ()=>{
w = playerArea.width();
canvas.width = w;
};
syncCanvasHeight();
$(window).on('resize', syncCanvasHeight);
dancer.bind('update', () => {
let currentVisName = this.get('currentVisName'),
gradient = ctx.createLinearGradient(0, 0, 0, h),
pageHidden = document.hidden || document.msHidden || document.webkitHidden || document.mozHidden;
// dont do anything if the page is hidden or no visualization
if(currentVisName === 'None' || pageHidden || !this.get('active')){
return;
}
ctx.clearRect(0, 0, w, h);
if (currentVisName === 'Wave') {
let width = 3,
count = 1024;
gradient.addColorStop(0.6, 'white');
gradient.addColorStop(0, '#0036FA');
ctx.lineWidth = 1;
ctx.strokeStyle = gradient;
let waveform = dancer.getWaveform();
ctx.beginPath();
ctx.moveTo(0, h / 2);
for (let i = 0, l = waveform.length; i < l && i < count; i++) {
ctx.lineTo(i * ( spacing + width ), ( h / 2 ) + waveform[i] * ( h / 2 ));
}
ctx.stroke();
ctx.closePath();
} else if (currentVisName === 'Bars') {
let width = 4,
count = 128;
gradient.addColorStop(1, '#0f0');
gradient.addColorStop(0.6, '#ff0');
gradient.addColorStop(0.2, '#F12B24');
ctx.fillStyle = gradient;
let spectrum = dancer.getSpectrum();
for (let i = 0, l = spectrum.length; i < l && i < count; i++) {
ctx.fillRect(i * ( spacing + width ), h, width, -spectrum[i] * h - 60);
}
}
});
}
});

View file

@ -1,127 +1,3 @@
<div class="row" id="step1">
<div id="player-area" class="col-sm-8 col-xs-12 {{if (eq "None" currentVisName) "display-icon"}}" {{action "playerAreaPlay"}}>
<canvas id="visualization"></canvas>
<div id="artwork">
<img src={{largeArtworkPic}}>
</div>
{{paper-icon playerAreaClickIcon id="play-notification"}}
<div id="player-controls">
{{range-slider start=seekPosition min=0 max=100 connect=filledConnect id="seek-slider" on-change="seekChanged"}}
{{#if playQueueNotEmpty}}
<span data-toggle="tooltip" data-placement="top" class="bootstrap-tooltip" id="prevTooltip"
data-title={{prevTooltipTxt}} {{action "previous"}}>{{paper-icon "skip-previous" class="player-control-icon"}}</span><!--
-->{{/if}}<!--
--><span data-toggle="tooltip" data-placement="top" id="playingTooltip" class="bootstrap-tooltip"
data-title={{playingTooltipTxt}} {{action "play"}}>{{paper-icon playingIcon class="player-control-icon"}}</span><!--
-->{{#if playQueueMultiple}}<!--
--><span data-toggle="tooltip" data-placement="top" class="bootstrap-tooltip"
data-title="Next" {{action "next" true}}>{{paper-icon "skip-next" action="" class="player-control-icon"}}</span><!--
-->{{/if}}<!--
--><span data-toggle="tooltip" data-placement="top" class="bootstrap-tooltip" id="volumeMutedTooltip"
data-title={{volumeMutedTooltipTxt}} {{action "volumeMutedChanged"}}>{{paper-icon icon=volumeIcon class=volumeMutedClass}}</span><!--
-->{{range-slider start=volume min=0 max=100 connect=filledConnect on-change="volumeChanged" id="volume-bar" class="hidden-xs"}}
<div id="player-time-controls">{{timeElapsedTxt}} / {{timeTotalTxt}}</div>
{{#paper-menu as |menu|}}
{{#menu.trigger}}
{{#paper-button iconButton=true}}
{{paper-icon "remove-red-eye" class="player-control-icon"}}
{{/paper-button}}
{{/menu.trigger}}
{{#menu.content width=2 as |content|}}
{{#each visNames as |name|}}
{{#content.menu-item onClick=(action "setVisName" name)}}
{{name}}
{{#if (eq currentVisName name)}}
{{paper-icon "check" classNames=dimmerOnClass}}
{{/if}}
{{/content.menu-item}}
{{/each}}
{{/menu.content}}
{{/paper-menu}}
{{#if scUrl}}
<a href={{scUrl}} class="sound-cloud-link"{{action "gotoSCURL" scUrl}}>
<img src="assets/images/sc-white.png" id="soundcloud-logo" />
<img src="assets/images/sc-white-sm.png" id="soundcloud-logo-small" />
</a>
{{/if}}
</div>
</div>
<div id="playlist" class="col-sm-4 col-xs-12">
<input id="file-input" type="file" accept="audio/*" multiple="true"/>
<div id="play-list-controls">
{{#paper-menu as |menu|}}
{{#menu.trigger}}
{{#paper-button iconButton=false}}
{{paper-icon "playlist add" class="player-control-icon"}} <span id="add-new-music-label">Add new music</span>
{{/paper-button}}
{{/menu.trigger}}
{{#menu.content width=3 as |content|}}
{{#content.menu-item onClick="addLocalAudio"}}
{{paper-icon "attachment" class=shuffleClass}} Local file
{{/content.menu-item}}
{{#content.menu-item onClick="toggleIsShowingAddSoundCloudModal"}}
{{paper-icon "cloud" class=shuffleClass}} SoundCloud
{{/content.menu-item}}
{{/menu.content}}
{{/paper-menu}}
<span data-toggle="tooltip" data-placement="top auto" class="bootstrap-tooltip" id="shuffleTooltip" data-title={{shuffleTooltipTxt}} {{action "shuffleChanged"}}>{{paper-icon "shuffle" class=shuffleClass}}</span>
<span data-toggle="tooltip" data-placement="top auto" class="bootstrap-tooltip" id="repeatTooltip" data-title={{repeatTooltipTxt}} {{action "repeatChanged"}}>{{paper-icon repeatIcon class=repeatClass}}</span>
<span data-toggle="tooltip" data-placement="top auto" class="bootstrap-tooltip hidden-xs" data-title="Clear playlist" {{action "clearPlaylist"}}>{{paper-icon "clear-all" class="player-control-icon"}}</span>
</div>
<div id="play-list-area" class={{playListAreaClass}} {{action "addLocalAudio"}} {{action "playerListAreaDragOver" on="dragOver"}} {{action "playerListAreaDragLeave" on="dragLeave"}} {{action "dropFiles" on="drop"}}>
{{#if (or playQueueEmpty dragging)}}
<div id="dragHere">
{{#if dragging}}
Drag your music files here
{{else}}
Add your music files here
{{/if}}
</div>
{{paper-icon "library-music" class=dimmerOnClass}}
{{/if}}
{{#each playQueue as |item index|}}
<div class="playlist-item pointer track{{index}} {{if (eq index playQueuePointer) "active"}} {{if dragging "hidden"}}" {{action "goToSong" index true bubbles=false}}>
{{#if item.picture}}
<img class="album-art" src={{item.picture}}>
{{else}}
<img class="album-art" src="assets/images/missingArtwork.png">
{{/if}}
<div class="song-info">
{{#if item.title}}
<div class="song-title">{{item.title}}</div>
<div class="song-artist">
{{#if item.artistUrl}}
<a href="#" {{action "gotoURL" item.artistUrl bubbles=false}}>{{item.artist}}</a>
{{else}}
{{item.artist}}
{{/if}}
</div>
{{else}}
{{item.fileName}}
{{/if}}
</div>
<span data-toggle="tooltip" data-placement="top auto" data-title="Remove" data-container="body" class="audio-remove-button pointer bootstrap-tooltip" {{action "removeAudio" index bubbles=false}}>{{paper-icon "close" classNames="close"}}</span>
</div>
{{/each}}
</div>
</div>
</div>
<div id="slide-toggle" class="text-center pointer row" {{action "slideTogglePlayerBottom"}}> <div id="slide-toggle" class="text-center pointer row" {{action "slideTogglePlayerBottom"}}>
<div class="col-xs-offset-5 col-xs-2"> <div class="col-xs-offset-5 col-xs-2">
{{paper-icon beatDetectionAreaArrowIcon id="beat-detection-area-arrow-icon"}} {{paper-icon beatDetectionAreaArrowIcon id="beat-detection-area-arrow-icon"}}
@ -130,43 +6,45 @@
<div id="player-bottom" class="row {{if dimmerOn "dimmerOn"}} {{if playerBottomDisplayed "display-flex"}}"> <div id="player-bottom" class="row {{if dimmerOn "dimmerOn"}} {{if playerBottomDisplayed "display-flex"}}">
<div id="beat-area" class="col-sm-7 col-xs-12"> <div id="beat-area" class="col-sm-7 col-xs-12">
{{#if usingBeatPreferences}}
<span data-toggle="tooltip" data-placement="top" data-title="Using the saved sensitivity preference from the last time you listened to this song" class="bootstrap-tooltip" id="save-beat-preferences-star">
{{paper-icon "star" class=dimmerOnClass}}
</span>
{{/if}}
<div class="row" id="beat-option-row"> <div class="row" id="beat-option-row">
<div class="beat-option col-xs-4"> <div class="beat-option col-xs-4">
<span data-toggle="tooltip" data-placement="top" data-title="The range of hues ( colors ) that the lights may change to on beat." class="option-description bootstrap-tooltip"> <span data-toggle="tooltip" data-placement="top" data-title="The range of hues ( colors ) that the lights may change to on beat."
class="option-description bootstrap-tooltip">
Hue Range Hue Range
</span> </span>
{{range-slider start=hueRange orientation="vertical" step=beatOptions.hueRange.step range=beatOptions.hueRange.range connect=hueRangeConnect on-change="hueRangeChanged" pips=beatOptions.hueRange.pips}} {{range-slider start=hueRange orientation="vertical" step=beatOptions.hueRange.step range=beatOptions.hueRange.range connect=hueRangeConnect
on-change="hueRangeChanged" pips=beatOptions.hueRange.pips}}
</div> </div>
<div class="beat-option col-xs-4"> <div class="beat-option col-xs-4">
<span data-toggle="tooltip" data-placement="top" data-title="The minimum ( off-beat ) and maximum ( on-beat ) brightness of the lights" class="option-description bootstrap-tooltip"> <span data-toggle="tooltip" data-placement="top" data-title="The minimum ( off-beat ) and maximum ( on-beat ) brightness of the lights"
class="option-description bootstrap-tooltip">
Brightness Range Brightness Range
</span> </span>
{{range-slider start=brightnessRange orientation="vertical" step=beatOptions.brightnessRange.step range=beatOptions.brightnessRange.range on-change="brightnessRangeChanged" pips=beatOptions.brightnessRange.pips}} {{range-slider start=brightnessRange orientation="vertical" step=beatOptions.brightnessRange.step range=beatOptions.brightnessRange.range
on-change="brightnessRangeChanged" pips=beatOptions.brightnessRange.pips}}
</div> </div>
<div id="sensitivity-settings" class="beat-option col-xs-4"> <div id="sensitivity-settings" class="beat-option col-xs-4">
<span data-toggle="tooltip" data-placement="top" data-title="The sensitivity of the beat detector ( more sensitivity results in more registered beats )" class="option-description bootstrap-tooltip"> <span data-toggle="tooltip" data-placement="top" data-title="The sensitivity of the beat detector ( more sensitivity results in more registered beats )"
class="option-description bootstrap-tooltip">
Sensitivity Sensitivity
</span> </span>
{{range-slider start=threshold orientation="vertical" step=beatOptions.threshold.step range=beatOptions.threshold.range on-change="thresholdChanged" pips=beatOptions.threshold.pips}} {{range-slider start=threshold orientation="vertical" step=beatOptions.threshold.step range=beatOptions.threshold.range on-change="thresholdChanged"
pips=beatOptions.threshold.pips}}
</div> </div>
<div id="light-option" class="col-xs-12"> <div id="light-option" class="col-xs-12">
<span data-toggle="tooltip" data-placement="top auto" data-title="Quickly flash the lights on beat" class="bootstrap-tooltip" {{action "hideTooltip" on="mouseLeave"}}> <span data-toggle="tooltip" data-placement="top auto" data-title="Quickly flash the lights on beat" class="bootstrap-tooltip"
{{action "hideTooltip" on="mouseLeave"}}>
{{paper-checkbox value=flashingTransitions onChange=(action (mut flashingTransitions)) label="Flashing Transitions"}} {{paper-checkbox value=flashingTransitions onChange=(action (mut flashingTransitions)) label="Flashing Transitions"}}
</span> </span>
<span data-toggle="tooltip" data-placement="top auto" data-title="Slowly cycle the lights through all the colors" class="bootstrap-tooltip" {{action "hideTooltip" on="mouseLeave"}}> <span data-toggle="tooltip" data-placement="top auto" data-title="Slowly cycle the lights through all the colors" class="bootstrap-tooltip"
{{action "hideTooltip" on="mouseLeave"}}>
{{paper-checkbox value=colorloopMode onChange=(action (mut colorloopMode)) label="Colorloop"}} {{paper-checkbox value=colorloopMode onChange=(action (mut colorloopMode)) label="Colorloop"}}
</span> </span>
</div> </div>
@ -190,5 +68,3 @@
</div> </div>
</div> </div>
</div> </div>
{{music-tab/add-soundcloud-sound-modal action="handleNewSoundCloudURL" isShowingModal=isShowingAddSoundCloudModal}}

View file

@ -10,7 +10,6 @@
@import 'common'; @import 'common';
@import 'dimmer'; @import 'dimmer';
@import 'fancy-speaker'; @import 'fancy-speaker';
@import 'introjs';
@import 'hue-controls'; @import 'hue-controls';
@import 'light-group'; @import 'light-group';
@import 'music-tab'; @import 'music-tab';
@ -38,25 +37,6 @@ body, button {
padding-bottom: 50px; padding-bottom: 50px;
} }
.footer {
margin: 0 auto 10px auto;
width: 100%;
max-width: 800px;
text-align: center;
display: flex;
align-items: center;
justify-content: space-around;
}
.footer-text {
display: inline-block;
font-size: 18px;
a {
margin-left: 5px;
}
}
.alert { .alert {
margin-bottom: 0; margin-bottom: 0;
border: none; border: none;

View file

@ -1,18 +0,0 @@
#settings.introjs-fixParent {
position: inherit !important;
}
.introjs-tooltip {
width: 300px;
}
.introjs-skipbutton {
color: $secondaryThemeColor;
}
.introjs-bullets ul li a.active {
position: relative;
height: 10px;
width: 10px;
top: -2px;
}

View file

@ -23,70 +23,6 @@
color: lighten($playerDefaultIconColor, 30%) !important; color: lighten($playerDefaultIconColor, 30%) !important;
} }
#player-controls {
transition: all 0.2s ease-in-out;
position: absolute;
bottom: 0;
left: 0;
padding: 15px 10px;
width: 100%;
color: white !important;
z-index: 20;
cursor: default;
background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 1));
.ember-basic-dropdown-trigger {
position: absolute;
right: 0;
bottom: 13px;
}
.tooltip.top {
margin-top: -17px;
}
.tooltip-arrow {
display: none;
}
md-menu-item>.md-button md-icon {
margin: auto 0 5px 10px;
}
.play-arrow,
.pause,
.replay {
font-size: 30px;
}
}
#player-time-controls {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
display: inline-block;
margin-left: 1em;
}
.player-control-icon {
color: $playerDefaultIconColor !important;
transition-duration: 0.1s;
margin-right: 10px;
margin-top: 4px;
font-size: 22px;
}
.player-control-icon.active {
color: $secondaryThemeColor !important;
}
.player-control-icon:hover {
color: white !important;
}
#play-notification {
position: relative;
color: white !important;
background: black;
top: 50%;
left: 50%;
opacity: 0;
border-radius: 100%;
}
#player-area { #player-area {
height: $playerHeight; height: $playerHeight;
@ -153,129 +89,11 @@
box-shadow: none; box-shadow: none;
} }
#play-list-controls {
min-height: 40px;
margin-top: 5px;
border-bottom: 1px solid #3a3a3a;
position: relative;
button .player-control-icon {
margin: 0 5px 1px 3px;
}
.ember-basic-dropdown-trigger {
position: absolute;
bottom: 0;
right: 0;
color: $whitish;
.paper-button {
margin: 0;
}
}
}
#play-list-area {
background-color: white;
width: 100%;
height: 350px;
margin: 0 auto;
border-radius: 5px;
transition: 0.1s all ease-in-out;
position: relative;
overflow: auto;
#dragHere {
position: absolute;
top: 27%;
font-size: 20px;
text-align: center;
width: 100%;
}
[md-font-icon="library-music"] {
position: absolute;
top: 40%;
font-size: 100px;
opacity: 0.5;
width: 100%;
text-align: center;
}
}
.song-artist {
font-weight: bold;
}
#play-list-area.drag-here-highlight {
background-color: white;
border: 5px dotted #5383ff;
}
#play-list-area.dragging-over {
background-color: darken(white, 5%);
box-shadow: inset 0 0 20px 0 rgba(0, 0, 0, 1);
}
#file-input {
width: 1px;
height: 1px;
visibility: hidden;
}
.playlist-item {
border-bottom: 1px solid rgba(128, 128, 128, 0.3);
border-top: 1px solid rgba(128, 128, 128, 0.3);
height: 62px;
font-family: 'Open Sans', sans-serif;
padding: 0 20px 0 5px;
position: relative;
color: $blackish;
background: darken(white, 5%);
.close {
font-size: 18px;
}
.album-art {
height: 60px;
float: left;
margin-right: 5px;
border: 1px solid rgba(0, 0, 0, 0.5);
}
.song-info {
.song-title {
max-height: 40px;
overflow: hidden;
}
.song-artist {
max-height: 20px;
overflow: hidden;
}
}
.audio-remove-button {
position: absolute;
top: 10px;
right: 0;
padding: 10px;
}
}
.playlist-item.active {
background: darken(white, 15%) !important;
border-top: 1px solid $secondaryThemeColor;
border-bottom: 1px solid $secondaryThemeColor;
}
.playlist-item:hover {
background: darken(white, 10%);
.close {
display: block;
}
}
#beat-area { #beat-area {
position: relative; position: relative;
padding: 0; padding: 0;
} }
.star {
cursor: auto !important;
}
#beat-option-button-group { #beat-option-button-group {
margin: 20px 0 10px 0; margin: 20px 0 10px 0;
} }
@ -363,11 +181,7 @@
bottom: 22px; bottom: 22px;
} }
#visualization {
position: absolute;
top: 0;
left: 0;
}
#save-beat-preferences-star { #save-beat-preferences-star {
position: absolute; position: absolute;
@ -390,17 +204,6 @@
background-size: 80px 80px; background-size: 80px 80px;
} }
#artwork {
position: absolute;
width: 100%;
overflow: hidden;
img {
display: block;
margin: 0 auto;
max-height: 400px;
}
}
.keyboard-arrow-down { .keyboard-arrow-down {
font-size: 20px; font-size: 20px;
} }

View file

@ -1,12 +1,8 @@
{ {
"name": "huegasm", "name": "huegasm",
"dependencies": { "dependencies": {
"JavaScript-ID3-Reader": "https://github.com/aadsm/JavaScript-ID3-Reader.git",
"bootstrap-sass": "^3.3.5", "bootstrap-sass": "^3.3.5",
"hammer.js": "^2.0.8", "hammer.js": "^2.0.8",
"intro.js": "^2.1.0",
"jquery-mousewheel": "^3.1.13",
"locallyjs": "^0.3.2",
"matchMedia": "^0.3.0", "matchMedia": "^0.3.0",
"nouislider": "^9.0.0", "nouislider": "^9.0.0",
"velocity": "^1.3.1" "velocity": "^1.3.1"

View file

@ -17,12 +17,6 @@ module.exports = function (defaults) {
app.import('vendor/dancer.js'); app.import('vendor/dancer.js');
app.import('bower_components/bootstrap-sass/assets/javascripts/bootstrap/tooltip.js'); app.import('bower_components/bootstrap-sass/assets/javascripts/bootstrap/tooltip.js');
app.import('bower_components/intro.js/intro.js');
app.import('bower_components/intro.js/introjs.css');
app.import('bower_components/intro.js/themes/introjs-nassim.css');
app.import('bower_components/JavaScript-ID3-Reader/dist/id3-minimized.js');
app.import('bower_components/jquery-mousewheel/jquery.mousewheel.js');
app.import('bower_components/locallyjs/dist/locally.min.js');
app.import('bower_components/velocity/velocity.js'); app.import('bower_components/velocity/velocity.js');
return app.toTree(extraAssets); return app.toTree(extraAssets);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

View file

@ -0,0 +1,11 @@
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.action === 'start-listen') {
chrome.tabCapture.capture({
audio: true,
video: false
}, function (stream) {
console.log('stream', stream);
//I can attach all my filter here...
});
}
});

View file

@ -3,14 +3,17 @@
"name": "Huegasm", "name": "Huegasm",
"description": "Huegasm is a free web application for managing and synchronizing your Philips Hue lights with the beat of your music.", "description": "Huegasm is a free web application for managing and synchronizing your Philips Hue lights with the beat of your music.",
"version": "1.0", "version": "1.0",
"content_security_policy": "script-src https://connect.soundcloud.com 'self'; object-src 'self'",
"icons": { "icons": {
"16": "16x16.png", "16": "16x16.png",
"48": "48x48.png", "48": "48x48.png",
"128": "128x128.png" "128": "128x128.png"
}, },
"background": { "background": {
"page": "index.html" "background": {
"scripts": [
"background.js"
]
},
}, },
"browser_action": { "browser_action": {
"default_icon": { "default_icon": {
@ -22,7 +25,8 @@
}, },
"permissions": [ "permissions": [
"activeTab", "activeTab",
"background", "tabCapture",
"storage",
"https://ajax.googleapis.com/" "https://ajax.googleapis.com/"
] ]
} }