diff --git a/app/logical/media_file.rb b/app/logical/media_file.rb index 66ea8cdd6..fad6da362 100644 --- a/app/logical/media_file.rb +++ b/app/logical/media_file.rb @@ -54,7 +54,12 @@ class MediaFile :png when /\ACWS/, /\AFWS/, /\AZWS/ :swf - when /\x1a\x45\xdf\xa3/n + + # This detects the Matroska (.mkv) header. WebM files have a DocType of "webm", which is checked later in `MediaFile::Video#is_supported?`. + # + # https://www.rfc-editor.org/rfc/rfc8794.html#section-8.1 + # https://www.webmproject.org/docs/container/ + when /\A\x1a\x45\xdf\xa3/n :webm # https://www.ftyps.com diff --git a/app/logical/media_file/video.rb b/app/logical/media_file/video.rb index 0cc1ca4e3..197f01b3d 100644 --- a/app/logical/media_file/video.rb +++ b/app/logical/media_file/video.rb @@ -15,6 +15,17 @@ class MediaFile::Video < MediaFile preview_frame.preview(max_width, max_height, **options) end + def is_supported? + case file_ext + when :webm + metadata["Matroska:DocType"] == "webm" + when :mp4 + true + else + false + end + end + private def video diff --git a/test/components/post_preview_component_test.rb b/test/components/post_preview_component_test.rb index c32794fa7..06003769a 100644 --- a/test/components/post_preview_component_test.rb +++ b/test/components/post_preview_component_test.rb @@ -20,7 +20,7 @@ class PostPreviewComponentTest < ViewComponent::TestCase context "for a video post" do should "render" do - @post = create(:post_with_file, filename: "test-512x512.webm").reload + @post = create(:post_with_file, filename: "webm/test-512x512.webm").reload node = render_preview(@post, current_user: User.anonymous) assert_equal(post_path(@post), node.css("article a").attr("href").value) diff --git a/test/files/webm/test-512x512.mkv b/test/files/webm/test-512x512.mkv new file mode 100644 index 000000000..366643872 Binary files /dev/null and b/test/files/webm/test-512x512.mkv differ diff --git a/test/files/test-512x512.webm b/test/files/webm/test-512x512.webm similarity index 100% rename from test/files/test-512x512.webm rename to test/files/webm/test-512x512.webm diff --git a/test/functional/uploads_controller_test.rb b/test/functional/uploads_controller_test.rb index 9e2296386..55c7b8cd0 100644 --- a/test/functional/uploads_controller_test.rb +++ b/test/functional/uploads_controller_test.rb @@ -224,6 +224,13 @@ class UploadsControllerTest < ActionDispatch::IntegrationTest end end + context "for an unsupported video file" do + should "fail for a .mkv file" do + create_upload!("test/files/webm/test-512x512.mkv", user: @user) + assert_match("File type is not supported", Upload.last.error) + end + end + context "for a video longer than the video length limit" do should "fail for a regular user" do create_upload!("https://cdn.donmai.us/original/63/cb/63cb09f2526ef3ac14f11c011516ad9b.webm", user: @user) @@ -293,7 +300,7 @@ class UploadsControllerTest < ActionDispatch::IntegrationTest should_upload_successfully("test/files/test-static-32x32.gif") should_upload_successfully("test/files/test-animated-86x52.gif") should_upload_successfully("test/files/test-300x300.mp4") - should_upload_successfully("test/files/test-512x512.webm") + should_upload_successfully("test/files/webm/test-512x512.webm") should_upload_successfully("test/files/test-audio.m4v") # should_upload_successfully("test/files/compressed.swf") diff --git a/test/unit/media_file_test.rb b/test/unit/media_file_test.rb index 804eeca8f..07bc3c9a6 100644 --- a/test/unit/media_file_test.rb +++ b/test/unit/media_file_test.rb @@ -27,7 +27,7 @@ class MediaFileTest < ActiveSupport::TestCase should "determine the correct dimensions for a webm file" do skip unless MediaFile.videos_enabled? - assert_equal([512, 512], MediaFile.open("test/files/test-512x512.webm").dimensions) + assert_equal([512, 512], MediaFile.open("test/files/webm/test-512x512.webm").dimensions) end should "determine the correct dimensions for a mp4 file" do @@ -58,7 +58,7 @@ class MediaFileTest < ActiveSupport::TestCase should "work for a video if called twice" do skip unless MediaFile.videos_enabled? - mf = MediaFile.open("test/files/test-512x512.webm") + mf = MediaFile.open("test/files/webm/test-512x512.webm") assert_equal([512, 512], mf.dimensions) assert_equal([512, 512], mf.dimensions) @@ -96,7 +96,7 @@ class MediaFileTest < ActiveSupport::TestCase end should "determine the correct extension for a webm file" do - assert_equal(:webm, MediaFile.open("test/files/test-512x512.webm").file_ext) + assert_equal(:webm, MediaFile.open("test/files/webm/test-512x512.webm").file_ext) end should "determine the correct extension for a mp4 file" do @@ -150,7 +150,7 @@ class MediaFileTest < ActiveSupport::TestCase should "generate a preview image for a video" do skip unless MediaFile.videos_enabled? - assert_equal([150, 150], MediaFile.open("test/files/test-512x512.webm").preview(150, 150).dimensions) + assert_equal([150, 150], MediaFile.open("test/files/webm/test-512x512.webm").preview(150, 150).dimensions) assert_equal([150, 150], MediaFile.open("test/files/test-300x300.mp4").preview(150, 150).dimensions) end @@ -204,11 +204,17 @@ class MediaFileTest < ActiveSupport::TestCase context "for a webm file" do should "determine the duration of the video" do - file = MediaFile.open("test/files/test-512x512.webm") + file = MediaFile.open("test/files/webm/test-512x512.webm") assert_equal(0.48, file.duration) assert_equal(10/0.48, file.frame_rate) assert_equal(10, file.frame_count) end + + should "not detect .mkv files as .webm" do + file = MediaFile.open("test/files/webm/test-512x512.mkv") + + assert_equal(false, file.is_supported?) + end end context "a compressed SWF file" do diff --git a/test/unit/post_query_builder_test.rb b/test/unit/post_query_builder_test.rb index 7c94b0028..003f5cdd1 100644 --- a/test/unit/post_query_builder_test.rb +++ b/test/unit/post_query_builder_test.rb @@ -775,7 +775,7 @@ class PostQueryBuilderTest < ActiveSupport::TestCase end should "return posts for the duration: metatag" do - post = create(:post, media_asset: create(:media_asset, file: "test/files/test-512x512.webm")) + post = create(:post, media_asset: create(:media_asset, file: "test/files/webm/test-512x512.webm")) assert_tag_match([post], "duration:0.48") assert_tag_match([post], "duration:>0.4")