🎨 Automatically download network assets when the cloud inbox is moved to docs https://github.com/siyuan-note/siyuan/issues/9775
This commit is contained in:
parent
d647335d6e
commit
a8625ca27d
8 changed files with 188 additions and 10 deletions
|
@ -1235,9 +1235,9 @@
|
|||
"116": "Processing, please wait...",
|
||||
"117": "[%s] is not a valid Pandoc executable",
|
||||
"118": "The current settings do not allow the creation of sub-documents under a document 7 levels deep",
|
||||
"119": "Downloading web image [%s]",
|
||||
"119": "Downloading network file [%s]",
|
||||
"120": "Download complete, [%d] files total",
|
||||
"121": "There is no network image in this document",
|
||||
"121": "There is no network file in this document",
|
||||
"122": "This function needs to be configured on the SiYuan desktop. If you have already configured it, please refresh it in the top account settings",
|
||||
"123": "The synchronization function can only be activated after adding/selecting the cloud synchronization directory",
|
||||
"124": "Please enable cloud sync in [Settings - Enable Cloud Sync]",
|
||||
|
|
|
@ -1235,9 +1235,9 @@
|
|||
"116": "Procesando, por favor espere...",
|
||||
"117": "[%s] no es un ejecutable válido de Pandoc",
|
||||
"118": "La configuración actual no permite la creación de subdocumentos bajo un documento de 7 niveles de profundidad",
|
||||
"119": "Descargando imagen web [%s]",
|
||||
"119": "Descargando archivo de red [%s]",
|
||||
"120": "Descarga completa, [%d] archivos en total",
|
||||
"121": "No hay ninguna imagen de red en este documento",
|
||||
"121": "No hay ningún archivo de red en este documento",
|
||||
"122": "Esta funci\u00f3n debe configurarse en el escritorio de SiYuan. Si ya la configur\u00f3, actualice en la configuraci\u00f3n de la cuenta superior",
|
||||
"123": "La función de sincronización solo puede activarse después de añadir/seleccionar el directorio de sincronización en la nube",
|
||||
"124": "Por favor, active la sincronización en la nube en [Configuración - Activar sincronización en la nube]",
|
||||
|
|
|
@ -1235,9 +1235,9 @@
|
|||
"116": "Traitement en cours, veuillez patienter...",
|
||||
"117": "[%s] n'est pas un exécutable Pandoc valide",
|
||||
"118": "Les paramètres actuels ne permettent pas la création de sous-documents sous un document de 7 niveaux de profondeur",
|
||||
"119": "Téléchargement de l'image Web [%s]",
|
||||
"119": "Téléchargement du fichier réseau [%s]",
|
||||
"120": "Téléchargement terminé, [%d] fichiers au total",
|
||||
"121": "Il n'y a pas d'image réseau dans ce document",
|
||||
"121": "Il n'y a aucun fichier réseau dans ce document",
|
||||
"122": "Cette fonction doit être configurée sur le bureau SiYuan. Si vous l'avez déjà configurée, veuillez l'actualiser dans les paramètres supérieurs du compte",
|
||||
"123": "Ajouter/sélectionner un répertoire de synchronisation Cloud avant d'activer la synchronisation",
|
||||
"124": "Veuillez activer la synchronisation cloud dans [Paramètres - Activer la synchronisation cloud]",
|
||||
|
|
|
@ -1235,10 +1235,10 @@
|
|||
"116": "正在處理中,請稍等...",
|
||||
"117": "[%s] 不是有效的 Pandoc 可執行文件",
|
||||
"118": "當前設置不允許在 7 層深度的文檔下建立子文檔",
|
||||
"119": "正在下載網絡圖片 [%s]",
|
||||
"119": "正在下載網路檔案 [%s]",
|
||||
"120": "下載完畢,一共 [%d] 個文件",
|
||||
"122": "該功能需在思源桌面端進行配置。如果你已經配置,請在頂部賬號設置中進行重新整理",
|
||||
"121": "該文檔中不存在網絡圖片",
|
||||
"121": "該文件中不存在網路檔案",
|
||||
"123": "新增/選擇雲端同步目錄後才能啟用同步功能",
|
||||
"124": "請在 [設置 - 啟用雲端同步] 中開啟雲端同步",
|
||||
"125": "自動同步失敗次數過多,請嘗試手動觸發同步,如果還有問題請<a href=\"https://ld246.com/article/1649901726096\" target=\"_blank\">反饋</a>",
|
||||
|
|
|
@ -1235,9 +1235,9 @@
|
|||
"116": "正在处理中,请稍等...",
|
||||
"117": "[%s] 不是有效的 Pandoc 可执行文件",
|
||||
"118": "当前设置不允许在 7 层深度的文档下创建子文档",
|
||||
"119": "正在下载网络图片 [%s]",
|
||||
"119": "正在下载网络文件 [%s]",
|
||||
"120": "下载完毕,一共 [%d] 个文件",
|
||||
"121": "该文档中不存在网络图片",
|
||||
"121": "该文档中不存在网络文件",
|
||||
"122": "该功能需在思源桌面端进行配置。如果你已经配置,请在顶部账号设置中进行刷新",
|
||||
"123": "添加/选择云端同步目录后才能启用同步功能",
|
||||
"124": "请在 [设置 - 启用云端同步] 中开启云端同步",
|
||||
|
|
|
@ -25,6 +25,25 @@ import (
|
|||
"github.com/siyuan-note/siyuan/kernel/util"
|
||||
)
|
||||
|
||||
func netAssets2LocalAssets(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
||||
arg, ok := util.JsonArg(c, ret)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
id := arg["id"].(string)
|
||||
err := model.NetAssets2LocalAssets(id)
|
||||
if nil != err {
|
||||
ret.Code = -1
|
||||
ret.Msg = err.Error()
|
||||
ret.Data = map[string]interface{}{"closeTimeout": 5000}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func netImg2LocalAssets(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
|
|
@ -116,6 +116,7 @@ func ServeAPI(ginServer *gin.Engine) {
|
|||
|
||||
ginServer.Handle("POST", "/api/format/autoSpace", model.CheckAuth, model.CheckReadonly, autoSpace)
|
||||
ginServer.Handle("POST", "/api/format/netImg2LocalAssets", model.CheckAuth, model.CheckReadonly, netImg2LocalAssets)
|
||||
ginServer.Handle("POST", "/api/format/netAssets2LocalAssets", model.CheckAuth, model.CheckReadonly, netAssets2LocalAssets)
|
||||
|
||||
ginServer.Handle("POST", "/api/history/getNotebookHistory", model.CheckAuth, getNotebookHistory)
|
||||
ginServer.Handle("POST", "/api/history/rollbackNotebookHistory", model.CheckAuth, model.CheckReadonly, rollbackNotebookHistory)
|
||||
|
|
|
@ -220,6 +220,164 @@ func NetImg2LocalAssets(rootID, originalURL string) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func NetAssets2LocalAssets(rootID string) (err error) {
|
||||
tree, err := loadTreeByBlockID(rootID)
|
||||
if nil != err {
|
||||
return
|
||||
}
|
||||
|
||||
var files int
|
||||
msgId := gulu.Rand.String(7)
|
||||
|
||||
docDirLocalPath := filepath.Join(util.DataDir, tree.Box, path.Dir(tree.Path))
|
||||
assetsDirPath := getAssetsDir(filepath.Join(util.DataDir, tree.Box), docDirLocalPath)
|
||||
if !gulu.File.IsExist(assetsDirPath) {
|
||||
if err = os.MkdirAll(assetsDirPath, 0755); nil != err {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
browserClient := req.C().
|
||||
SetUserAgent(util.UserAgent).
|
||||
SetTimeout(30 * time.Second).
|
||||
EnableInsecureSkipVerify().
|
||||
SetProxy(httpclient.ProxyFromEnvironment)
|
||||
|
||||
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
|
||||
if !entering || (ast.NodeLinkDest != n.Type && !n.IsTextMarkType("a")) {
|
||||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
var dest []byte
|
||||
if ast.NodeLinkDest == n.Type {
|
||||
dest = n.Tokens
|
||||
} else {
|
||||
dest = []byte(n.TextMarkAHref)
|
||||
}
|
||||
|
||||
if util.IsAssetLinkDest(dest) {
|
||||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
if bytes.HasPrefix(bytes.ToLower(dest), []byte("file://")) { // 处理本地文件链接
|
||||
u := string(dest)[7:]
|
||||
if !gulu.File.IsExist(u) || gulu.File.IsDir(u) {
|
||||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
name := filepath.Base(u)
|
||||
name = util.FilterFileName(name)
|
||||
name = util.TruncateLenFileName(name)
|
||||
name = "network-asset-" + name
|
||||
name = util.AssetName(name)
|
||||
writePath := filepath.Join(assetsDirPath, name)
|
||||
if err = filelock.Copy(u, writePath); nil != err {
|
||||
logging.LogErrorf("copy [%s] to [%s] failed: %s", u, writePath, err)
|
||||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
if ast.NodeLinkDest == n.Type {
|
||||
n.Tokens = []byte("assets/" + name)
|
||||
} else {
|
||||
n.TextMarkAHref = "assets/" + name
|
||||
}
|
||||
files++
|
||||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
if bytes.HasPrefix(bytes.ToLower(dest), []byte("https://")) || bytes.HasPrefix(bytes.ToLower(dest), []byte("http://")) {
|
||||
u := string(dest)
|
||||
if strings.Contains(u, "qpic.cn") {
|
||||
// 改进 `网络图片转换为本地图片` 微信图片拉取 https://github.com/siyuan-note/siyuan/issues/5052
|
||||
if strings.Contains(u, "http://") {
|
||||
u = strings.Replace(u, "http://", "https://", 1)
|
||||
}
|
||||
|
||||
// 改进 `网络图片转换为本地图片` 微信图片拉取 https://github.com/siyuan-note/siyuan/issues/6431
|
||||
// 下面这部分需要注释掉,否则会导致响应 400
|
||||
//if strings.HasSuffix(u, "/0") {
|
||||
// u = strings.Replace(u, "/0", "/640", 1)
|
||||
//} else if strings.Contains(u, "/0?") {
|
||||
// u = strings.Replace(u, "/0?", "/640?", 1)
|
||||
//}
|
||||
}
|
||||
util.PushUpdateMsg(msgId, fmt.Sprintf(Conf.Language(119), u), 15000)
|
||||
request := browserClient.R()
|
||||
request.SetRetryCount(1).SetRetryFixedInterval(3 * time.Second)
|
||||
resp, reqErr := request.Get(u)
|
||||
if nil != reqErr {
|
||||
logging.LogErrorf("download network asset [%s] failed: %s", u, reqErr)
|
||||
return ast.WalkContinue
|
||||
}
|
||||
if 200 != resp.StatusCode {
|
||||
logging.LogErrorf("download network asset [%s] failed: %d", u, resp.StatusCode)
|
||||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
if 1024*1024*96 < resp.ContentLength {
|
||||
logging.LogWarnf("network asset [%s]' size [%s] is large then [96 MB], ignore it", u, humanize.IBytes(uint64(resp.ContentLength)))
|
||||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
data, repErr := resp.ToBytes()
|
||||
if nil != repErr {
|
||||
logging.LogErrorf("download network asset [%s] failed: %s", u, repErr)
|
||||
return ast.WalkContinue
|
||||
}
|
||||
var name string
|
||||
if strings.Contains(u, "?") {
|
||||
name = u[:strings.Index(u, "?")]
|
||||
name = path.Base(name)
|
||||
} else {
|
||||
name = path.Base(u)
|
||||
}
|
||||
if strings.Contains(name, "#") {
|
||||
name = name[:strings.Index(name, "#")]
|
||||
}
|
||||
name, _ = url.PathUnescape(name)
|
||||
ext := path.Ext(name)
|
||||
if "" == ext {
|
||||
if mtype := mimetype.Detect(data); nil != mtype {
|
||||
ext = mtype.Extension()
|
||||
}
|
||||
}
|
||||
if "" == ext {
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
exts, _ := mime.ExtensionsByType(contentType)
|
||||
if 0 < len(exts) {
|
||||
ext = exts[0]
|
||||
}
|
||||
}
|
||||
name = strings.TrimSuffix(name, ext)
|
||||
name = util.FilterFileName(name)
|
||||
name = util.TruncateLenFileName(name)
|
||||
name = "network-asset-" + name + "-" + ast.NewNodeID() + ext
|
||||
writePath := filepath.Join(assetsDirPath, name)
|
||||
if err = filelock.WriteFile(writePath, data); nil != err {
|
||||
logging.LogErrorf("write downloaded network asset [%s] to local asset [%s] failed: %s", u, writePath, err)
|
||||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
if ast.NodeLinkDest == n.Type {
|
||||
n.Tokens = []byte("assets/" + name)
|
||||
} else {
|
||||
n.TextMarkAHref = "assets/" + name
|
||||
}
|
||||
files++
|
||||
}
|
||||
return ast.WalkContinue
|
||||
})
|
||||
|
||||
if 0 < files {
|
||||
util.PushUpdateMsg(msgId, Conf.Language(113), 7000)
|
||||
if err = writeJSONQueue(tree); nil != err {
|
||||
return
|
||||
}
|
||||
util.PushUpdateMsg(msgId, fmt.Sprintf(Conf.Language(120), files), 5000)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SearchAssetsByName(keyword string, exts []string) (ret []*cache.Asset) {
|
||||
ret = []*cache.Asset{}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue