def sync_tags(self) -> None: """ 同步为知笔记的 tag 到 Joplin Tag """ created_keys = self.cu.tags.keys() waiting_create_tags = [ wt for wt in self.ws.tags if not tojoplinid(wt.guid) in created_keys ] logger.info(f'为知笔记共有 {len(self.ws.tags)} 个 tag 。') logger.info(f'有 {len(waiting_create_tags)} 个 tag 等待同步。') for wt in waiting_create_tags: tag_id = tojoplinid(wt.guid) try: logger.info(f'处理 tag {wt.name} {tag_id}') jt = self.jda.post_tag(id=tag_id, title=wt.name, created_time=wt.modified, updated_time=wt.modified) self.cu.add_tag(jt) except ValueError as e: logger.error(e) # 由于加入的 tag 没有写入转换数据库导致的 guid 重复错误,此时需要将 tag 写入转换数据库 if str(e).find( 'SQLITE_CONSTRAINT: UNIQUE constraint failed') > -1: jt = self.jda.get_tag(tag_id) self.cu.add_tag(jt) continue
def sync_folders(self) -> None: """ 同步为知笔记的目录 到 Joplin Folder 在为知笔记中,目录不是一种资源,它直接在配置文件中定义,在数据库中仅作为 location 字段存在 而在 Joplin 中,目录是一种标准资源 https://joplinapp.org/api/references/rest_api/#item-type-ids """ waiting_created_l2f = self.cu.get_waiting_for_created_l2f() logger.info(f'有 {len(waiting_created_l2f)} 个 folder 等待同步。') for l2f in waiting_created_l2f: jf = None logger.info(f'处理 location {l2f.location}') # level1 没有父对象 if l2f.parent_location is None: jf = self.jda.post_folder(title=l2f.title) self.cu.update_l2f(l2f.location, jf.id) else: parent_l2f: Location2Folder = self.cu.l2f_cache.get( l2f.parent_location) if parent_l2f is None: msg = f'找不到父对象 {l2f.parent_location}!' logger.error(msg) raise ValueError(msg) if parent_l2f.id is None: msg = f'父对象 {l2f.parent_location} 没有 id!' logger.error(msg) raise ValueError(msg) jf = self.jda.post_folder(title=l2f.title, parent_id=parent_l2f.id) self.cu.update_l2f(l2f.location, jf.id, jf.parent_id) # 更新了 l2f_cache 之后,要更新一次 folders self.cu.load_folders()
def post_note(self, id: str, title: str, body: str, is_markdown: bool, parent_id: str, source_url: str) -> JoplinNote: """ 创建一个新的 Note 隐藏的 Joplin 参数:通过抓包 Joplin WebClipper complete Page Html source_command { 'name': 'completePageHtml', 'preProcessFor': 'html' } convert_to = html simplified Page Html source_command { 'name': 'simplifiedPageHtml', } convert_to = markdown complete page source_command = markdown { 'name': 'completePageHtml', 'preProcessFor': 'markdown' } convert_to = markdown """ kwargs = { 'id': id, 'title': title, 'parent_id': parent_id, 'markup_language': 1, } if source_url: kwargs['source_url'] = source_url if is_markdown: kwargs['body'] = body else: # 使用 joplin 的功能将所有的 html 都转换成 markdown kwargs['body_html'] = body kwargs['convert_to'] = 'markdown' kwargs['source_command'] = { 'name': 'simplifiedPageHtml', } query = self._build_query() logger.info(f'向 Joplin 增加 note {kwargs}') resp = self.client.post('/notes', params=query, json=kwargs) data = resp.json() if data.get('error'): logger.error(data['error']) raise ValueError(data['error']) return JoplinNote(**data)
def get_resource(self, guid: str) -> JoplinResource: """ 根据 guid 获取 resource """ query = self._build_query(fields=JoplinResource.fields_str()) resp = self.client.get(f'/resources/{guid}', params=query) data = resp.json() logger.info(f'从 Joplin 获取 resource {guid}: {data}') if data.get('error'): logger.error(data['error']) raise ValueError(data['error']) return JoplinResource(**data)
def get_tag(self, guid: str) -> JoplinTag: """ 根据 guid 获取 tag """ query = self._build_query(fields=JoplinTag.fields_str()) resp = self.client.get(f'/tags/{guid}', params=query) data = resp.json() logger.info(f'从 Joplin 获取 tag {guid}: {data}') if data.get('error'): logger.error(data['error']) raise ValueError(data['error']) return JoplinTag(**data)
def post_tag(self, **kwargs) -> JoplinTag: """ 创建一个新的 tag """ query = self._build_query() logger.info(f'向 Joplin 增加 tag {kwargs}') resp = self.client.post('/tags', params=query, json=kwargs) data = resp.json() if data.get('error'): logger.error(data['error']) raise ValueError(data['error']) return JoplinTag(**data)
def post_folder(self, **kwargs) -> JoplinFolder: """ 创建一个新的 folder """ query = self._build_query() logger.info(f'向 Joplin 增加 folder {kwargs}') resp = self.client.post('/folders', params=query, json=kwargs) data = resp.json() if data.get('error'): logger.error(data['error']) raise ValueError(data['error']) return JoplinFolder(**data)
def post_resource(self, file: Path, resource_type: int, **kwargs) -> JoplinResource: """ 创建一个新的 resources """ query = self._build_query() files = {'data': open(file, 'rb')} # 经过测试 props 中只有 title 和 id 有作用,其他的参数都无效 data = {'props': json.dumps(kwargs)} logger.info(f'向 Joplin 增加 resource {file} {kwargs}') resp = self.client.post('/resources', params=query, files=files, data=data) data = resp.json() if data.get('error'): logger.error(data['error']) raise ValueError(data['error']) return JoplinResource(**data, resource_type=resource_type)