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

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