ChapterContentController.php 8.2 KB

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