管理markdown图片 cos对象存储

管理markdown图片

源文档

image-20230411210702597

程序替换链接后的新文档

image-20230411210806103

目录结构:

release目录存放程序生成的md文件(已更改 位于项目上级目录中)

cache目录存放1080p缩略图 命名为源文件md5值 jpg格式

image-20230411211809723

assets为自定义目录,在md编辑器中设置添加图片自动复制到该目录,方便集中管理源图片

image-20230411210951835

image-20230411211009316

上传到腾讯对象存储cos

sdk:cos-python-sdk-v5

1.上传文件:

可以指定上传文件夹

upload_file(
            Bucket=self.bucket,
            LocalFilePath=p,  # 本地文件的路径
            Key='md/'+name,  # 上传到桶之后的文件名
        )

2. 获取文件列表信息:

指定文件夹

1.marker来自返回值response['NextMarker']

  1. :param Marker(string): 从marker开始列出条目.

应该是数字,如请求10条response['NextMarker']=10 下次请求Marker=10就从第10个开始返回

循环获取所有文件列表

3.终止条件:response['IsTruncated'] == 'false'

list_objects(
            Bucket=self.bucket,
            Prefix=dir_name,
            Marker=marker
            )

3.图片链接:

https://pic-1305365488.cos.ap-chongqing.myqcloud.com/md/name

name为上传指定的名字

注意需要后缀,且后缀与文件不符可能无法正常显示

文档本地图片处理

1.替换掉本地链接

链接格式

![name](uri)

通过正则获取图片链接 uri

'\!\[.*\]\((.*)\)'

替换为网络链接

2.压缩图片

   im=Image.open(file)
   im.thumbnail((1920,1080))
    im=im.convert('RGB')
    im.save(img,'JPEG')

完整代码

注意设置环境变量

os.environ.setdefault('key','value')

requests

cos-python-sdk-v5
pillow
pathlib
import hashlib, time, os, pickle,re
from pathlib import Path
from PIL import Image
from env import *

def cal(f):
    # 函数运行计时
    from functools import wraps

    @wraps(f)
    def func(*a, **b):
        s = time.time()
        ret = f(*a, **b)
        print('{} 耗时:{:.3f}'.format(f.__name__, time.time()-s))
        return ret
    return func

def dir_make(arg):
    if not os.path.exists(arg):
        os.makedirs(arg)

def _get_file(p,index):
    # 获取所有文件/夹
    ret=[] 
    for f in os.walk(p):
        for i in f[index]:
            file= '{}\\{}'.format(f[0], i)
            ret.append(file)
    return ret

def get_files(p):
    return _get_file(p,index=2)


class UploadImg:
    bucket='pic-1305365488'
    secret_id = os.environ['COS_SECRET_ID']     # 用户的 SecretId,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
    secret_key = os.environ['COS_SECRET_KEY']   # 用户的 SecretKey,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
    def __init__(self) -> None:
        from qcloud_cos import CosConfig
        from qcloud_cos import CosS3Client
        
        # 1. 设置用户属性, 包括 secret_id, secret_key, region等。Appid 已在 CosConfig 中移除,请在参数 Bucket 中带上 Appid。Bucket 由 BucketName-Appid 组成
       
        region = 'ap-chongqing'      # 替换为用户的 region,已创建桶归属的 region 可以在控制台查看,https://console.cloud.tencent.com/cos5/bucket
                                # COS 支持的所有 region 列表参见 https://cloud.tencent.com/document/product/436/6224
        token = None               # 如果使用永久密钥不需要填入 token,如果使用临时密钥需要填入,临时密钥生成和使用指引参见 https://cloud.tencent.com/document/product/436/14048
        config = CosConfig(Region=region, SecretId=self.secret_id, SecretKey=self.secret_key, Token=token )
        self.client = CosS3Client(config)

    def send_file(self,p,func_name=lambda p:Path(p).name,name=''):
        if not name:
            name=func_name(p)

        response = self.client.upload_file(
            Bucket=self.bucket,
            LocalFilePath=p,  # 本地文件的路径
            Key='md/'+name,  # 上传到桶之后的文件名
        )
        return response['ETag']
        
    def send_files(self,p):
        [self.send_file(i) for i in get_files(p)]

    def list_all(self):
        dir_name='md'
        r=[]
        marker=''
        while True:
            response = self.client.list_objects(
            Bucket=self.bucket,
            Prefix=dir_name,
            Marker=marker
            )
            r+=response['Contents']
            if response['IsTruncated'] == 'false':
                break 
            marker = response['NextMarker']
        return r
        
    def show_all(self):
        r=self.list_all()
        print('上传文件列表')
        print('\n'.join([i['Key'] for i in r]))

