diff --git a/Gemfile b/Gemfile index e1be030..121b61c 100644 --- a/Gemfile +++ b/Gemfile @@ -67,3 +67,5 @@ gem "bcrypt", "~> 3.1.7" group :development do eval_gemfile "gemfiles/rubocop.gemfile" end + +gem "turbo_power", "~> 0.3.1" diff --git a/Gemfile.lock b/Gemfile.lock index 1420b9c..30f1409 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -315,6 +315,8 @@ GEM turbo_boost-streams (0.0.8) rails (>= 6.1) turbo-rails (>= 1.1) + turbo_power (0.3.1) + turbo-rails (~> 1.3) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.4.2) @@ -362,6 +364,7 @@ DEPENDENCIES tailwindcss-rails turbo-rails turbo_boost-commands + turbo_power (~> 0.3.1) web-console RUBY VERSION diff --git a/app/controllers/live_stations_controller.rb b/app/controllers/live_stations_controller.rb index ecaca98..317f5a8 100644 --- a/app/controllers/live_stations_controller.rb +++ b/app/controllers/live_stations_controller.rb @@ -79,6 +79,19 @@ def play render turbo_stream: turbo_stream.update("player", partial: "player/player", locals: {station:, track: station.current_track}) end + def pause + station = current_user.live_station + station.update!(live: false) + Turbo::StreamsChannel.broadcast_stream_to station, content: turbo_stream.set_attribute(".player", "data-player-state-value", "paused") + end + + + def resume + station = current_user.live_station + station.update!(live: true) + Turbo::StreamsChannel.broadcast_stream_to station, content: turbo_stream.set_attribute(".player", "data-player-state-value", "playing") + end + private def station_params diff --git a/app/javascript/application.js b/app/javascript/application.js index 4fdc39a..5fa4cd6 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -6,6 +6,9 @@ import "controllers"; import { createCable } from "@anycable/web"; import { start } from "@anycable/turbo-stream"; +import TurboPower from 'turbo_power' +TurboPower.initialize(Turbo.StreamActions) + const logLevel = document.documentElement.classList.contains("debug") ? "debug" : "error"; diff --git a/app/javascript/controllers/player_controller.js b/app/javascript/controllers/player_controller.js index 6d8e4ff..7d009c3 100644 --- a/app/javascript/controllers/player_controller.js +++ b/app/javascript/controllers/player_controller.js @@ -14,7 +14,7 @@ function secondsToDuration(num) { export default class extends Controller { static targets = ["progress", "time"]; static outlets = ["track"]; - static values = { duration: Number, track: String, nextTrackUrl: String }; + static values = { duration: Number, track: String, nextTrackUrl: String, state: String, pauseUrl: String , resumeUrl: String }; static classes = ["playing"]; initialize() { @@ -36,6 +36,18 @@ export default class extends Controller { } } + stateValueChanged() { + if (this.pauseUrlValue) { + return; + } + + if (this.playing && this.stateValue === "paused") { + this.pause(false); + } else if (!this.playing && this.stateValue === "playing") { + this.play(false); + } + } + trackOutletConnected(outlet, el) { outlet.togglePlayingIfMatch(this.trackValue); } @@ -46,7 +58,7 @@ export default class extends Controller { this.setupAudioListeners(); } - if (this.playing) { + if (this.playing || this.stateValue === "playing") { this.play(); } } @@ -61,12 +73,16 @@ export default class extends Controller { this.element.classList.add(this.playingClass); this.audio.play(); this.playing = true; + + if (this.resumeUrlValue) this.broadcastStateChange(this.resumeUrlValue); } pause() { this.element.classList.remove(this.playingClass); this.audio.pause(); this.playing = false; + + if (this.pauseUrlValue) this.broadcastStateChange(this.pauseUrlValue); } seek(e) { @@ -99,6 +115,16 @@ export default class extends Controller { } } + async broadcastStateChange(url) { + const request = new FetchRequest("POST", url, { + responseKind: "turbo-stream", + }); + const response = await request.perform(); + if (!response.ok) { + console.error("Failed to broadcast pause/resume", response.status); + } + } + updateProgress(currentTime) { const percent = (currentTime * 100) / this.durationValue; diff --git a/app/views/player/_player.html.erb b/app/views/player/_player.html.erb index 6d47d6a..b999aab 100644 --- a/app/views/player/_player.html.erb +++ b/app/views/player/_player.html.erb @@ -4,7 +4,10 @@ data-player-duration-value="<%= track&.duration %>" data-player-track-value="<%= track&.id %>" data-player-playing-class="player-playing" + data-player-state-value="playing" data-player-next-track-url-value="<%= live ? play_next_live_station_path : (!station && play_next_track_path(track))%>" + data-player-pause-url-value="<%= pause_live_station_path if live %>" + data-player-resume-url-value="<%= resume_live_station_path if live %>" data-player-track-outlet=".track" > <% if track %> @@ -12,7 +15,7 @@
<% end %> - <% unless station %> + <% if !station || live %>