Skip to content

Commit

Permalink
Fix #175, use bit depth to check if song is lossless or not
Browse files Browse the repository at this point in the history
  • Loading branch information
aidewoode committed Jun 16, 2023
1 parent 9e7962a commit f29efd8
Show file tree
Hide file tree
Showing 14 changed files with 62 additions and 76 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ gem "puma", "~> 6.0.2"
gem "jbuilder", "~> 2.11.5"

# Get meta data from audio file
gem "wahwah", "~> 1.3.0"
gem "wahwah", "~> 1.4.0"

# Use sidekiq for backgroud job
gem "sidekiq", "~> 7.0.0"
Expand Down
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ GEM
concurrent-ruby (~> 1.0)
unicode-display_width (2.3.0)
uniform_notifier (1.16.0)
wahwah (1.3.0)
wahwah (1.4.0)
web-console (4.2.0)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
Expand Down Expand Up @@ -354,7 +354,7 @@ DEPENDENCIES
stimulus-rails (~> 1.0.2)
turbo-rails (~> 1.3.0)
tzinfo-data
wahwah (~> 1.3.0)
wahwah (~> 1.4.0)
web-console (>= 3.3.0)
webmock (~> 3.14.0)

Expand Down
12 changes: 7 additions & 5 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ class ApplicationController < ActionController::Base
logout_current_user
end

def need_transcode?(format)
return true unless format.in?(Stream::SUPPORTED_FORMATS)
return true if safari? && !format.in?(Stream::SAFARI_SUPPORTED_FORMATS)
return true if turbo_ios? && !format.in?(Stream::IOS_SUPPORTED_FORMATS)
def need_transcode?(song)
song_format = song.format

Setting.allow_transcode_lossless ? format.in?(Stream::LOSSLESS_FORMATS) : false
return true unless song_format.in?(Stream::SUPPORTED_FORMATS)
return true if safari? && !song_format.in?(Stream::SAFARI_SUPPORTED_FORMATS)
return true if turbo_ios? && !song_format.in?(Stream::IOS_SUPPORTED_FORMATS)

Setting.allow_transcode_lossless ? song.lossless? : false
end

def flash_errors_message(object, now: false)
Expand Down
14 changes: 0 additions & 14 deletions app/jobs/attach_album_image_from_file_job.rb

This file was deleted.

22 changes: 11 additions & 11 deletions app/models/media.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,24 +63,24 @@ def attach(file_info)

album = if various_artist?(file_info)
various_artist = Artist.find_or_create_by!(is_various: true)
Album.find_or_create_by!(artist: various_artist, name: file_info[:album_name])
Album.find_or_initialize_by(artist: various_artist, name: file_info[:album_name])
else
Album.find_or_create_by!(artist: artist, name: file_info[:album_name])
Album.find_or_initialize_by(artist: artist, name: file_info[:album_name])
end

album.update_column(:year, file_info[:year]) if file_info[:year].present? && album.year.blank?
album.update_column(:genre, file_info[:genre]) if file_info[:genre].present? && album.genre.blank?
album.update!(album_info(file_info))
album.update!(image: file_info[:image]) unless album.has_image?

# Attach image from file to the album.
AttachAlbumImageFromFileJob.perform_later(album, file_info[:file_path]) unless album.has_image?

Song.find_or_create_by!(md5_hash: file_info[:md5_hash]) do |item|
item.attributes = song_info(file_info).merge(album: album, artist: artist)
end
song = Song.find_or_initialize_by(md5_hash: file_info[:md5_hash])
song.update!(song_info(file_info).merge(album: album, artist: artist))
end

def song_info(file_info)
file_info.slice(:name, :tracknum, :duration, :file_path, :file_path_hash)
file_info.slice(:name, :tracknum, :duration, :file_path, :file_path_hash, :bit_depth).compact
end

def album_info(file_info)
file_info.slice(:year, :genre).compact
end

def various_artist?(file_info)
Expand Down
19 changes: 11 additions & 8 deletions app/models/media_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,6 @@ def format(file_path)
File.extname(file_path).downcase.delete(".")
end

def image(file_path)
tag = WahWah.open(file_path)
image = tag.images.first

