MediaCloudUrlRewrite.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. <?php
  2. namespace App\Console\Commands;
  3. use App\Avatar;
  4. use App\Media;
  5. use Illuminate\Console\Command;
  6. use Illuminate\Contracts\Console\PromptsForMissingInput;
  7. use Storage;
  8. use function Laravel\Prompts\select;
  9. class MediaCloudUrlRewrite extends Command implements PromptsForMissingInput
  10. {
  11. /**
  12. * The name and signature of the console command.
  13. *
  14. * @var string
  15. */
  16. protected $signature = 'media:cloud-url-rewrite {oldDomain} {newDomain}';
  17. /**
  18. * Prompt for missing input arguments using the returned questions.
  19. *
  20. * @return array
  21. */
  22. protected function promptForMissingArgumentsUsing()
  23. {
  24. return [
  25. 'oldDomain' => 'The old S3 domain',
  26. 'newDomain' => 'The new S3 domain',
  27. ];
  28. }
  29. /**
  30. * The console command description.
  31. *
  32. * @var string
  33. */
  34. protected $description = 'Rewrite S3 media urls from local users';
  35. /**
  36. * Execute the console command.
  37. */
  38. public function handle()
  39. {
  40. $this->preflightCheck();
  41. $this->bootMessage();
  42. $this->confirmCloudUrl();
  43. $this->handleTask();
  44. }
  45. protected function preflightCheck()
  46. {
  47. if (! (bool) config_cache('pixelfed.cloud_storage')) {
  48. $this->info('Error: Cloud storage is not enabled! Please enable before proceeding.');
  49. $this->error('Aborting...');
  50. exit;
  51. }
  52. }
  53. protected function bootMessage()
  54. {
  55. $this->info(' ____ _ ______ __ ');
  56. $this->info(' / __ \(_) _____ / / __/__ ____/ / ');
  57. $this->info(' / /_/ / / |/_/ _ \/ / /_/ _ \/ __ / ');
  58. $this->info(' / ____/ /> </ __/ / __/ __/ /_/ / ');
  59. $this->info(' /_/ /_/_/|_|\___/_/_/ \___/\__,_/ ');
  60. $this->info(' ');
  61. $this->info(' Media Cloud Url Rewrite Tool');
  62. $this->info(' ===');
  63. $this->info(' Old S3: '.trim($this->argument('oldDomain')));
  64. $this->info(' New S3: '.trim($this->argument('newDomain')));
  65. $this->info(' ');
  66. }
  67. protected function confirmCloudUrl()
  68. {
  69. $disk = Storage::disk(config('filesystems.cloud'))->url('test');
  70. $domain = parse_url($disk, PHP_URL_HOST);
  71. if (trim($this->argument('newDomain')) !== $domain) {
  72. $this->error('Error: The new S3 domain you entered is not currently configured');
  73. exit;
  74. }
  75. if (! $this->confirm('Confirm this is correct')) {
  76. $this->error('Aborting...');
  77. exit;
  78. }
  79. }
  80. protected function handleTask()
  81. {
  82. $task = select(
  83. label: 'What action would you like to perform?',
  84. options: ['Migrate All', 'Migrate Media', 'Migrate Avatars']
  85. );
  86. switch ($task) {
  87. case 'Migrate All':
  88. $this->updateMediaUrls();
  89. $this->updateAvatarUrls();
  90. break;
  91. case 'Migrate Media':
  92. $this->updateMediaUrls();
  93. break;
  94. case 'Migrate Avatars':
  95. $this->updateAvatarUrls();
  96. break;
  97. default:
  98. $this->error('Invalid selection');
  99. return;
  100. break;
  101. }
  102. }
  103. protected function updateMediaUrls()
  104. {
  105. $this->info('Updating media urls...');
  106. $oldDomain = trim($this->argument('oldDomain'));
  107. $newDomain = trim($this->argument('newDomain'));
  108. $disk = Storage::disk(config('filesystems.cloud'));
  109. $count = Media::whereNotNull('cdn_url')->count();
  110. $bar = $this->output->createProgressBar($count);
  111. $counter = 0;
  112. $bar->start();
  113. foreach (Media::whereNotNull('cdn_url')->lazyById(1000, 'id') as $media) {
  114. if (strncmp($media->media_path, 'http', 4) === 0) {
  115. $bar->advance();
  116. continue;
  117. }
  118. $cdnHost = parse_url($media->cdn_url, PHP_URL_HOST);
  119. if ($oldDomain != $cdnHost || $newDomain == $cdnHost) {
  120. $bar->advance();
  121. continue;
  122. }
  123. $media->cdn_url = str_replace($oldDomain, $newDomain, $media->cdn_url);
  124. if ($media->thumbnail_url != null) {
  125. $thumbHost = parse_url($media->thumbnail_url, PHP_URL_HOST);
  126. if ($thumbHost == $oldDomain) {
  127. $thumbUrl = $disk->url($media->thumbnail_path);
  128. $media->thumbnail_url = $thumbUrl;
  129. }
  130. }
  131. if ($media->optimized_url != null) {
  132. $optiHost = parse_url($media->optimized_url, PHP_URL_HOST);
  133. if ($optiHost == $oldDomain) {
  134. $optiUrl = str_replace($oldDomain, $newDomain, $media->optimized_url);
  135. $media->optimized_url = $optiUrl;
  136. }
  137. }
  138. $media->save();
  139. $counter++;
  140. $bar->advance();
  141. }
  142. $bar->finish();
  143. $this->line(' ');
  144. $this->info('Finished! Updated '.$counter.' total records!');
  145. $this->line(' ');
  146. $this->info('Tip: Run `php artisan cache:clear` to purge cached urls');
  147. }
  148. protected function updateAvatarUrls()
  149. {
  150. $this->info('Updating avatar urls...');
  151. $oldDomain = trim($this->argument('oldDomain'));
  152. $newDomain = trim($this->argument('newDomain'));
  153. $disk = Storage::disk(config('filesystems.cloud'));
  154. $count = Avatar::count();
  155. $bar = $this->output->createProgressBar($count);
  156. $counter = 0;
  157. $bar->start();
  158. foreach (Avatar::lazyById(1000, 'id') as $avatar) {
  159. if (! $avatar->cdn_url) {
  160. $bar->advance();
  161. continue;
  162. }
  163. $cdnHost = parse_url($avatar->cdn_url, PHP_URL_HOST);
  164. if (strcasecmp($oldDomain, $cdnHost) !== 0 || strcasecmp($newDomain, $cdnHost) === 0) {
  165. $bar->advance();
  166. continue;
  167. }
  168. $avatar->cdn_url = str_replace($oldDomain, $newDomain, $avatar->cdn_url);
  169. $avatar->save();
  170. $counter++;
  171. $bar->advance();
  172. }
  173. $bar->finish();
  174. $this->line(' ');
  175. $this->info('Finished! Updated '.$counter.' total records!');
  176. $this->line(' ');
  177. $this->info('Tip: Run `php artisan cache:clear` to purge cached urls');
  178. }
  179. }