class Control:
    url_pattern='https://pic-1305365488.cos.ap-chongqing.myqcloud.com/md/{}.jpg'
    def __init__(self,p) -> None:
        self.path=p
        self.release_path=Path(p).parent.joinpath('release')
        self.cache_path=Path(p).joinpath('cache')
        dir_make(self.release_path)
        dir_make(self.cache_path)

       
        self.updata=[]
    def new_md(self,src,dst):
        text=open(src,'r',encoding='utf-8').read()
        imgs_path=re.findall('\!\[.*\]\((.*)\)',text)
        # 获取文件链接
        def img_link(p):
            if not os.path.exists(p):
                return
            id=hashlib.md5(open(p,'rb').read()).hexdigest()
            self.updata.append({'path':p,'id':id})
            return [p,self.url_pattern.format(id)]

        data=[img_link(i) for i in imgs_path]
        data=[i for i in data if i]
        new_text=text
        # 替换链接
        for i in data:
            old,new=i
            new_text=new_text.replace(old,new)
        dir_make(Path(dst).parent)
        open(dst,'w',encoding='utf-8').write(new_text)

    def _thumbnail(self,file,img):
        # 缩略图
        if os.path.exists(img):
            return
        try:
            im=Image.open(file)
            im.thumbnail((1920,1080))
        except:
            return
        im=im.convert('RGB')
        im.save(img,'JPEG')

    def up_load(self):
        # 上传文件 转化为1080p jpg缩略图 
        client=''
        updata=self.updata
        # 已上传文件id
        data_pickle=self.cache_path.joinpath('uploaddata.pickle')
        if data_pickle.exists():
            uploaddata=pickle.load( open(data_pickle,'rb'))
        else:
            uploaddata={}
        
        def f(i):
            try:
                return re.findall('([^/]+)\.\w+',i['Key'])[0]
            except:
                return
        uploadids= {f(i) for i in uploaddata}
        
        skip=0
        for i in updata:
            p=i['path']
            id=i['id']
            if id in uploadids:
                skip+=1
                continue
            if not client:
                # 上次数据不足以应付
                client=UploadImg()
                uploaddata=client.list_all()
                pickle.dump(uploaddata,open(data_pickle,'wb'))
                uploadids= {f(i) for i in uploaddata}
                if id in uploadids:
                    skip+=1
                    continue

            # 强制jpg缩略图
            img=self.cache_path.joinpath(f'{id}.jpg')
            self._thumbnail(p,img)
             
            client.send_file(img,name=id+'.jpg'  )
        print('文件上传完毕:{}  已上传跳过:{}'.format(len(updata)-skip,skip))
    @cal
    def release(self):
        # 制作md副本
      
        p=self.path
        len_path=len(p)
        dst=self.release_path
        md_files=[i for  i in get_files(p) if i.endswith('md') and not str(dst) in i]
        
        md_pair_files=[[i,dst.joinpath(i[len_path+1:])] for i in md_files]
        
        [self.new_md(*i) for i in md_pair_files]
        print('release done:{}'.format(len(md_pair_files)))
        print('upload...')
        self.up_load()

 
control=Control(r'X:\bufferx\OneDrive\文档\笔记')
control.release()
 

posted @ 2023-04-11 22:27  caiusxin  阅读(105)  评论(0)    收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css