{data: image[:data], format: MIME::Type.new(image[:mime_type]).sub_type} if image
end

def file_info(file_path)
tag_info = get_tag_info(file_path)
tag_info.merge(
Expand All @@ -36,6 +29,14 @@ def get_md5_hash(file_path, with_mtime: false)

private

def extract_image_from(tag)
image = tag.images.first
return unless image.present?

image_format = MIME::Type.new(image[:mime_type]).sub_type
CarrierWaveStringIO.new("cover.#{image_format}", image[:data])
end

def get_tag_info(file_path)
tag = WahWah.open(file_path)

Expand All @@ -46,7 +47,9 @@ def get_tag_info(file_path)
albumartist_name: tag.albumartist.presence,
genre: tag.genre.presence,
tracknum: tag.track,
duration: tag.duration.round
duration: tag.duration.round,
bit_depth: tag.bit_depth,
image: extract_image_from(tag)
}.tap do |info|
info[:year] = begin
Date.strptime(tag.year, "%Y").year
Expand Down
4 changes: 4 additions & 0 deletions app/models/song.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ def format
MediaFile.format(file_path)
end

def lossless?
bit_depth.present?
end

private

def remove_transcode_cache
Expand Down
1 change: 0 additions & 1 deletion app/models/stream.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
class Stream
extend Forwardable

LOSSLESS_FORMATS = MediaFile::SUPPORTED_FORMATS & %w[flac wav]
SUPPORTED_FORMATS = MediaFile::SUPPORTED_FORMATS - %w[wma]
SAFARI_SUPPORTED_FORMATS = MediaFile::SUPPORTED_FORMATS - %w[ogg opus oga]
IOS_SUPPORTED_FORMATS = MediaFile::SUPPORTED_FORMATS - %w[ogg opus oga]
Expand Down
4 changes: 2 additions & 2 deletions app/views/api/v1/songs/_song.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
json.call(song, :id, :name, :duration)
json.url need_transcode?(song.format) ? new_api_v1_transcoded_stream_url(song_id: song.id) : new_api_v1_stream_url(song_id: song.id)
json.url need_transcode?(song) ? new_api_v1_transcoded_stream_url(song_id: song.id) : new_api_v1_stream_url(song_id: song.id)
json.album_name song.album.title
json.artist_name song.artist.title
json.is_favorited song.is_favorited || Current.user.favorited?(song)
json.format need_transcode?(song.format) ? Stream::TRANSCODE_FORMAT : song.format
json.format need_transcode?(song) ? Stream::TRANSCODE_FORMAT : song.format
json.album_image_url do
json.small URI.join(root_url, image_url_for(song.album, size: "small"))
json.medium URI.join(root_url, image_url_for(song.album, size: "medium"))
Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20230616013722_add_bit_depth_to_songs.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddBitDepthToSongs < ActiveRecord::Migration[7.0]
def change
add_column :songs, :bit_depth, :integer
end
end
3 changes: 2 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.0].define(version: 2023_02_21_024303) do
ActiveRecord::Schema[7.0].define(version: 2023_06_16_013722) do
create_table "albums", force: :cascade do |t|
t.string "name"
t.string "image"
Expand Down Expand Up @@ -67,6 +67,7 @@
t.integer "album_id"
t.integer "artist_id"
t.string "file_path_hash"
t.integer "bit_depth"
t.index ["album_id"], name: "index_songs_on_album_id"
t.index ["artist_id"], name: "index_songs_on_artist_id"
t.index ["file_path_hash"], name: "index_songs_on_file_path_hash"
Expand Down
7 changes: 5 additions & 2 deletions test/fixtures/songs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ flac_sample:
md5_hash: 'flac_sample_md5_hash'
artist: 'artist1'
album: 'album1'
duration: 8.0
duration: 8.0,
bit_depth: 16,
created_at: 2023-01-01

ogg_sample:
Expand All @@ -39,7 +40,8 @@ wav_sample:
md5_hash: 'wav_sample_md5_hash'
artist: 'artist2'
album: 'album3'
duration: 8.0
duration: 8.0,
bit_depth: 16,
created_at: 2023-01-04

opus_sample:
Expand Down Expand Up @@ -84,6 +86,7 @@ wma_sample:
artist: 'artist2'
album: 'album3'
duration: 8.0
bit_depth: 16,
created_at: 2023-01-06

