Skip to content

Commit 4f8a4fa

Browse files
authored
Skip downloading video and audio attachments (#2608)
1 parent cf9913d commit 4f8a4fa

File tree

3 files changed

+151
-1
lines changed

3 files changed

+151
-1
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: patch
2+
Type: changed
3+
4+
Skip downloading video and audio attachments, embedding remote URLs directly to avoid storage limits.

includes/class-attachments.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,19 +483,33 @@ private static function save_attachment( $attachment_data, $post_id, $author_id
483483
/**
484484
* Save a file directly to uploads/activitypub/{type}/{id}/.
485485
*
486+
* For video and audio files, returns the remote URL directly without downloading
487+
* to avoid storage overhead for large media files.
488+
*
486489
* @param array $attachment_data The normalized attachment data.
487490
* @param int $object_id The post or comment ID to attach to.
488491
* @param string $object_type The object type ('post' or 'comment').
489492
*
490493
* @return array|\WP_Error {
491494
* Array of file data on success, WP_Error on failure.
492495
*
493-
* @type string $url Full URL to the saved file.
496+
* @type string $url Full URL to the saved file (or remote URL for video/audio).
494497
* @type string $mime_type MIME type of the file.
495498
* @type string $alt Alt text from attachment name field.
496499
* }
497500
*/
498501
private static function save_file( $attachment_data, $object_id, $object_type ) {
502+
$mime_type = $attachment_data['mediaType'] ?? '';
503+
504+
// Skip download for video and audio files - use remote URL directly.
505+
if ( str_starts_with( $mime_type, 'video/' ) || str_starts_with( $mime_type, 'audio/' ) ) {
506+
return array(
507+
'url' => $attachment_data['url'],
508+
'mime_type' => $attachment_data['mediaType'],
509+
'alt' => $attachment_data['name'] ?? '',
510+
);
511+
}
512+
499513
if ( ! \function_exists( 'download_url' ) ) {
500514
require_once ABSPATH . 'wp-admin/includes/file.php';
501515
}

tests/phpunit/tests/includes/class-test-attachments.php

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,4 +664,136 @@ public function test_file_storage_filename_strips_query_parameters() {
664664
$this->assertStringNotContainsString( '?', $result[0]['url'] );
665665
$this->assertStringNotContainsString( 'size=', $result[0]['url'] );
666666
}
667+
668+
/**
669+
* Test that video attachments use remote URL directly without downloading.
670+
*
671+
* @covers ::save_file
672+
*/
673+
public function test_video_uses_remote_url() {
674+
// Create a test post.
675+
$post_id = self::factory()->post->create(
676+
array(
677+
'post_type' => 'ap_post',
678+
'post_content' => 'Test video content',
679+
)
680+
);
681+
682+
$attachments = array(
683+
array(
684+
'url' => 'https://example.com/video.mp4',
685+
'mediaType' => 'video/mp4',
686+
'name' => 'Test Video',
687+
'type' => 'Video',
688+
),
689+
);
690+
691+
$result = Attachments::import_post_files( $attachments, $post_id );
692+
693+
$this->assertIsArray( $result );
694+
$this->assertCount( 1, $result );
695+
696+
// Verify the URL is the original remote URL (not downloaded).
697+
$this->assertEquals( 'https://example.com/video.mp4', $result[0]['url'] );
698+
$this->assertEquals( 'video/mp4', $result[0]['mime_type'] );
699+
$this->assertEquals( 'Test Video', $result[0]['alt'] );
700+
701+
// Verify content was updated with video block.
702+
$post = get_post( $post_id );
703+
$this->assertStringContainsString( '<!-- wp:video', $post->post_content );
704+
$this->assertStringContainsString( 'https://example.com/video.mp4', $post->post_content );
705+
}
706+
707+
/**
708+
* Test that audio attachments use remote URL directly without downloading.
709+
*
710+
* @covers ::save_file
711+
*/
712+
public function test_audio_uses_remote_url() {
713+
// Create a test post.
714+
$post_id = self::factory()->post->create(
715+
array(
716+
'post_type' => 'ap_post',
717+
'post_content' => 'Test audio content',
718+
)
719+
);
720+
721+
$attachments = array(
722+
array(
723+
'url' => 'https://example.com/podcast.mp3',
724+
'mediaType' => 'audio/mpeg',
725+
'name' => 'Test Audio',
726+
'type' => 'Audio',
727+
),
728+
);
729+
730+
$result = Attachments::import_post_files( $attachments, $post_id );
731+
732+
$this->assertIsArray( $result );
733+
$this->assertCount( 1, $result );
734+
735+
// Verify the URL is the original remote URL (not downloaded).
736+
$this->assertEquals( 'https://example.com/podcast.mp3', $result[0]['url'] );
737+
$this->assertEquals( 'audio/mpeg', $result[0]['mime_type'] );
738+
$this->assertEquals( 'Test Audio', $result[0]['alt'] );
739+
740+
// Verify content was updated with audio block.
741+
$post = get_post( $post_id );
742+
$this->assertStringContainsString( '<!-- wp:audio', $post->post_content );
743+
$this->assertStringContainsString( 'https://example.com/podcast.mp3', $post->post_content );
744+
}
745+
746+
/**
747+
* Test mixed attachments with images, video, and audio.
748+
*
749+
* @covers ::import_post_files
750+
* @covers ::save_file
751+
*/
752+
public function test_mixed_attachments_images_video_audio() {
753+
// Create a test post.
754+
$post_id = self::factory()->post->create(
755+
array(
756+
'post_type' => 'ap_post',
757+
'post_content' => 'Mixed media content',
758+
)
759+
);
760+
761+
$attachments = array(
762+
array(
763+
'url' => 'https://example.com/image.jpg',
764+
'mediaType' => 'image/jpeg',
765+
'name' => 'Test Image',
766+
'type' => 'Image',
767+
),
768+
array(
769+
'url' => 'https://example.com/video.mp4',
770+
'mediaType' => 'video/mp4',
771+
'name' => 'Test Video',
772+
'type' => 'Video',
773+
),
774+
array(
775+
'url' => 'https://example.com/audio.mp3',
776+
'mediaType' => 'audio/mpeg',
777+
'name' => 'Test Audio',
778+
'type' => 'Audio',
779+
),
780+
);
781+
782+
$result = Attachments::import_post_files( $attachments, $post_id );
783+
784+
$this->assertIsArray( $result );
785+
$this->assertCount( 3, $result );
786+
787+
// Image should be downloaded to local storage.
788+
$this->assertStringContainsString( 'activitypub/ap_posts', $result[0]['url'] );
789+
$this->assertEquals( 'image/jpeg', $result[0]['mime_type'] );
790+
791+
// Video should use remote URL.
792+
$this->assertEquals( 'https://example.com/video.mp4', $result[1]['url'] );
793+
$this->assertEquals( 'video/mp4', $result[1]['mime_type'] );
794+
795+
// Audio should use remote URL.
796+
$this->assertEquals( 'https://example.com/audio.mp3', $result[2]['url'] );
797+
$this->assertEquals( 'audio/mpeg', $result[2]['mime_type'] );
798+
}
667799
}

0 commit comments

Comments
 (0)