2
0

ChapterService.php 8.4 KB

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