asset.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. // SiYuan - Refactor your thinking
  2. // Copyright (c) 2020-present, b3log.org
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Affero General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Affero General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Affero General Public License
  15. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. package api
  17. import (
  18. "fmt"
  19. "net/http"
  20. "os"
  21. "path/filepath"
  22. "strings"
  23. "github.com/88250/go-humanize"
  24. "github.com/88250/gulu"
  25. "github.com/djherbis/times"
  26. "github.com/gin-gonic/gin"
  27. "github.com/siyuan-note/filelock"
  28. "github.com/siyuan-note/siyuan/kernel/model"
  29. "github.com/siyuan-note/siyuan/kernel/util"
  30. )
  31. func statAsset(c *gin.Context) {
  32. ret := gulu.Ret.NewResult()
  33. defer c.JSON(http.StatusOK, ret)
  34. arg, ok := util.JsonArg(c, ret)
  35. if !ok {
  36. return
  37. }
  38. path := arg["path"].(string)
  39. var p string
  40. if strings.HasPrefix(path, "assets/") {
  41. var err error
  42. p, err = model.GetAssetAbsPath(path)
  43. if nil != err {
  44. ret.Code = 1
  45. return
  46. }
  47. } else if strings.HasPrefix(path, "file://") {
  48. p = strings.TrimPrefix(path, "file://")
  49. if strings.Contains(p, ":") {
  50. p = strings.TrimPrefix(p, "/")
  51. }
  52. } else {
  53. ret.Code = 1
  54. return
  55. }
  56. info, err := os.Stat(p)
  57. if nil != err {
  58. ret.Code = 1
  59. return
  60. }
  61. t, err := times.Stat(p)
  62. if nil != err {
  63. ret.Code = 1
  64. return
  65. }
  66. updated := t.ModTime().UnixMilli()
  67. hUpdated := t.ModTime().Format("2006-01-02 15:04:05")
  68. created := updated
  69. hCreated := hUpdated
  70. // Check birthtime before use
  71. if t.HasBirthTime() {
  72. created = t.BirthTime().UnixMilli()
  73. hCreated = t.BirthTime().Format("2006-01-02 15:04:05")
  74. }
  75. ret.Data = map[string]interface{}{
  76. "size": info.Size(),
  77. "hSize": humanize.BytesCustomCeil(uint64(info.Size()), 2),
  78. "created": created,
  79. "hCreated": hCreated,
  80. "updated": updated,
  81. "hUpdated": hUpdated,
  82. }
  83. }
  84. func fullReindexAssetContent(c *gin.Context) {
  85. ret := gulu.Ret.NewResult()
  86. defer c.JSON(http.StatusOK, ret)
  87. model.ReindexAssetContent()
  88. }
  89. func getImageOCRText(c *gin.Context) {
  90. ret := gulu.Ret.NewResult()
  91. defer c.JSON(http.StatusOK, ret)
  92. arg, ok := util.JsonArg(c, ret)
  93. if !ok {
  94. return
  95. }
  96. path := arg["path"].(string)
  97. ret.Data = map[string]interface{}{
  98. "text": util.GetAssetText(path),
  99. }
  100. }
  101. func setImageOCRText(c *gin.Context) {
  102. ret := gulu.Ret.NewResult()
  103. defer c.JSON(http.StatusOK, ret)
  104. arg, ok := util.JsonArg(c, ret)
  105. if !ok {
  106. return
  107. }
  108. path := arg["path"].(string)
  109. text := arg["text"].(string)
  110. util.SetAssetText(path, text)
  111. }
  112. func ocr(c *gin.Context) {
  113. ret := gulu.Ret.NewResult()
  114. defer c.JSON(http.StatusOK, ret)
  115. arg, ok := util.JsonArg(c, ret)
  116. if !ok {
  117. return
  118. }
  119. path := arg["path"].(string)
  120. ocrJSON := util.OcrAsset(path)
  121. ret.Data = map[string]interface{}{
  122. "text": util.GetOcrJsonText(ocrJSON),
  123. "ocrJSON": ocrJSON,
  124. }
  125. }
  126. func renameAsset(c *gin.Context) {
  127. ret := gulu.Ret.NewResult()
  128. defer c.JSON(http.StatusOK, ret)
  129. arg, ok := util.JsonArg(c, ret)
  130. if !ok {
  131. return
  132. }
  133. oldPath := arg["oldPath"].(string)
  134. newName := arg["newName"].(string)
  135. newPath, err := model.RenameAsset(oldPath, newName)
  136. if nil != err {
  137. ret.Code = -1
  138. ret.Msg = err.Error()
  139. ret.Data = map[string]interface{}{"closeTimeout": 5000}
  140. return
  141. }
  142. ret.Data = map[string]interface{}{
  143. "newPath": newPath,
  144. }
  145. }
  146. func getDocImageAssets(c *gin.Context) {
  147. ret := gulu.Ret.NewResult()
  148. defer c.JSON(http.StatusOK, ret)
  149. arg, ok := util.JsonArg(c, ret)
  150. if !ok {
  151. return
  152. }
  153. id := arg["id"].(string)
  154. assets, err := model.DocImageAssets(id)
  155. if nil != err {
  156. ret.Code = -1
  157. ret.Msg = err.Error()
  158. return
  159. }
  160. ret.Data = assets
  161. }
  162. func setFileAnnotation(c *gin.Context) {
  163. ret := gulu.Ret.NewResult()
  164. defer c.JSON(http.StatusOK, ret)
  165. arg, ok := util.JsonArg(c, ret)
  166. if !ok {
  167. return
  168. }
  169. p := arg["path"].(string)
  170. p = strings.ReplaceAll(p, "%23", "#")
  171. data := arg["data"].(string)
  172. writePath, err := resolveFileAnnotationAbsPath(p)
  173. if nil != err {
  174. ret.Code = -1
  175. ret.Msg = err.Error()
  176. return
  177. }
  178. if err := filelock.WriteFile(writePath, []byte(data)); nil != err {
  179. ret.Code = -1
  180. ret.Msg = err.Error()
  181. return
  182. }
  183. model.IncSync()
  184. }
  185. func getFileAnnotation(c *gin.Context) {
  186. ret := gulu.Ret.NewResult()
  187. defer c.JSON(http.StatusOK, ret)
  188. arg, ok := util.JsonArg(c, ret)
  189. if !ok {
  190. return
  191. }
  192. p := arg["path"].(string)
  193. p = strings.ReplaceAll(p, "%23", "#")
  194. readPath, err := resolveFileAnnotationAbsPath(p)
  195. if nil != err {
  196. ret.Code = -1
  197. ret.Msg = err.Error()
  198. ret.Data = map[string]interface{}{"closeTimeout": 5000}
  199. return
  200. }
  201. if !filelock.IsExist(readPath) {
  202. ret.Code = 1
  203. return
  204. }
  205. data, err := filelock.ReadFile(readPath)
  206. if nil != err {
  207. ret.Code = -1
  208. ret.Msg = err.Error()
  209. return
  210. }
  211. ret.Data = map[string]interface{}{
  212. "data": string(data),
  213. }
  214. }
  215. func resolveFileAnnotationAbsPath(assetRelPath string) (ret string, err error) {
  216. filePath := strings.TrimSuffix(assetRelPath, ".sya")
  217. absPath, err := model.GetAssetAbsPath(filePath)
  218. if nil != err {
  219. return
  220. }
  221. dir := filepath.Dir(absPath)
  222. base := filepath.Base(assetRelPath)
  223. ret = filepath.Join(dir, base)
  224. return
  225. }
  226. func removeUnusedAsset(c *gin.Context) {
  227. ret := gulu.Ret.NewResult()
  228. defer c.JSON(http.StatusOK, ret)
  229. arg, ok := util.JsonArg(c, ret)
  230. if !ok {
  231. return
  232. }
  233. p := arg["path"].(string)
  234. asset := model.RemoveUnusedAsset(p)
  235. ret.Data = map[string]interface{}{
  236. "path": asset,
  237. }
  238. }
  239. func removeUnusedAssets(c *gin.Context) {
  240. ret := gulu.Ret.NewResult()
  241. defer c.JSON(http.StatusOK, ret)
  242. paths := model.RemoveUnusedAssets()
  243. ret.Data = map[string]interface{}{
  244. "paths": paths,
  245. }
  246. }
  247. func getUnusedAssets(c *gin.Context) {
  248. ret := gulu.Ret.NewResult()
  249. defer c.JSON(http.StatusOK, ret)
  250. unusedAssets := model.UnusedAssets()
  251. ret.Data = map[string]interface{}{
  252. "unusedAssets": unusedAssets,
  253. }
  254. }
  255. func getMissingAssets(c *gin.Context) {
  256. ret := gulu.Ret.NewResult()
  257. defer c.JSON(http.StatusOK, ret)
  258. missingAssets := model.MissingAssets()
  259. ret.Data = map[string]interface{}{
  260. "missingAssets": missingAssets,
  261. }
  262. }
  263. func resolveAssetPath(c *gin.Context) {
  264. ret := gulu.Ret.NewResult()
  265. defer c.JSON(http.StatusOK, ret)
  266. arg, ok := util.JsonArg(c, ret)
  267. if !ok {
  268. return
  269. }
  270. path := arg["path"].(string)
  271. p, err := model.GetAssetAbsPath(path)
  272. if nil != err {
  273. ret.Code = -1
  274. ret.Msg = err.Error()
  275. ret.Data = map[string]interface{}{"closeTimeout": 3000}
  276. return
  277. }
  278. ret.Data = p
  279. return
  280. }
  281. func uploadCloud(c *gin.Context) {
  282. ret := gulu.Ret.NewResult()
  283. defer c.JSON(http.StatusOK, ret)
  284. arg, ok := util.JsonArg(c, ret)
  285. if !ok {
  286. return
  287. }
  288. rootID := arg["id"].(string)
  289. count, err := model.UploadAssets2Cloud(rootID)
  290. if nil != err {
  291. ret.Code = -1
  292. ret.Msg = err.Error()
  293. ret.Data = map[string]interface{}{"closeTimeout": 3000}
  294. return
  295. }
  296. util.PushMsg(fmt.Sprintf(model.Conf.Language(41), count), 3000)
  297. }
  298. func insertLocalAssets(c *gin.Context) {
  299. ret := gulu.Ret.NewResult()
  300. defer c.JSON(http.StatusOK, ret)
  301. arg, ok := util.JsonArg(c, ret)
  302. if !ok {
  303. return
  304. }
  305. assetPathsArg := arg["assetPaths"].([]interface{})
  306. var assetPaths []string
  307. for _, pathArg := range assetPathsArg {
  308. assetPaths = append(assetPaths, pathArg.(string))
  309. }
  310. isUpload := true
  311. isUploadArg := arg["isUpload"]
  312. if nil != isUploadArg {
  313. isUpload = isUploadArg.(bool)
  314. }
  315. id := arg["id"].(string)
  316. succMap, err := model.InsertLocalAssets(id, assetPaths, isUpload)
  317. if nil != err {
  318. ret.Code = -1
  319. ret.Msg = err.Error()
  320. return
  321. }
  322. ret.Data = map[string]interface{}{
  323. "succMap": succMap,
  324. }
  325. }