From 4fe52e5a69eec82a7295481b80de731f81f09816 Mon Sep 17 00:00:00 2001 From: Rhilip Date: Fri, 9 Aug 2019 08:16:54 +0800 Subject: [PATCH] feat(Subtitle): Add Base Subtitle Page 1. Add subtitle search, upload, download support 2. change the http server config about `buffer_output_size` , which default is 2M, may let server can't sent file bigger than 2M. So change it to 32M. --- CHANGELOG.md | 7 +- apps/config/httpd.php | 1 + apps/controllers/SubtitlesController.php | 64 +++++++++ apps/models/form/Subtitles/DeleteForm.php | 17 +++ apps/models/form/Subtitles/DownloadForm.php | 49 +++++++ apps/models/form/Subtitles/SearchForm.php | 35 +++++ apps/models/form/Subtitles/UploadForm.php | 105 ++++++++++++++ .../form/Traits/isValidSubtitleTrait.php | 42 ++++++ .../form/Traits/isValidTorrentTrait.php | 10 +- apps/views/subtitles/search.php | 135 ++++++++++++++++++ framework/Http/UploadFile.php | 4 + 11 files changed, 464 insertions(+), 5 deletions(-) create mode 100644 apps/controllers/SubtitlesController.php create mode 100644 apps/models/form/Subtitles/DeleteForm.php create mode 100644 apps/models/form/Subtitles/DownloadForm.php create mode 100644 apps/models/form/Subtitles/SearchForm.php create mode 100644 apps/models/form/Subtitles/UploadForm.php create mode 100644 apps/models/form/Traits/isValidSubtitleTrait.php create mode 100644 apps/views/subtitles/search.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 70e8000..9e3c7c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,19 +9,20 @@ ### Feat - **Category:** Add Categories Manage Pane -- **Category:** Add Image and class_name support - **Category:** Add Categories Support when upload torrent +- **Category:** Add Image and class_name support - **Category:** Add Default sprite image of category - **Crontab:** Move From Timer to Process - **Editor:** Support wysibb editor - **Gravatar:** Add support of gravatar -- **Pager:** Add Pager Support - **Pager:** Torrents/{SearchForm,TagsForm} +- **Pager:** Add Pager Support - **Process:** Add custom Process Support - **Process:** Clean Components before sleep +- **RateLimit:** Add actionRateLimitCheckTrait - **Redis:** Add mutiDelete() function for Redis -- **Tracker:** Move From Timer to Process - **Tracker:** Add `retry in` field when failed +- **Tracker:** Move From Timer to Process - **User:** Add Bonus And Unread Messsage count - **UserInfo:** Add Cache Lock of user access_{time,ip} update - **Validator:** Add autoload from requests function diff --git a/apps/config/httpd.php b/apps/config/httpd.php index 44a6947..17d050d 100644 --- a/apps/config/httpd.php +++ b/apps/config/httpd.php @@ -84,6 +84,7 @@ 'max_request' => 3000, // 进程的最大任务数 'max_wait_time' => 60, // 退出等待时间 'package_max_length' => 6242880, // 最大上传包大小,单位 Bytes + 'buffer_output_size' => 33554432, // 发送缓存区大小,影响向用户发送文件的最大大小,单位 Bytes 'reload_async' => true, // 异步安全重启 /* 'user' => 'www', // 子进程运行用户 */ ], diff --git a/apps/controllers/SubtitlesController.php b/apps/controllers/SubtitlesController.php new file mode 100644 index 0000000..2b971de --- /dev/null +++ b/apps/controllers/SubtitlesController.php @@ -0,0 +1,64 @@ +actionSearch(); + } + + public function actionSearch() + { + $search = new Subtitles\SearchForm(); + if (false === $success = $search->validate()) { + return $this->render('action/action_fail'); + } + return $this->render('subtitles/search',['search' => $search]); + } + + public function actionUpload() + { + if (app()->request->isPost()) { + $upload = new Subtitles\UploadForm(); + if (false === $success = $upload->validate()) { + return $this->render('action/action_fail',['msg' => $upload->getError()]); // TODO add redirect + } else { + $upload->flush(); + return $this->render('action/action_success'); // TODO add redirect + } + } + return $this->actionSearch(); + } + + public function actionDownload() + { + $download = new Subtitles\DownloadForm(); + if (false === $success = $download->validate()) { + return $this->render('action/action_fail'); + } + + return $download->sendFileContentToClient(); + } + + public function actionDelete() + { + $delete = new Subtitles\DeleteForm(); + if (false === $success = $delete->validate()) { + return $this->render('action/action_fail'); // TODO add redirect + } else { + return $this->render('action/action_success'); // TODO add redirect + } + } +} diff --git a/apps/models/form/Subtitles/DeleteForm.php b/apps/models/form/Subtitles/DeleteForm.php new file mode 100644 index 0000000..1b9ca69 --- /dev/null +++ b/apps/models/form/Subtitles/DeleteForm.php @@ -0,0 +1,17 @@ +pdo->createCommand('UPDATE `subtitles` SET `hits` = `hits` + 1 WHERE id = :sid')->bindParams([ + 'sid' => $this->id + ])->execute(); + } + + protected function getSendFileName(): string + { + return $this->subtitle['filename']; + } + + protected function getSendFileContentLength(): int + { + return (int)$this->subtitle['size']; + } + + protected function hookFileContentSend() + { + $this->addDownloadHit(); + } + + protected function getSendFileContent() + { + $filename = $this->id . '.' . $this->subtitle['ext']; + $file_loc = app()->getPrivatePath('subs') . DIRECTORY_SEPARATOR . $filename; + return file_get_contents($file_loc); + } +} diff --git a/apps/models/form/Subtitles/SearchForm.php b/apps/models/form/Subtitles/SearchForm.php new file mode 100644 index 0000000..2956c2b --- /dev/null +++ b/apps/models/form/Subtitles/SearchForm.php @@ -0,0 +1,35 @@ +pdo->createCommand('SELECT COUNT(`id`) FROM `subtitles`')->queryScalar(); // TODO + } + + protected function getRemoteData(): array + { + return app()->pdo->createCommand('SELECT * FROM `subtitles` ORDER BY id DESC')->queryAll(); // TODO + } + + public function getSubsSizeSum() + { + if (false === $size = app()->redis->get('Site:subtitle_sub_size:string')) { + $size = app()->pdo->createCommand('SELECT SUM(`size`) FROM `subtitles`')->queryScalar(); + app()->redis->set('Site:subtitle_sub_size:string', $size); + } + return $size; + } + +} diff --git a/apps/models/form/Subtitles/UploadForm.php b/apps/models/form/Subtitles/UploadForm.php new file mode 100644 index 0000000..d1177cf --- /dev/null +++ b/apps/models/form/Subtitles/UploadForm.php @@ -0,0 +1,105 @@ + 0 + ]; + } + + public static function inputRules() + { + return [ + 'torrent_id' => 'Required | Integer', + 'file' => [ + ['Required'], + ['Upload\Required'], + ['Upload\Extension', ['allowed' => ['sub', 'srt', 'zip', 'rar', 'ace', 'txt', 'ssa', 'ass', 'cue']]], + ['Upload\Size', ['size' => config('upload.max_subtitle_file_size') . 'B']] + ], + 'anonymous' => [ + ['InList', ['list' => [0, 1]]] + ] + ]; + } + + public static function callbackRules() + { + return ['isExistTorrent', 'checkSubtitleUniqueByHash']; + } + + protected function checkSubtitleUniqueByHash() + { + /** @var UploadFile $file */ + $file = $this->getData('file'); + $this->hashs = $file_md5 = md5_file($file->tmpName); + + $exist_id = app()->pdo->createCommand('SELECT id FROM `subtitles` WHERE `hashs` = :hashs LIMIT 1;')->bindParams([ + 'hashs' => $file_md5 + ])->queryOne(); + + if ($exist_id !== false) { + $this->buildCallbackFailMsg('file', 'This Subtitle has been upload before.'); + } + } + + /** + * @throws \Exception + */ + public function flush() + { + $title = $this->title ?: $this->file->getFileName(); + + app()->pdo->beginTransaction(); + try { + + $ext = $this->file->getExtension(); + app()->pdo->createCommand('INSERT INTO `subtitles`(`torrent_id`, `hashs` ,`title`, `filename`, `added_at`, `size`, `uppd_by`, `anonymous`, `ext`) +VALUES (:tid, :hashs, :title, :filename, NOW(), :size, :upper, :anonymous, :ext)')->bindParams([ + 'tid' => $this->torrent_id, 'hashs' => $this->hashs, + 'title' => $title, 'filename' => $this->file->getBaseName(), + 'size' => $this->file->size, 'upper' => app()->site->getCurUser()->getId(), + 'anonymous' => $this->anonymous, 'ext' => $ext + ])->execute(); + $id = app()->pdo->getLastInsertId(); + $file_loc = app()->getPrivatePath('subs') . DIRECTORY_SEPARATOR . $id . '.' . $ext; + $this->file->saveAs($file_loc); + app()->pdo->commit(); + } catch (\Exception $e) { + if (isset($file_loc)) unlink($file_loc); + app()->pdo->rollback(); + throw $e; + } + app()->redis->del('Site:subtitle_sub_size:string'); + } +} diff --git a/apps/models/form/Traits/isValidSubtitleTrait.php b/apps/models/form/Traits/isValidSubtitleTrait.php new file mode 100644 index 0000000..7646d06 --- /dev/null +++ b/apps/models/form/Traits/isValidSubtitleTrait.php @@ -0,0 +1,42 @@ + 'required | Integer' + ]; + } + + public static function callbackRules() + { + return ['isValidSubtitle']; + } + + protected function isValidSubtitle() + { + $sub_id = $this->getData('id'); + + $this->subtitle = app()->pdo->createCommand('SELECT * FROM `subtitles` WHERE id = :sid LIMIT 1;')->bindParams([ + 'sid' => $sub_id + ])->queryOne(); + + if ($this->subtitle === false) { + $this->buildCallbackFailMsg('file', 'File not found'); + } + } +} diff --git a/apps/models/form/Traits/isValidTorrentTrait.php b/apps/models/form/Traits/isValidTorrentTrait.php index 1a09f0d..ac817dd 100644 --- a/apps/models/form/Traits/isValidTorrentTrait.php +++ b/apps/models/form/Traits/isValidTorrentTrait.php @@ -13,12 +13,18 @@ trait isValidTorrentTrait { - public $id; + public $torrent_id; public $tid; + public $id; /** @var Torrent */ protected $torrent; + public static function callbackRules() + { + return ['isExistTorrent']; + } + /** * @return Torrent */ @@ -28,7 +34,7 @@ public function getTorrent(): Torrent } protected function isExistTorrent() { - $tid = $this->getData('tid') ?? $this->getData('id'); + $tid = $this->getData('torrent_id') ?? $this->getData('tid') ?? $this->getData('id'); $torrent_exist = app()->pdo->createCommand('SELECT COUNT(`id`) FROM `torrents` WHERE `id` = :tid')->bindParams([ 'tid' => $tid ])->queryScalar(); diff --git a/apps/views/subtitles/search.php b/apps/views/subtitles/search.php new file mode 100644 index 0000000..00e04d5 --- /dev/null +++ b/apps/views/subtitles/search.php @@ -0,0 +1,135 @@ + + +layout('layout/base') ?> + +start('title') ?>Subtitleend(); ?> + +start('container') ?> +
+
+
+
Upload Subtitles - total uploaded e($search->getSubsSizeSum(),'format_bytes') ?>
+
+
+

