diff --git a/platypush/backend/http/static/css/application.css b/platypush/backend/http/static/css/application.css index 46663d87..58039222 100644 --- a/platypush/backend/http/static/css/application.css +++ b/platypush/backend/http/static/css/application.css @@ -203,6 +203,11 @@ button[disabled] { font-size: 25px; } + #notification-container * > .notification-image img { + width: 80%; + height: 80%; + } + #hidden-plugins-container > .plugin { display: none; } diff --git a/platypush/backend/http/static/css/dashboard.css b/platypush/backend/http/static/css/dashboard.css new file mode 100644 index 00000000..7c7b0399 --- /dev/null +++ b/platypush/backend/http/static/css/dashboard.css @@ -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); +} + diff --git a/platypush/backend/http/static/css/widgets/date-time-weather.css b/platypush/backend/http/static/css/widgets/date-time-weather.css new file mode 100644 index 00000000..6790ba2f --- /dev/null +++ b/platypush/backend/http/static/css/widgets/date-time-weather.css @@ -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; + } + diff --git a/platypush/backend/http/static/css/widgets/music.css b/platypush/backend/http/static/css/widgets/music.css new file mode 100644 index 00000000..3ed8d1e9 --- /dev/null +++ b/platypush/backend/http/static/css/widgets/music.css @@ -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; +} + diff --git a/platypush/backend/http/static/js/pushbullet.js b/platypush/backend/http/static/js/pushbullet.js new file mode 100644 index 00000000..65f1b081 --- /dev/null +++ b/platypush/backend/http/static/js/pushbullet.js @@ -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(); +}); + diff --git a/platypush/backend/http/static/js/widgets/music.js b/platypush/backend/http/static/js/widgets/music.js new file mode 100644 index 00000000..24d5c2a7 --- /dev/null +++ b/platypush/backend/http/static/js/widgets/music.js @@ -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': '' + ('artist' in event.args.track ? event.args.track.artist : '') + + '
' + + ('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(); +}); + diff --git a/platypush/backend/http/templates/dashboard.html b/platypush/backend/http/templates/dashboard.html index ef25b4a2..19926bab 100644 --- a/platypush/backend/http/templates/dashboard.html +++ b/platypush/backend/http/templates/dashboard.html @@ -7,12 +7,14 @@ + + + + -

-

+
+
+
-

- N/A° -

+

+ N/A° +

-

+
- - - + + + +
diff --git a/platypush/backend/http/templates/widgets/music.html b/platypush/backend/http/templates/widgets/music.html new file mode 100644 index 00000000..61f065f0 --- /dev/null +++ b/platypush/backend/http/templates/widgets/music.html @@ -0,0 +1,31 @@ + + + +
+
+
No media is being played
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+ diff --git a/platypush/backend/music/mpd/__init__.py b/platypush/backend/music/mpd/__init__.py index c786e490..2a2e7149 100644 --- a/platypush/backend/music/mpd/__init__.py +++ b/platypush/backend/music/mpd/__init__.py @@ -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)) diff --git a/platypush/plugins/music/mpd/__init__.py b/platypush/plugins/music/mpd/__init__.py index 18fc8ae2..db626f50 100644 --- a/platypush/plugins/music/mpd/__init__.py +++ b/platypush/plugins/music/mpd/__init__.py @@ -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())