From eece22750863ab0703c540dabdf2f5422a3dd6ce Mon Sep 17 00:00:00 2001
From: thyttan <6uuxstm66@mozmail.comā©>
Date: Mon, 19 Sep 2022 20:31:25 +0200
Subject: [PATCH] Spotify remote initial release
restructure menu
Requires Gadgetbridge 71.0
fix textinput->search menu
screenshots
---
apps/spotrem/ChangeLog | 5 +
apps/spotrem/README.md | 21 +++
apps/spotrem/app-icon.js | 1 +
apps/spotrem/app.js | 244 +++++++++++++++++++++++++++++++++++
apps/spotrem/app.png | Bin 0 -> 1877 bytes
apps/spotrem/metadata.json | 17 +++
apps/spotrem/screenshot1.png | Bin 0 -> 1816 bytes
apps/spotrem/screenshot2.png | Bin 0 -> 3282 bytes
8 files changed, 288 insertions(+)
create mode 100644 apps/spotrem/ChangeLog
create mode 100644 apps/spotrem/README.md
create mode 100644 apps/spotrem/app-icon.js
create mode 100644 apps/spotrem/app.js
create mode 100644 apps/spotrem/app.png
create mode 100644 apps/spotrem/metadata.json
create mode 100644 apps/spotrem/screenshot1.png
create mode 100644 apps/spotrem/screenshot2.png
diff --git a/apps/spotrem/ChangeLog b/apps/spotrem/ChangeLog
new file mode 100644
index 000000000..8e3d8b652
--- /dev/null
+++ b/apps/spotrem/ChangeLog
@@ -0,0 +1,5 @@
+0.01: New app.
+0.02: Restructure menu.
+0.03: change handling of intent extras.
+0.04: New layout.
+0.05: Add widgets field. Tweak layout.
diff --git a/apps/spotrem/README.md b/apps/spotrem/README.md
new file mode 100644
index 000000000..346ec9eba
--- /dev/null
+++ b/apps/spotrem/README.md
@@ -0,0 +1,21 @@
+Requires Gadgetbridge 71.0 or later. Allow intents in Gadgetbridge in order for this app to work.
+
+Touch input:
+
+Press the different ui elements to control Podcast Addict and open menus. Press left or right arrow to go to previous/next track.
+
+Swipe input:
+
+Swipe left/right to go to previous/next track. Swipe up/down to change the volume.
+
+It's possible to start tracks by searching with the remote. Search term without tags will override search with tags.
+
+To start playing 'from cold' the command for previous/next track via touch or swipe can be used. Pressing just play/pause is not guaranteed to initiate spotify in all circumstances (this will probably change with subsequent releases).
+
+In order to search to play or start music from the 'Saved' menu the Android device must be awake and unlocked. The remote can wake and unlock the device if the Bangle.js has been added as a 'trusted device' under Android Settings->Security->Smart Lock->Trusted devices.
+
+The swipe logic was inspired by the implementation in [rigrig](https://git.tubul.net/rigrig/)'s Scrolling Messages.
+
+Spotify Remote was created by [thyttan](https://github.com/thyttan/).
+
+Spotify icon by Icons8
diff --git a/apps/spotrem/app-icon.js b/apps/spotrem/app-icon.js
new file mode 100644
index 000000000..8da55b9a5
--- /dev/null
+++ b/apps/spotrem/app-icon.js
@@ -0,0 +1 @@
+require("heatshrink").decompress(atob("mEwwhC/AFV3AAQVVDKQWHDB0HC5NwCyoYMCxZJKFxgwKCxowJC6xGOJBAWPGA4MGogXOIwdCmf/AAczkhIKC4VzCogAD+YZEC49PC5AABmgXO+czJYoYDC4gfCuRYGoUjDAZ4GUJlyn4XNukjIwMzmVHBAU/+YXKoZ0GmQLCDgQXIU5IVDC5JVCIwIECDA5HIR4hkBDAX0C5YAHOoIXJa4QRDoUikiOEm7vKE4YADmZ1FC5N/R48nC5tzFQMiokimYYHC4h4KJwX3Ow6QMOwoXGSAoAKIwrBNFxIXZJBxGHGB4WIGBouJDBgWLJJYWMDBIWODIwVRAH4AXA="))
diff --git a/apps/spotrem/app.js b/apps/spotrem/app.js
new file mode 100644
index 000000000..2e68fb0fb
--- /dev/null
+++ b/apps/spotrem/app.js
@@ -0,0 +1,244 @@
+/*
+Bluetooth.println(JSON.stringify({t:"intent", action:"", flags:["flag1", "flag2",...], categories:["category1","category2",...], mimetype:"", data:"", package:"", class:"", target:"", extra:{someKey:"someValueOrString"}}));
+*/
+
+var R;
+var backToMenu = false;
+var isPaused = true;
+
+// The main layout of the app
+function gfx() {
+ //Bangle.drawWidgets();
+ R = Bangle.appRect;
+ marigin = 8;
+ // g.drawString(str, x, y, solid)
+ g.clearRect(R);
+ g.reset();
+
+ g.setFont("4x6:2");
+ g.setFontAlign(1, 0, 0);
+ g.drawString("->", R.x2 - marigin, R.y + R.h/2);
+
+ g.setFontAlign(-1, 0, 0);
+ g.drawString("<-", R.x + marigin, R.y + R.h/2);
+
+ g.setFontAlign(-1, 0, 1);
+ g.drawString("<-", R.x + R.w/2, R.y + marigin);
+
+ g.setFontAlign(1, 0, 1);
+ g.drawString("->", R.x + R.w/2, R.y2 - marigin);
+
+ g.setFontAlign(0, 0, 0);
+ g.drawString("Play\nPause", R.x + R.w/2, R.y + R.h/2);
+
+ g.setFontAlign(-1, -1, 0);
+ g.drawString("Menu", R.x + 2*marigin, R.y + 2*marigin);
+
+ g.setFontAlign(-1, 1, 0);
+ g.drawString("Wake", R.x + 2*marigin, R.y + R.h - 2*marigin);
+
+ g.setFontAlign(1, -1, 0);
+ g.drawString("Srch", R.x + R.w - 2*marigin, R.y + 2*marigin);
+
+ g.setFontAlign(1, 1, 0);
+ g.drawString("Saved", R.x + R.w - 2*marigin, R.y + R.h - 2*marigin);
+}
+
+// Touch handler for main layout
+function touchHandler(_, xy) {
+ x = xy.x;
+ y = xy.y;
+ len = (R.wb-1 instead of a>b.
+ if ((R.x-1 {
+ if (ud) Bangle.musicControl(ud>0 ? "volumedown" : "volumeup");
+ }
+ );
+ Bangle.on("touch", touchHandler);
+ Bangle.on("swipe", swipeHandler);
+}
+
+
+
+// Get back to the main layout
+function backToGfx() {
+ E.showMenu();
+ g.clear();
+ g.reset();
+ Bangle.removeAllListeners("touch");
+ Bangle.removeAllListeners("swipe");
+ setUI();
+ gfx();
+ backToMenu = false;
+}
+
+/*
+The functions for interacting with Android and the Spotify app
+*/
+
+simpleSearch = "";
+function simpleSearchTerm() { // input a simple search term without tags, overrides search with tags (artist and track)
+ require("textinput").input({text:simpleSearch}).then(result => {simpleSearch = result;}).then(() => {E.showMenu(searchMenu);});
+}
+
+artist = "";
+function artistSearchTerm() { // input artist to search for
+ require("textinput").input({text:artist}).then(result => {artist = result;}).then(() => {E.showMenu(searchMenu);});
+}
+
+track = "";
+function trackSearchTerm() { // input track to search for
+ require("textinput").input({text:track}).then(result => {track = result;}).then(() => {E.showMenu(searchMenu);});
+}
+
+album = "";
+function albumSearchTerm() { // input album to search for
+ require("textinput").input({text:album}).then(result => {album = result;}).then(() => {E.showMenu(searchMenu);});
+}
+
+function searchPlayWOTags() {//make a spotify search and play using entered terms
+ searchString = simpleSearch;
+ Bluetooth.println(JSON.stringify({t:"intent", action:"android.media.action.MEDIA_PLAY_FROM_SEARCH", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", target:"activity", extra:{query:searchString}, flags:["FLAG_ACTIVITY_NEW_TASK"]}));
+}
+
+function searchPlayWTags() {//make a spotify search and play using entered terms
+ searchString = (artist=="" ? "":("artist:\""+artist+"\"")) + ((artist!="" && track!="") ? " ":"") + (track=="" ? "":("track:\""+track+"\"")) + (((artist!="" && album!="") || (track!="" && album!="")) ? " ":"") + (album=="" ? "":(" album:\""+album+"\""));
+ Bluetooth.println(JSON.stringify({t:"intent", action:"android.media.action.MEDIA_PLAY_FROM_SEARCH", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", target:"activity", extra:{query:searchString}, flags:["FLAG_ACTIVITY_NEW_TASK"]}));
+}
+
+function playVreden() {//Play the track "Vreden" by Sara Parkman via spotify uri-link
+ Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:track:5QEFFJ5tAeRlVquCUNpAJY:play", target:"activity" , flags:["FLAG_ACTIVITY_NEW_TASK", "FLAG_ACTIVITY_NO_ANIMATION"/*, "FLAG_ACTIVITY_CLEAR_TOP", "FLAG_ACTIVITY_PREVIOUS_IS_TOP"*/]}));
+}
+
+function playVredenAlternate() {//Play the track "Vreden" by Sara Parkman via spotify uri-link
+ Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:track:5QEFFJ5tAeRlVquCUNpAJY:play", target:"activity" , flags:["FLAG_ACTIVITY_NEW_TASK"]}));
+}
+
+function searchPlayVreden() {//Play the track "Vreden" by Sara Parkman via search and play
+ Bluetooth.println(JSON.stringify({t:"intent", action:"android.media.action.MEDIA_PLAY_FROM_SEARCH", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", target:"activity", extra:{query:'artist:"Sara Parkman" track:"Vreden"'}, flags:["FLAG_ACTIVITY_NEW_TASK"]}));
+}
+
+function openAlbum() {//Play EP "The Blue Room" by Coldplay
+ Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:album:3MVb2CWB36x7VwYo5sZmf2", target:"activity", flags:["FLAG_ACTIVITY_NEW_TASK"]}));
+}
+
+function searchPlayAlbum() {//Play EP "The Blue Room" by Coldplay via search and play
+ Bluetooth.println(JSON.stringify({t:"intent", action:"android.media.action.MEDIA_PLAY_FROM_SEARCH", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", target:"activity", extra:{query:'album:"The blue room" artist:"Coldplay"', "android.intent.extra.focus":"vnd.android.cursor.item/album"}, flags:["FLAG_ACTIVITY_NEW_TASK"]}));
+}
+
+function spotifyWidget(action) {
+ Bluetooth.println(JSON.stringify({t:"intent", action:("com.spotify.mobile.android.ui.widget."+action), package:"com.spotify.music", target:"broadcastreceiver"}));
+}
+
+function gadgetbridgeWake() {
+ Bluetooth.println(JSON.stringify({t:"intent", target:"activity", flags:["FLAG_ACTIVITY_NEW_TASK", "FLAG_ACTIVITY_CLEAR_TASK", "FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS", "FLAG_ACTIVITY_NO_ANIMATION"], package:"gadgetbridge", class:"nodomain.freeyourgadget.gadgetbridge.activities.WakeActivity"}));
+}
+
+function spotifyPlaylistDW() {
+ Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:user:spotify:playlist:37i9dQZEVXcRfaeEbxXIgb:play", target:"activity" , flags:["FLAG_ACTIVITY_NEW_TASK", "FLAG_ACTIVITY_NO_ANIMATION"/*, "FLAG_ACTIVITY_CLEAR_TOP", "FLAG_ACTIVITY_PREVIOUS_IS_TOP"*/]}));
+}
+
+// Spotify Remote Menu
+var spotifyMenu = {
+ "" : { title : " ",
+ back: backToGfx },
+ "Controls" : ()=>{E.showMenu(controlMenu);},
+ "Search and play" : ()=>{E.showMenu(searchMenu);},
+ "Saved music" : ()=>{E.showMenu(savedMenu);},
+ "Wake the android" : function() {gadgetbridgeWake();gadgetbridgeWake();},
+ "Exit Spotify Remote" : ()=>{load();}
+};
+
+
+var controlMenu = {
+ "" : { title : " ",
+ back: () => {if (backToMenu) E.showMenu(spotifyMenu);
+ if (!backToMenu) backToGfx();} },
+ "Play" : ()=>{Bangle.musicControl("play");},
+ "Pause" : ()=>{Bangle.musicControl("pause");},
+ "Previous" : ()=>{spotifyWidget("PREVIOUS");},
+ "Next" : ()=>{spotifyWidget("NEXT");},
+ "Play (widget, next then previous)" : ()=>{spotifyWidget("NEXT"); spotifyWidget("PREVIOUS");},
+ "Messages Music Controls" : ()=>{load("messagesmusic.app.js");},
+};
+
+var searchMenu = {
+ "" : { title : " ",
+ back: () => {if (backToMenu) E.showMenu(spotifyMenu);
+ if (!backToMenu) backToGfx();} },
+ "Search term w/o tags" : ()=>{simpleSearchTerm();},
+ "Execute search and play w/o tags" : ()=>{searchPlayWOTags();},
+ "Search term w tag \"artist\"" : ()=>{artistSearchTerm();},
+ "Search term w tag \"track\"" : ()=>{trackSearchTerm();},
+ "Search term w tag \"album\"" : ()=>{albumSearchTerm();},
+ "Execute search and play with tags" : ()=>{searchPlayWTags();},
+ "Play \"Vreden\" by Sara Parkman via uri-link" : ()=>{playVreden();},
+ "Play \"Vreden\" by Sara Parkman via search&play" : ()=>{searchPlayVreden();},
+ "Open \"The Blue Room\" EP (no autoplay)" : ()=>{openAlbum();},
+ "Play \"The Blue Room\" EP via search&play" : ()=>{searchPlayAlbum();},
+ "Play playlist Discover Weekly" : ()=>{spotifyPlaylistDW();},
+};
+
+var savedMenu = {
+ "" : { title : " ",
+ back: () => {if (backToMenu) E.showMenu(spotifyMenu);
+ if (!backToMenu) backToGfx();} },
+ "Play \"Vreden\" by Sara Parkman via uri-link" : ()=>{playVreden();},
+ "Open \"The Blue Room\" EP (no autoplay)" : ()=>{openAlbum();},
+ "Play \"The Blue Room\" EP via search&play" : ()=>{searchPlayAlbum();},
+ "Play playlist Discover Weekly" : ()=>{spotifyPlaylistDW();},
+};
+
+Bangle.loadWidgets();
+setUI();
+gfx();
diff --git a/apps/spotrem/app.png b/apps/spotrem/app.png
new file mode 100644
index 0000000000000000000000000000000000000000..3c0d65eee994757cfcee51e2191164cc49f3179b
GIT binary patch
literal 1877
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
literal 0
HcmV?d00001
diff --git a/apps/spotrem/screenshot2.png b/apps/spotrem/screenshot2.png
new file mode 100644
index 0000000000000000000000000000000000000000..7801a3034027861558ee960b030561276d578bbc
GIT binary patch
literal 3282
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 qw~cha>S{eO_
zTl(gA!A{;qL3?54gB$#AVp6WbCvq&5JNp^fwCA5~u_INpxVw`_gAoXQzlP7K{ZnX+
z6Ow*eu7R}7{c6mY*4X_iPnwn@Z4PZcW&lcPt|=6gPBrL};wr#iB{e@h-_^+j40&_@
z9q!a24TJwt^^J{fO@{6Dp#C{o^~NKD{^=1d+|9CROuW~*di7WjIEf81qs--4S)?Rf
zQSY1ITMga3+PFFpm$QC4u@~m^p?2evwM9U0%cVu+e8gHwUq_R@)+CAd$52%J$b3-S
z9=_n7g93b#UXnn8)~Uh8dd7EpY)MT$j_7I$$O^G+$(T|Yh7+&6ufOO%v~uDO939WB
zb)4Ws7j$wNt6x|$lDva#_E2A^nB3phc&P@nMvFEszx=}8-=|~I)4(;UgSzl_^KcB!
z9K-hJ)ekU7K^gqVU-LR~lKahD@4uGAQ7
zr;tQtcy%YF0+3o
z#l16VU`hW{tq8l`$98=t4!*Ms(fwzjfa5BQN3_B=;jx^iK-FSl?W)R>%3_{{i@9P1OJZ
literal 0
HcmV?d00001