Rules:

+
    +
  1. Before upload subtitle please search at subtitles page to confirm your subtitle is no exist, please do not upload duplicate subtitles!
  2. +
  3. Upload subtitle must be synchronized with the video (which requires that you have the video file and checked the subtitles)! Identified or membership report, 10% of the entire timeline subtitles portion subtitles in more than 0.3s (can clearly feel error) it will be rejected and be deleted.
  4. +
  5. The film collection of subtitles please upload packaged as zip or rar, do not separate upload.
  6. +
  7. Name of the rule:
    + Example: One.Night.In.Taipei.2015.BluRay.720p.DD5.1.x264-HDBiger.chs
    + Format:
    +
      +
    1. The name must correspond subtitles video file name within the same seed [in principle is not recommended for video name is Chinese, no English name only some video captions allow the use of Chinese].
    2. +
    3. different languages are required after the file name added language identifier, such as Simplified Chinese is .chs, Traditional Chinese is .cht, English .eng, Japanese .jp like. In this case, to select the corresponding language and subtitle types.
    4. +
    5. multilingual subtitles, such as Jane English subtitles, adding the language identifier .chs & eng, join the rest of similar identifier. In this case, the language type selected for Other
    6. +
    7. allowed to upload subtitle format ass / ssa / srt
    8. +
    9. If you previously uploaded subtitle timeline there is something wrong when you upload subtitles proper (correct version) or re-synced (recalibrate) the subtitles, please add at the end of the subtitle file [PROPER] or [R3]. Example: One.Night.In.Taipei.2015.BluRay.720p.DD5.1.x264-HDBiger.chs [PROPER]
    10. +
    +
  8. +
  9. Upload subtitle must meet all the above requirements, otherwise it will be deleted, and the corresponding bonus will be take back. Upload failed for multiple subtitles (malicious upload) members or malicious prosecution subtitles others members will be given a warning, serious case account will be banned.
  10. +
  11. 25 bonus for each subtitle uploaded, and we welcome and encourage any qualified subtitle.
  12. +
+
+
+
+
+
+
+
+ +
+ +
+
(Maximum file size: e(config('upload.max_subtitle_file_size'),'format_bytes') ?>.)
+
+
+ +
+ +
+
The number in the address bar when you go to the details page of the torrent
+
+
+ +
+ +
+
(Optional, taken from file name if not specified.)
+
+ +
+ +
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+
+
+
+ +
+ getTotal()): ?> + + + + + + + + + + + + + + getPagerData() as $datum): ?> + + + + + + + + + + + +
TitleAdded atSizeHitsUploaderReport
+ + e($datum['title']) ?> + e($datum['size'],'format_bytes') ?>e($datum['hits']) ?>insert('helper/username',['user' => app()->site->getUser($datum['uppd_by'])]) ?>Report
+ + No exist upload subtitles + +
+
+ +
+
+
+end(); ?> diff --git a/framework/Http/UploadFile.php b/framework/Http/UploadFile.php index 672e5ac..9f3c8e5 100644 --- a/framework/Http/UploadFile.php +++ b/framework/Http/UploadFile.php @@ -62,6 +62,10 @@ public function getBaseName($suffix = null) return $this->name; } + public function getFileName(){ + return pathinfo($this->name)['filename']; + } + // 获取扩展名 public function getExtension() {