-
-
Notifications
You must be signed in to change notification settings - Fork 135
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #333 from igorkasyanchuk/301-handle-audio-media
301 handle audio media
- Loading branch information
Showing
13 changed files
with
168 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'open3' | ||
require_relative 'shared/asv_ff_probable' | ||
|
||
module ActiveStorageValidations | ||
# = ActiveStorageValidations Audio \Analyzer | ||
# | ||
# Extracts the following from an audio attachable: | ||
# | ||
# * Duration (seconds) | ||
# * Bit rate (bits/s) | ||
# * Sample rate (hertz) | ||
# * Tags (internal metadata) | ||
# | ||
# Example: | ||
# | ||
# ActiveStorageValidations::Analyzer::AudioAnalyzer.new(attachable).metadata | ||
# # => { duration: 5.0, bit_rate: 320340, sample_rate: 44100, tags: { encoder: "Lavc57.64", ... } } | ||
# | ||
# This analyzer requires the {FFmpeg}[https://www.ffmpeg.org] system library, which is not provided by \Rails. | ||
class Analyzer::AudioAnalyzer < Analyzer | ||
include ASVFFProbable | ||
|
||
def metadata | ||
read_media do |media| | ||
{ | ||
duration: duration, | ||
bit_rate: bit_rate, | ||
sample_rate: sample_rate, | ||
tags: tags | ||
}.compact | ||
end | ||
end | ||
|
||
private | ||
|
||
def duration | ||
duration = audio_stream["duration"] | ||
Float(duration).round(1) if duration | ||
end | ||
|
||
def bit_rate | ||
bit_rate = audio_stream["bit_rate"] | ||
Integer(bit_rate) if bit_rate | ||
end | ||
|
||
def sample_rate | ||
sample_rate = audio_stream["sample_rate"] | ||
Integer(sample_rate) if sample_rate | ||
end | ||
|
||
def tags | ||
tags = audio_stream["tags"] | ||
Hash(tags) if tags | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
lib/active_storage_validations/analyzer/shared/asv_ff_probable.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# frozen_string_literal: true | ||
|
||
module ActiveStorageValidations | ||
# ActiveStorageValidations:::ASVFFProbable | ||
# | ||
# Validator helper methods for analyzers using FFprobe. | ||
module ASVFFProbable | ||
extend ActiveSupport::Concern | ||
|
||
private | ||
|
||
def read_media | ||
Tempfile.create(binmode: true) do |tempfile| | ||
begin | ||
if media(tempfile).present? | ||
yield media(tempfile) | ||
else | ||
logger.info "Skipping file metadata analysis because ffprobe doesn't support the file" | ||
{} | ||
end | ||
ensure | ||
tempfile.close | ||
end | ||
end | ||
rescue Errno::ENOENT | ||
logger.info "Skipping file metadata analysis because ffprobe isn't installed" | ||
{} | ||
end | ||
|
||
def media_from_path(path) | ||
instrument(File.basename(ffprobe_path)) do | ||
stdout, stderr, status = Open3.capture3( | ||
ffprobe_path, | ||
"-print_format", "json", | ||
"-show_streams", | ||
"-show_format", | ||
"-v", "error", | ||
path | ||
) | ||
|
||
status.success? ? JSON.parse(stdout) : nil | ||
end | ||
end | ||
|
||
def ffprobe_path | ||
ActiveStorage.paths[:ffprobe] || "ffprobe" | ||
end | ||
|
||
def video_stream | ||
@video_stream ||= streams.detect { |stream| stream["codec_type"] == "video" } || {} | ||
end | ||
|
||
def audio_stream | ||
@audio_stream ||= streams.detect { |stream| stream["codec_type"] == "audio" } || {} | ||
end | ||
|
||
def streams | ||
@streams ||= @media["streams"] || [] | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# frozen_string_literal: true | ||
|
||
require "test_helper" | ||
require 'analyzers/support/analyzer_helpers' | ||
require 'analyzers/shared_examples/returns_the_right_metadata_for_any_attachable' | ||
|
||
describe ActiveStorageValidations::Analyzer::AudioAnalyzer do | ||
include AnalyzerHelpers | ||
|
||
let(:analyzer_klass) { ActiveStorageValidations::Analyzer::AudioAnalyzer } | ||
let(:analyzer) { analyzer_klass.new(attachable) } | ||
|
||
let(:media_extension) { '.mp3' } | ||
let(:media_filename) { "audio#{media_extension}" } | ||
let(:media_filename_over_10ko) { "audio_28ko#{media_extension}" } | ||
let(:media_filename_rotated) { "audio#{media_extension}" } | ||
let(:media_filename_0ko) { "audio_0ko#{media_extension}" } | ||
let(:media_path) { Rails.root.join('public', media_filename) } | ||
let(:media_io) { File.open(media_path) } | ||
let(:media_content_type) { 'audio/mp3' } | ||
let(:media_content_type_rotated) { media_content_type } | ||
let(:expected_metadata) { { duration: 1.1, bit_rate: 32000, sample_rate: 44100, tags: { "encoder" => "Lavc60.3."} } } | ||
let(:expected_metadata_over_10ko) { { duration: 2.1, bit_rate: 107141, sample_rate: 44100, tags: { "encoder" => "LAME3.100"} } } | ||
let(:expected_metadata_rotated) { { duration: 1.1, bit_rate: 32000, sample_rate: 44100, tags: { "encoder" => "Lavc60.3."} } } | ||
|
||
include ReturnsTheRightMetadataForAnyAttachable | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Empty file.
Binary file not shown.