Skip to content

Commit

Permalink
Merge pull request #199 from blackcandy-org/api
Browse files Browse the repository at this point in the history
Move stream controller to API
  • Loading branch information
aidewoode committed Sep 9, 2022
2 parents de22a2a + c8faee9 commit baf3879
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 147 deletions.
17 changes: 17 additions & 0 deletions app/controllers/api/v1/cached_transcoded_stream_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

module Api
module V1
class CachedTranscodedStreamController < StreamController
def new
send_local_file @stream.transcode_cache_file_path
end

private

def set_nginx_header
response.headers["X-Accel-Redirect"] = File.join("/private_cache_media", @stream.transcode_cache_file_path.sub(Stream::TRANSCODE_CACHE_DIRECTORY.to_s, ""))
end
end
end
end
55 changes: 55 additions & 0 deletions app/controllers/api/v1/stream_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

module Api
module V1
class StreamController < ApiController
before_action :find_stream

def new
if need_transcode? @stream.format
redirect_to new_api_v1_transcoded_stream_path(song_id: params[:song_id])
else
send_local_file @stream.file_path
end
end

private

def set_nginx_header
# Let nginx can get value of media_path dynamically in the nginx config,
# when use X-Accel-Redirect header to send file.
response.headers["X-Media-Path"] = Setting.media_path
response.headers["X-Accel-Redirect"] = File.join("/private_media", @stream.file_path.sub(File.expand_path(Setting.media_path), ""))
end

def find_stream
song = Song.find(params[:song_id])
@stream = Stream.new(song)
end

def nginx_senfile?
Rails.configuration.action_dispatch.x_sendfile_header == "X-Accel-Redirect"
end

def send_local_file(file_path)
if nginx_senfile?
set_nginx_header

send_file file_path
return
end

# Use Rack::File to support HTTP range without nginx. see https://github.com/rails/rails/issues/32193
Rack::File.new(nil).serving(request, file_path).tap do |(status, headers, body)|
self.status = status
self.response_body = body

headers.each { |name, value| response.headers[name] = value }

response.headers["Content-Type"] = Mime[@stream.format]
response.headers["Content-Disposition"] = "attachment"
end
end
end
end
end
45 changes: 45 additions & 0 deletions app/controllers/api/v1/transcoded_stream_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# frozen_string_literal: true

module Api
module V1
class TranscodedStreamController < StreamController
include ActionController::Live

before_action :find_cache

# Similar to send_file in rails, but let response_body to be a stream object.
# The instance of Stream can respond to each() method. So the download can be streamed,
# instead of read whole data into memory.
def new
response.headers["Content-Type"] = Mime[Stream::TRANSCODE_FORMAT]

send_stream(filename: "#{@stream.name}.mp3") do |stream_response|
File.open(@stream.transcode_cache_file_path, "w") do |file|
@stream.each do |data|
stream_response.write data
file.write data
end
end
end
end

private

def find_cache
if valid_cache?
redirect_to new_api_v1_cached_transcoded_stream_path(song_id: params[:song_id])
end
end

def valid_cache?
return unless File.exist?(@stream.transcode_cache_file_path)

# Compare duration of cache file and original file to check integrity of cache file.
# Because the different format of the file, the duration will have a little difference,
# so the duration difference in two seconds are considered no problem.
cache_file_tag = WahWah.open(@stream.transcode_cache_file_path)
(@stream.duration - cache_file_tag.duration).abs <= 2
end
end
end
end
13 changes: 0 additions & 13 deletions app/controllers/cached_transcoded_stream_controller.rb

This file was deleted.

51 changes: 0 additions & 51 deletions app/controllers/stream_controller.rb

This file was deleted.

41 changes: 0 additions & 41 deletions app/controllers/transcoded_stream_controller.rb

This file was deleted.

2 changes: 1 addition & 1 deletion app/views/api/v1/songs/show.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
json.call(@song, :id, :name, :duration)
json.url new_stream_path(song_id: @song.id)
json.url new_api_v1_stream_path(song_id: @song.id)
json.album_name @song.album.title
json.artist_name @song.artist.title
json.is_favorited Current.user.favorited? @song
Expand Down
6 changes: 3 additions & 3 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
resource :library, only: [:show]

resources :artists, only: [:index, :show, :edit, :update]
resources :stream, only: [:new]
resources :transcoded_stream, only: [:new]
resources :cached_transcoded_stream, only: [:new]
resources :songs, only: [:index]
resources :albums, only: [:index, :show, :edit, :update], concerns: :playable

Expand Down Expand Up @@ -56,6 +53,9 @@
namespace :v1 do
resource :authentication, only: [:create]
resources :songs, only: [:show]
resources :stream, only: [:new]
resources :transcoded_stream, only: [:new]
resources :cached_transcoded_stream, only: [:new]
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require "test_helper"

class CachedTranscodedStreamControllerTest < ActionDispatch::IntegrationTest
class Api::V1::CachedTranscodedStreamControllerTest < ActionDispatch::IntegrationTest
setup do
stream = Stream.new(songs(:flac_sample))
FileUtils.touch(stream.transcode_cache_file_path)
Expand All @@ -11,17 +11,17 @@ class CachedTranscodedStreamControllerTest < ActionDispatch::IntegrationTest
end

test "should get stream" do
get new_cached_transcoded_stream_url(song_id: songs(:flac_sample).id)
get new_api_v1_cached_transcoded_stream_url(song_id: songs(:flac_sample).id)
assert_response :success
end

test "should set header for nginx send file" do
get new_cached_transcoded_stream_url(song_id: songs(:flac_sample).id)
get new_api_v1_cached_transcoded_stream_url(song_id: songs(:flac_sample).id)
assert_equal "/private_cache_media/2/ZmxhY19zYW1wbGVfbWQ1X2hhc2g=_128.mp3", @response.get_header("X-Accel-Redirect")
end

test "should set correct content type header" do
get new_cached_transcoded_stream_url(song_id: songs(:flac_sample).id)
get new_api_v1_cached_transcoded_stream_url(song_id: songs(:flac_sample).id)
assert_equal "audio/mpeg", @response.get_header("Content-Type")
end
end
Loading

0 comments on commit baf3879

Please sign in to comment.