Просмотр файла app/Models/Down.php

Размер файла: 6.8Kb
  1. <?php
  2.  
  3. declare(strict_types=1);
  4.  
  5. namespace App\Models;
  6.  
  7. use App\Traits\UploadTrait;
  8. use Exception;
  9. use FFMpeg\FFProbe;
  10. use FFMpeg\Format\Video\X264;
  11. use Illuminate\Database\Eloquent\Collection;
  12. use Illuminate\Database\Eloquent\Relations\BelongsTo;
  13. use Illuminate\Database\Eloquent\Relations\HasMany;
  14. use Illuminate\Database\Eloquent\Relations\MorphMany;
  15. use Illuminate\Database\Eloquent\Relations\MorphOne;
  16. use Illuminate\Http\UploadedFile;
  17. use Illuminate\Support\HtmlString;
  18.  
  19. /**
  20. * Class Down
  21. *
  22. * @property int id
  23. * @property int category_id
  24. * @property string title
  25. * @property string text
  26. * @property int user_id
  27. * @property int created_at
  28. * @property int count_comments
  29. * @property int rating
  30. * @property int loads
  31. * @property int active
  32. * @property int updated_at
  33. * @property Collection files
  34. * @property Collection comments
  35. * @property Load category
  36. */
  37. class Down extends BaseModel
  38. {
  39. use UploadTrait;
  40.  
  41. /**
  42. * Indicates if the model should be timestamped.
  43. *
  44. * @var bool
  45. */
  46. public $timestamps = false;
  47.  
  48. /**
  49. * The attributes that aren't mass assignable.
  50. *
  51. * @var array
  52. */
  53. protected $guarded = [];
  54.  
  55. /**
  56. * Директория загрузки файлов
  57. *
  58. * @var string
  59. */
  60. public $uploadPath = '/uploads/files';
  61.  
  62. /**
  63. * Counting field
  64. *
  65. * @var string
  66. */
  67. public $countingField = 'loads';
  68.  
  69. /**
  70. * Список расширений доступных для просмотра в архиве
  71. *
  72. * @var array
  73. */
  74. public static $viewExt = ['xml', 'wml', 'asp', 'aspx', 'shtml', 'htm', 'phtml', 'html', 'php', 'htt', 'dat', 'tpl', 'htaccess', 'pl', 'js', 'jsp', 'css', 'txt', 'sql', 'gif', 'png', 'bmp', 'wbmp', 'jpg', 'jpeg', 'env', 'gitignore', 'json', 'yml', 'md'];
  75.  
  76. /**
  77. * Morph name
  78. *
  79. * @var string
  80. */
  81. public static $morphName = 'downs';
  82.  
  83. /**
  84. * Возвращает категорию загрузок
  85. *
  86. * @return BelongsTo
  87. */
  88. public function category(): BelongsTo
  89. {
  90. return $this->belongsTo(Load::class, 'category_id')->withDefault();
  91. }
  92.  
  93. /**
  94. * Возвращает комментарии
  95. */
  96. public function comments(): MorphMany
  97. {
  98. return $this->morphMany(Comment::class, 'relate')->with('relate');
  99. }
  100.  
  101. /**
  102. * Возвращает связь с голосованием
  103. *
  104. * @return morphOne
  105. */
  106. public function polling(): morphOne
  107. {
  108. return $this->morphOne(Polling::class, 'relate')->where('user_id', getUser('id'));
  109. }
  110.  
  111. /**
  112. * Возвращает последнии комментарии к файлу
  113. *
  114. * @param int $limit
  115. * @return HasMany
  116. */
  117. public function lastComments(int $limit = 15): HasMany
  118. {
  119. return $this->hasMany(Comment::class, 'relate_id')
  120. ->where('relate_type', self::$morphName)
  121. ->orderBy('created_at', 'desc')
  122. ->with('user')
  123. ->limit($limit);
  124. }
  125.  
  126. /**
  127. * Возвращает загруженные файлы
  128. */
  129. public function files(): MorphMany
  130. {
  131. return $this->morphMany(File::class, 'relate');
  132. }
  133.  
  134. /**
  135. * Возвращает файлы
  136. *
  137. * @return Collection
  138. */
  139. public function getFiles(): Collection
  140. {
  141. return $this->files->filter(static function (File $value, $key) {
  142. return ! $value->isImage();
  143. });
  144. }
  145.  
  146. /**
  147. * Возвращает картинки
  148. *
  149. * @return Collection
  150. */
  151. public function getImages(): Collection
  152. {
  153. return $this->files->filter(static function (File $value, $key) {
  154. return $value->isImage();
  155. });
  156. }
  157.  
  158. /**
  159. * Возвращает сокращенный текст описания
  160. *
  161. * @param int $words
  162. * @return HtmlString
  163. */
  164. public function shortText(int $words = 50): HtmlString
  165. {
  166. if (strlen($this->text) > $words) {
  167. $this->text = bbCodeTruncate($this->text, $words);
  168. }
  169.  
  170. return new HtmlString($this->text);
  171. }
  172.  
  173. /**
  174. * Возвращает массив доступных расширений для просмотра в архиве
  175. *
  176. * @return array
  177. */
  178. public static function getViewExt(): array
  179. {
  180. return self::$viewExt;
  181. }
  182.  
  183. /**
  184. * Загружает файл
  185. *
  186. * @param UploadedFile $file
  187. * @return array
  188. */
  189. public function uploadAndConvertFile(UploadedFile $file): array
  190. {
  191. $uploadFile = $this->uploadFile($file);
  192. $this->convertVideo($uploadFile);
  193.  
  194. return $uploadFile;
  195. }
  196.  
  197. /**
  198. * Конвертирует видео
  199. *
  200. * @param array $file
  201. * @return void
  202. */
  203. public function convertVideo(array $file): void
  204. {
  205. $isVideo = strpos($file['mime'], 'video/') !== false;
  206.  
  207. // Обработка видео
  208. if ($isVideo && config('ffmpeg.enabled')) {
  209. $ffconfig = [
  210. 'ffmpeg.binaries' => config('ffmpeg.path'),
  211. 'ffprobe.binaries' => config('ffmpeg.ffprobe.path'),
  212. 'ffmpeg.threads' => config('ffmpeg.threads'),
  213. 'timeout' => config('ffmpeg.timeout'),
  214. ];
  215.  
  216. // Сохраняем скрин с 5 секунды
  217. /*$ffmpeg = FFMpeg::create($ffconfig);
  218. $video = $ffmpeg->open(public_path($file['path']));
  219.  
  220. $frame = $video->frame(TimeCode::fromSeconds(5));
  221. $frame->save(public_path($file['path'] . '.jpg'));
  222.  
  223. $this->files()->create([
  224. 'hash' => $file['path'] . '.jpg',
  225. 'name' => 'screenshot.jpg',
  226. 'size' => filesize(public_path($file['path'] . '.jpg')),
  227. 'user_id' => getUser('id'),
  228. 'created_at' => SITETIME,
  229. ]);*/
  230.  
  231. // Перекодируем видео в h264
  232. $ffprobe = FFProbe::create($ffconfig);
  233. $video = $ffprobe
  234. ->streams(public_path($file['path']))
  235. ->videos()
  236. ->first();
  237.  
  238. if ($video && $file['extension'] === 'mp4' && $video->get('codec_name') !== 'h264') {
  239. $format = new X264('libmp3lame', 'libx264');
  240. $video->save($format, public_path($file['path'] . '.convert'));
  241.  
  242. rename(public_path($file['path'] . '.convert'), public_path($file['path']));
  243. }
  244. }
  245. }
  246.  
  247. /**
  248. * Удаление загрузки и загруженных файлов
  249. *
  250. * @return bool|null
  251. * @throws Exception
  252. */
  253. public function delete(): ?bool
  254. {
  255. $this->files->each(static function (File $file) {
  256. $file->delete();
  257. });
  258.  
  259. return parent::delete();
  260. }
  261. }