- Added Pushbullet JS logic to show mirror notifications on web FE

- Added JS and CSS files for dashboard and widgets
This commit is contained in:
Fabio Manganiello 2018-05-04 17:25:12 +02:00
parent ae6467060b
commit 2f8c74c8e3
12 changed files with 306 additions and 27 deletions

View file

@ -203,6 +203,11 @@ button[disabled] {
font-size: 25px;
}
#notification-container * > .notification-image img {
width: 80%;
height: 80%;
}
#hidden-plugins-container > .plugin {
display: none;
}

View file

@ -0,0 +1,17 @@
body {
background: rgba(240,240,245,1.0);
font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
#widgets-container {
padding: 1em;
}
.widget {
background: white;
border-radius: 5px;
height: 18em;
overflow: hidden;
box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16), 0 0 0 1px rgba(0,0,0,0.08);
}

View file

@ -0,0 +1,17 @@
.widget.date-time-weather {
text-align: center;
}
.date-time-weather-container {
padding: 2rem;
}
h1.temperature {
font-size: 45px;
margin: 4rem;
}
.widget.date-time-weather * > .time {
font-size: 22px;
}

View file

@ -0,0 +1,49 @@
.music-container {
width: inherit;
height: inherit;
display: table-cell;
vertical-align: middle;
text-align: center;
}
.track-info {
font-size: 20px;
}
.track-info > .artist {
font-weight: bold;
margin-bottom: 1rem;
}
.track-info > .title {
margin-bottom: 2rem;
}
.time-bar {
height: 7.5px;
background: #ddd;
margin: 7.5px;
border-radius: 10px;
}
.time-bar > .elapsed {
height: 7.5px;
background: #98ffb0;
border-radius: 10px;
}
.time-elapsed {
text-align: left;
margin-left: 1rem;
}
.time-total {
float: right;
margin-right: 1rem;
}
.time-elapsed, .time-total {
color: rgba(0, 0, 0, 0.7);
letter-spacing: 1px;
}

View file

@ -0,0 +1,27 @@
$(document).ready(function() {
var onEvent = function(event) {
switch (event.args.type) {
case 'platypush.message.event.pushbullet.PushbulletEvent':
if (event.args.push_type === 'mirror') {
createNotification({
'title': event.args.title,
'text': event.args.body,
'image': 'data:image/png;base64, ' + event.args.icon,
});
}
break;
}
};
var initEvents = function() {
window.registerEventListener(onEvent);
};
var init = function() {
initEvents();
};
init();
});

View file

@ -0,0 +1,123 @@
$(document).ready(function() {
var $widget = $('.widget.music'),
$trackContainer = $widget.find('.track-container'),
$timeContainer = $widget.find('.time-container'),
$noTrackElement = $trackContainer.find('.no-track-info'),
$trackElement = $trackContainer.find('.track-info'),
$artistElement = $trackElement.find('[data-bind=artist]'),
$titleElement = $trackElement.find('[data-bind=title]'),
$timeElapsedElement = $timeContainer.find('.time-elapsed'),
$timeTotalElement = $timeContainer.find('.time-total'),
$elapsedTimeBar = $widget.find('.time-bar > .elapsed'),
timeElapsed,
timeTotal,
refreshElapsedInterval;
var onEvent = function(event) {
switch (event.args.type) {
case 'platypush.message.event.music.NewPlayingTrackEvent':
createNotification({
'icon': 'play',
'html': '<b>' + ('artist' in event.args.track ? event.args.track.artist : '')
+ '</b><br/>'
+ ('title' in event.args.track ? event.args.track.title : '[No name]'),
});
case 'platypush.message.event.music.MusicPlayEvent':
case 'platypush.message.event.music.MusicPauseEvent':
refreshTrack(event.args.track);
case 'platypush.message.event.music.MusicStopEvent':
refreshStatus(event.args.status);
break;
}
};
var initEvents = function() {
window.registerEventListener(onEvent);
};
var setState = function(state) {
if (state === 'play') {
$noTrackElement.hide();
$trackElement.show();
$timeContainer.show();
} else if (state === 'pause') {
$noTrackElement.hide();
$trackElement.show();
$timeContainer.hide();
} else if (state === 'stop') {
$noTrackElement.show();
$trackElement.hide();
$timeContainer.hide();
}
};
var secondsToTimeString = function(seconds) {
seconds = parseInt(seconds);
if (seconds) {
return (parseInt(seconds/60) + ':' +
(seconds%60 < 10 ? '0' : '') + seconds%60);
} else {
return '-:--';
}
};
var setTrackTime = function(time) {
$timeTotalElement.text(secondsToTimeString(time));
timeTotal = parseInt(time);
};
var setTrackElapsed = function(time) {
if (refreshElapsedInterval) {
clearInterval(refreshElapsedInterval);
refreshElapsedInterval = undefined;
}
timeElapsed = parseInt(time);
$timeElapsedElement.text(secondsToTimeString(timeElapsed));
var ratio = 100 * Math.min(timeElapsed/timeTotal, 1);
$elapsedTimeBar.css('width', ratio + '%');
refreshElapsedInterval = setInterval(function() {
timeElapsed += 1;
ratio = 100 * Math.min(timeElapsed/timeTotal, 1);
$elapsedTimeBar.css('width', ratio + '%');
$timeElapsedElement.text(secondsToTimeString(timeElapsed));
}, 1000);
};
var refreshStatus = function(status) {
setState(state=status.state);
if ('elapsed' in status) {
setTrackElapsed(status.elapsed);
}
};
var refreshTrack = function(track) {
setTrackTime(track.time);
$artistElement.text(track.artist);
$titleElement.text(track.title);
};
var initWidget = function() {
$.when(
execute({ type: 'request', action: 'music.mpd.currentsong' }),
execute({ type: 'request', action: 'music.mpd.status' })
).done(function(t, s) {
refreshTrack(t[0].response.output);
refreshStatus(s[0].response.output);
});
};
var init = function() {
initEvents();
initWidget();
};
init();
});

View file

@ -7,12 +7,14 @@
<link rel="stylesheet" href="{{ url_for('static', filename='css/normalize.css') }}"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='font-awesome/css/font-awesome.min.css') }}"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='css/application.css') }}"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='css/dashboard.css') }}"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='css/toggles.css') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery-3.3.1.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/skeleton-tabs.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/application.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/dashboard.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/pushbullet.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/assistant.google.js') }}"></script>
<script type="text/javascript">
window.websocket_port = {% print(websocket_port) %}
@ -27,15 +29,17 @@
<body>
<main>
{% for widget_name, widget in config['widgets'].items() %}
<div class="widget {% print(utils.widget_columns_to_html_class(widget['columns'])) %}
{% print(widget_name) %}"
id="{% print(widget['id'] if 'id' in widget else widget_name) %}">
{% with properties=widget %}
{% include 'widgets/' + widget_name + '.html' %}
{% endwith %}
</div>
{% endfor %}
<div id="widgets-container">
{% for widget_name, widget in config['widgets'].items() %}
<div class="widget {% print(utils.widget_columns_to_html_class(widget['columns'])) %}
{% print(widget_name) %}"
id="{% print(widget['id'] if 'id' in widget else widget_name) %}">
{% with properties=widget %}
{% include 'widgets/' + widget_name + '.html' %}
{% endwith %}
</div>
{% endfor %}
</div>
<div id="notification-container"></div>
</main>

View file

@ -12,6 +12,7 @@
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery-3.3.1.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/skeleton-tabs.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/application.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/pushbullet.js') }}"></script>
<script type="text/javascript">
window.websocket_port = {% print(websocket_port) %}

View file

@ -1,15 +1,18 @@
<script type="text/javascript" src="{{ url_for('static', filename='js/widgets/date-time-weather.js') }}"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='css/widgets/date-time-weather.css') }}"></script>
<p class="date" data-bind="date"></p>
<p class="time" data-bind="time"></p>
<div class="date-time-weather-container">
<div class="date" data-bind="date"></div>
<div class="time" data-bind="time"></div>
<h1 class="temperature">
<span data-bind="temperature">N/A</span>&deg;
</h1>
<h1 class="temperature">
<span data-bind="temperature">N/A</span>&deg;
</h1>
<p class="forecast" data-bind="forecast"></p>
<div class="forecast" data-bind="forecast"></div>
<!-- <p class="sensor-temperature"> -->
<!-- <span data-bind="sensor-temperature">N/A</span>&deg; -->
<!-- </p> -->
<!-- <p class="sensor-temperature"> -->
<!-- <span data-bind="sensor-temperature">N/A</span>&deg; -->
<!-- </p> -->
</div>

View file

@ -0,0 +1,31 @@
<script type="text/javascript" src="{{ url_for('static', filename='js/widgets/music.js') }}"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='css/widgets/music.css') }}"></script>
<div class="music-container">
<div class="track-container">
<div class="no-track-info">No media is being played</div>
<div class="track-info">
<div class="artist" data-bind="artist"></div>
<div class="title" data-bind="title"></div>
</div>
</div>
<div class="time-container">
<div class="row">
<div class="time-bar">
<div class="elapsed"></div>
</div>
</div>
<div class="row">
<div class="six columns">
<div class="time-elapsed" data-bind="time-elapsed"></div>
</div>
<div class="six columns">
<div class="time-total" data-bind="time-total"></div>
</div>
</div>
</div>
</div>

View file

@ -60,14 +60,6 @@ class MusicMpdBackend(Backend):
self.bus.post(PlaylistChangeEvent(changes=changes))
last_playlist = playlist
if 'title' in track and ('artist' not in track
or not track['artist']
or re.search('^tunein:', track['file'])):
m = re.match('^\s*(.+?)\s+-\s+(.*)\s*$', track['title'])
if m and m.group(1) and m.group(2):
track['artist'] = m.group(1)
track['title'] = m.group(2)
if state == 'play' and track != last_track:
self.bus.post(NewPlayingTrackEvent(status=status, track=track))

View file

@ -1,4 +1,5 @@
import mpd
import re
from platypush.message.response import Response
@ -105,7 +106,16 @@ class MusicMpdPlugin(MusicPlugin):
return Response(output=self.client.status())
def currentsong(self):
return Response(output=self.client.currentsong())
track = self.client.currentsong()
if 'title' in track and ('artist' not in track
or not track['artist']
or re.search('^tunein:', track['file'])):
m = re.match('^\s*(.+?)\s+-\s+(.*)\s*$', track['title'])
if m and m.group(1) and m.group(2):
track['artist'] = m.group(1)
track['title'] = m.group(2)
return Response(output=track)
def playlistinfo(self):
return Response(output=self.client.playlistinfo())