ChapterContentController.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\Http\Api\ChannelApi;
  4. use App\Http\Api\MdRender;
  5. use App\Http\Resources\TocResource;
  6. use App\Models\Channel;
  7. use App\Models\PaliText;
  8. use App\Models\Sentence;
  9. use App\Services\AuthService;
  10. use App\Services\PaliContentService;
  11. use Illuminate\Http\Request;
  12. use Illuminate\Http\Response;
  13. use Illuminate\Support\Str;
  14. class ChapterContentController extends Controller
  15. {
  16. protected $result = [
  17. 'uid' => '',
  18. 'title' => '',
  19. 'path' => [],
  20. 'sub_title' => '',
  21. 'summary' => '',
  22. 'content' => '',
  23. 'content_type' => 'html',
  24. 'toc' => [],
  25. 'status' => 30,
  26. 'lang' => '',
  27. 'created_at' => '',
  28. 'updated_at' => '',
  29. ];
  30. protected $selectCol = [
  31. 'uid',
  32. 'book_id',
  33. 'paragraph',
  34. 'word_start',
  35. 'word_end',
  36. 'channel_uid',
  37. 'content',
  38. 'content_type',
  39. 'editor_uid',
  40. 'acceptor_uid',
  41. 'pr_edit_at',
  42. 'fork_at',
  43. 'create_time',
  44. 'modify_time',
  45. 'created_at',
  46. 'updated_at',
  47. ];
  48. /**
  49. * Display a listing of the resource.
  50. *
  51. * @return Response
  52. */
  53. public function index()
  54. {
  55. //
  56. }
  57. /**
  58. * Store a newly created resource in storage.
  59. *
  60. * @return Response
  61. */
  62. public function store(Request $request)
  63. {
  64. //
  65. }
  66. /**
  67. * Store a newly created resource in storage.
  68. *
  69. * @return Response
  70. */
  71. public function show(Request $request, string $id)
  72. {
  73. /**
  74. $user = AuthService::current($request);
  75. if ($user) {
  76. $this->userUuid = $user['user_uid'];
  77. }
  78. */
  79. //
  80. $channels = [];
  81. if ($request->has('channels')) {
  82. if (strpos($request->input('channels'), ',') === false) {
  83. $_channels = explode('_', $request->input('channels'));
  84. } else {
  85. $_channels = explode(',', $request->input('channels'));
  86. }
  87. foreach ($_channels as $key => $channel) {
  88. if (Str::isUuid($channel)) {
  89. $channels[] = $channel;
  90. }
  91. }
  92. }
  93. $mode = $request->input('mode', 'read');
  94. if ($mode === 'read') {
  95. // 阅读模式加载html格式原文
  96. $channelId = ChannelApi::getSysChannel('_System_Pali_VRI_');
  97. } else {
  98. // 翻译模式加载json格式原文
  99. $channelId = ChannelApi::getSysChannel('_System_Wbw_VRI_');
  100. }
  101. if ($channelId !== false) {
  102. $channels[] = $channelId;
  103. }
  104. // 获取channel索引表
  105. $tranChannels = [];
  106. $channelInfo = Channel::whereIn('uid', $channels)
  107. ->select(['uid', 'type', 'lang', 'name'])->get();
  108. foreach ($channelInfo as $key => $value) {
  109. // code...
  110. if ($value->type === 'translation') {
  111. $tranChannels[] = $value->uid;
  112. }
  113. }
  114. $indexChannel = [];
  115. $paliService = app(PaliContentService::class);
  116. $indexChannel = $paliService->getChannelIndex($channels);
  117. // the end of channel
  118. // chapter info
  119. $sentId = \explode('-', $id);
  120. $chapter = PaliText::where('book', $sentId[0])->where('paragraph', $sentId[1])->first();
  121. if (! $chapter) {
  122. return $this->error('no data');
  123. }
  124. if (empty($chapter->toc)) {
  125. $this->result['title'] = 'unknown';
  126. } else {
  127. $this->result['title'] = $chapter->toc;
  128. $this->result['sub_title'] = $chapter->toc;
  129. $this->result['path'] = json_decode($chapter->path);
  130. }
  131. $title = Sentence::select($this->selectCol)
  132. ->where('book_id', $sentId[0])
  133. ->where('paragraph', $sentId[1])
  134. ->whereIn('channel_uid', $tranChannels)
  135. ->first();
  136. if ($title) {
  137. $this->result['title'] = MdRender::render($title->content, [$title->channel_uid]);
  138. $mdRender = new MdRender(['format' => 'simple']);
  139. $this->result['title_text'] = $mdRender->convert($title->content, [$title->channel_uid]);
  140. }
  141. /**
  142. * 获取句子数据
  143. * 算法:
  144. * 1. 如果标题和下一级第一个标题之间有段落。只输出这些段落和子目录
  145. * 2. 如果标题和下一级第一个标题之间没有间隔 且 chapter 长度大于10000个字符 且有子目录,只输出子目录
  146. * 3. 如果二者都不是,lazy load
  147. */
  148. // 1. 计算 标题和下一级第一个标题之间 是否有间隔
  149. $paraFrom = $sentId[1];
  150. $paraTo = $sentId[1] + $chapter->chapter_len - 1;
  151. $nextChapter = PaliText::where('book', $sentId[0])
  152. ->where('paragraph', '>', $sentId[1])
  153. ->where('level', '<', 8)
  154. ->orderBy('paragraph')
  155. ->value('paragraph');
  156. $between = $nextChapter - $sentId[1];
  157. // 查找子目录
  158. $chapterLen = $chapter->chapter_len;
  159. $toc = PaliText::where('book', $sentId[0])
  160. ->whereBetween('paragraph', [$paraFrom + 1, $paraFrom + $chapterLen - 1])
  161. ->where('level', '<', 8)
  162. ->orderBy('paragraph')
  163. ->select(['book', 'paragraph', 'level', 'toc'])
  164. ->get();
  165. $maxLen = 3000;
  166. if ($between > 1) {
  167. // 有间隔
  168. $paraTo = $nextChapter - 1;
  169. } else {
  170. if ($chapter->chapter_strlen > $maxLen) {
  171. if (count($toc) > 0) {
  172. // 有子目录只输出标题和目录
  173. $paraTo = $paraFrom;
  174. } else {
  175. // 没有子目录 全部输出
  176. }
  177. } else {
  178. // 章节小。全部输出 不输出子目录
  179. $toc = [];
  180. }
  181. }
  182. $pFrom = $request->input('from', $paraFrom);
  183. $pTo = $request->input('to', $paraTo);
  184. // 根据句子的长度找到这次应该加载的段落
  185. $paliText = PaliText::select(['paragraph', 'lenght'])
  186. ->where('book', $sentId[0])
  187. ->whereBetween('paragraph', [$pFrom, $pTo])
  188. ->orderBy('paragraph')
  189. ->get();
  190. $sumLen = 0;
  191. $currTo = $pTo;
  192. foreach ($paliText as $para) {
  193. $sumLen += $para->lenght;
  194. if ($sumLen > $maxLen) {
  195. $currTo = $para->paragraph;
  196. break;
  197. }
  198. }
  199. // content
  200. $record = Sentence::select($this->selectCol)
  201. ->where('book_id', $sentId[0])
  202. ->whereBetween('paragraph', [$pFrom, $currTo])
  203. ->whereIn('channel_uid', $channels)
  204. ->orderBy('paragraph')
  205. ->orderBy('word_start')
  206. ->get();
  207. if (count($record) === 0) {
  208. return $this->error('no data');
  209. }
  210. $this->result['content'] = json_encode($paliService->makeContentObj($record, $mode, $indexChannel), JSON_UNESCAPED_UNICODE);
  211. $this->result['content_type'] = 'json';
  212. if (! $request->has('from')) {
  213. // 第一次才显示toc
  214. $this->result['toc'] = TocResource::collection($toc);
  215. }
  216. if ($currTo < $pTo) {
  217. $this->result['from'] = $currTo + 1;
  218. $this->result['to'] = $pTo;
  219. $this->result['paraId'] = $id;
  220. $this->result['channels'] = $request->input('channels');
  221. $this->result['mode'] = $request->input('mode');
  222. }
  223. return $this->ok($this->result);
  224. }
  225. /**
  226. * Update the specified resource in storage.
  227. *
  228. * @param int $id
  229. * @return Response
  230. */
  231. public function update(Request $request, $id)
  232. {
  233. //
  234. }
  235. /**
  236. * Remove the specified resource from storage.
  237. *
  238. * @param int $id
  239. * @return Response
  240. */
  241. public function destroy($id)
  242. {
  243. //
  244. }
  245. }