various_artists_sample:
Expand Down
20 changes: 0 additions & 20 deletions test/jobs/attach_album_image_from_file_job_test.rb

This file was deleted.

21 changes: 12 additions & 9 deletions test/models/media_file_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,10 @@ class MediaFileTest < ActiveSupport::TestCase
assert_equal "m4a", MediaFile.format(file_fixture("artist1_album1.m4a"))
end

test "should get image from media file" do
cover_image_binary = file_fixture("cover_image.jpg").read.force_encoding("BINARY").strip

%w[artist1_album2.mp3 artist1_album1.m4a artist1_album1.flac artist2_album3.wav].each do |file|
assert_equal cover_image_binary, MediaFile.image(file_fixture(file))[:data].strip
assert_equal "jpeg", MediaFile.image(file_fixture(file))[:format]
end
end

test "should get tag info from mp3 file" do
tag_info = MediaFile.send(:get_tag_info, file_fixture("artist1_album2.mp3"))
tag_image_binary = tag_info[:image].read.force_encoding("BINARY").strip
cover_image_binary = file_fixture("cover_image.jpg").read.force_encoding("BINARY").strip

assert_equal "mp3_sample", tag_info[:name]
assert_equal "album2", tag_info[:album_name]
Expand All @@ -60,10 +53,13 @@ class MediaFileTest < ActiveSupport::TestCase
assert_equal 8, tag_info[:duration]
assert_equal 1984, tag_info[:year]
assert_equal "Rock", tag_info[:genre]
assert_equal cover_image_binary, tag_image_binary
end

test "should get tag info from flac file" do
tag_info = MediaFile.send(:get_tag_info, file_fixture("artist1_album1.flac"))
tag_image_binary = tag_info[:image].read.force_encoding("BINARY").strip
cover_image_binary = file_fixture("cover_image.jpg").read.force_encoding("BINARY").strip

assert_equal "flac_sample", tag_info[:name]
assert_equal "album1", tag_info[:album_name]
Expand All @@ -73,6 +69,7 @@ class MediaFileTest < ActiveSupport::TestCase
assert_equal 8, tag_info[:duration]
assert_equal 1984, tag_info[:year]
assert_equal "Rock", tag_info[:genre]
assert_equal cover_image_binary, tag_image_binary
end

test "should get tag info from ogg file" do
Expand All @@ -90,6 +87,8 @@ class MediaFileTest < ActiveSupport::TestCase

test "should get tag info from wav file" do
tag_info = MediaFile.send(:get_tag_info, file_fixture("artist2_album3.wav"))
tag_image_binary = tag_info[:image].read.force_encoding("BINARY").strip
cover_image_binary = file_fixture("cover_image.jpg").read.force_encoding("BINARY").strip

assert_equal "wav_sample", tag_info[:name]
assert_equal "album3", tag_info[:album_name]
Expand All @@ -99,6 +98,7 @@ class MediaFileTest < ActiveSupport::TestCase
assert_equal 8, tag_info[:duration]
assert_equal 1984, tag_info[:year]
assert_equal "Rock", tag_info[:genre]
assert_equal cover_image_binary, tag_image_binary
end

test "should get tag info from opus file" do
Expand All @@ -116,6 +116,8 @@ class MediaFileTest < ActiveSupport::TestCase

test "should get tag info from m4a file" do
tag_info = MediaFile.send(:get_tag_info, file_fixture("artist1_album1.m4a"))
tag_image_binary = tag_info[:image].read.force_encoding("BINARY").strip
cover_image_binary = file_fixture("cover_image.jpg").read.force_encoding("BINARY").strip

assert_equal "m4a_sample", tag_info[:name]
assert_equal "album1", tag_info[:album_name]
Expand All @@ -125,6 +127,7 @@ class MediaFileTest < ActiveSupport::TestCase
assert_equal 8, tag_info[:duration]
assert_equal 1984, tag_info[:year]
assert_equal "Rock", tag_info[:genre]
assert_equal cover_image_binary, tag_image_binary
end

test "should get tag info from oga file" do
Expand Down

0 comments on commit f29efd8

Please sign in to comment.