kobitonote.py --Synchronize and save items edited with Kobito to Evernote

What is this?

A python script that saves items edited in Kobito to Evernote

What are you happy about

You can't create text with markdown in Evernote, but with Kobito!

Save the HTML rendered by Kobito to Evernote as it is. For items updated with Kobito, we will update the corresponding Evernote notes. The tags on the Kobito side will also be reflected in Evernote. When you publish an item on Qiita, the public URL will be reflected in Evernote.

Note

Save recently updated items in Kobito to Evernote. The destination notebook is Kobito. If not, it will be made. The "recent" judgment is made by the time stamp saved in the file last_kobito created in the directory where the script is executed.

The interaction with Evernote is AppleScript.

Update monitoring is not performed, so please execute it regularly with cron etc.

Notes

There is no guarantee. It shouldn't be code that loses content on Kobito / Evernote, but please at your own risk.

If the specifications of Kobito change, it may suddenly stop working.

Source

git clone git://github.com/naoyat/qiita-toolkit.git

kobitonote.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
##
## kobitonote -Save Kobito items to Evernote
##
## (c)2012 by @naoya_t
##
import os
import re
import sqlite3
import subprocess
import sys
import time

##Destination notebook
NOTEBOOK_FOR_KOBITO = 'Kobito'

## Kobito.db location PATH
DB_PATH = os.environ['HOME'] + '/Library/Kobito/Kobito.db'

## Kobito.db internal time offset
TIME_OFFSET = 978307200.0 # time.mktime(time.strptime("Mon Jan 1 09:00:00 2001"))

##Last processed timestamp
LAST_KOBITO = './last_kobito'

##Seconds → ISO-8601 format
def iso_8601_jst(t):
    return time.strftime('%Y-%m-%dT%H:%M:%S+09:00', time.localtime(t))

##AppleScript generation
def make_script(title, body, created_at, updated_at, tags, url=None):
    def osa_escape(string):
        return string.replace('¥¥', '¥¥¥¥').replace('"', '¥¥"')
    def my_datetime(t):
        return time.strftime('my datetime(%Y,%m,%d,%H,%M,%S)', time.localtime(t))
    def make_tag_list(tags):
        return '{' + ','.join(['"'+osa_escape(tag)+'"' for tag in tags]) + '}'

    return """
on datetime(year, mon, day, hour, min, sec)
  set d to current date
  set d's year to year
  set d's month to mon
  set d's day to day
  set d's hours to hour
  set d's minutes to min
  set d's seconds to sec
  return d
end datetime

tell application "Evernote"
  set notebookStr to "%s"
  set titleStr to "%s"
  set htmlStr to "%s"
  set createdAt to %s
  set updatedAt to %s
  set tagNameList to %s
  set urlStr to %s

  if not exists notebook notebookStr then
    make new notebook with properties {name:notebookStr}
  end if

  set tagList to {}
  repeat with aTagName in tagNameList
    if exists tag aTagName then
      set aTag to tag aTagName
    else
      set aTag to make new tag with properties {name:aTagName}
    end if
    set end of tagList to aTag
  end repeat

  set destNote to null
  repeat with aNote in (find notes "notebook:" & notebookStr & " intitle:¥¥"" & titleStr & "¥¥"")
    if aNote's creation date = createdAt then
      set destNote to aNote
    end if
  end repeat

  if destNote = null then
    set destNote to (create note with html htmlStr title titleStr notebook notebookStr created createdAt tags tagList)
  else
    set destNote's title to titleStr
    set destNote's HTML content to htmlStr
    set destNote's tags to tagList
  end if
  set destNote's modification date to updatedAt
  if not urlStr is equal to "" then
    set destNote's source URL to urlStr
  end if
end tell
""" % (NOTEBOOK_FOR_KOBITO,
       osa_escape(title),
       osa_escape(body),
       my_datetime(created_at),
       my_datetime(updated_at),
       make_tag_list(tags),
       '"'+url+'"' if url else '""')

##Run applescript
def run_osascript(script, *args):
    p = subprocess.Popen(['arch', '-i386', 'osascript', '-e', script] +
                         [unicode(arg).encode('utf8') for arg in args],
                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    err = p.wait()
    if err:
        raise RuntimeError(err, p.stderr.read()[:-1].decode('utf8'))
    return p.stdout.read()[:-1].decode('utf8')

##Kobito item class
class KobitoItem :
    def __init__(self, row, items_tags={}):
        z_pk, z_ent, z_opt, zprivate, zteam, zcreated_at, zposted_at, zupdated_at, ¥
            zupdated_at_on_qiita, zbody, zkey, zlinked_file, zraw_body, ztitle, zurl, zuuid = row
        self._pk         = z_pk
        self._ent        = z_ent
        self._opt        = z_opt
        self.private     = zprivate
        self.team        = zteam
        self.created_at  = TIME_OFFSET + zcreated_at if zcreated_at else None
        self.posted_at   = TIME_OFFSET + zposted_at if zposted_at else None
        self.updated_at  = TIME_OFFSET + zupdated_at if zupdated_at else None
        self.updated_at_on_qiita = TIME_OFFSET + zupdated_at_on_qiita if zupdated_at_on_qiita else None
        self.body        = zbody.encode('utf-8')
        self.key         = zkey.encode('utf-8')
        self.linked_file = zlinked_file
        self.raw_body    = zraw_body.encode('utf-8')
        self.title       = ztitle.encode('utf-8')
        self.url         = zurl.encode('utf-8') if zurl else None
        self.uuid        = zuuid  #
        self.tags        = items_tags[z_pk] if items_tags.has_key(z_pk) else []

    def save_in_evernote(self):
        title = self.title
        body = self.body ¥
            .replace("<!DOCTYPE HTML>¥n", "") ¥
            .replace('rel="stylesheet" href="',
                     'rel="stylesheet" href="/Applications/Kobito.app/Contents/Resources/')
        body = re.sub(r'[ ¥t]*<script[^¥n]*</script>¥n', r'', body)
        body = re.sub(r'  <body>¥n<h1>[^¥n]*</h1>', r'<body>', body)

        script = make_script(title, body, self.created_at, self.updated_at, self.tags, self.url)
        # print script

        sys.stderr.write(iso_8601_jst(self.updated_at))
        sys.stderr.write("「" + self.title + "」")
        sys.stderr.write(" ".join(self.tags) + "¥n")
        run_osascript(script)

##Get the tag on the Kobito side
def get_kobito_tags(conn):
    c = conn.cursor()
    c.execute(u"select * from ZTAG")
    tags = {}
    for _pk, _ent, _opt, name in c:
        tags[_pk] = name.encode('utf-8')
    return tags

##Get tags attached to Kobito items
## {Item ID 1: [Tag ID1,Tag ID2, ...],Item ID 2: [...], ...}
##If the tag has been acquired, replace the tag ID with a character string
## {Item ID 1: [Tag 1,Tag 2, ...],Item ID 2: [...], ...}
def get_kobito_items_tags(conn, tags=None):
    items_tags = {}
    c = conn.cursor()
    c.execute(u"select * from Z_1TAGS")
    for _1items, _2tags in c:
        if tags:
            _2tags = tags[_2tags]
        if items_tags.has_key(_1items):
            items_tags[_1items].append(_2tags)
        else:
            items_tags[_1items] = [_2tags]
    return items_tags

##Get Kobito items
def get_kobito_items(conn, last, items_tags=None):
    c = conn.cursor()
    c.execute(u"select * from ZITEM where ZUPDATED_AT > %s" % str(last))
    return [KobitoItem(row, items_tags) for row in c]

##Save recent updates (= since the last time you ran this script) in evernote
##Evernote deduplication created_Match only by at and title
def save_recent_to_evernote():
    def last_kobito_time():
        if os.path.exists(LAST_KOBITO):
            with open(LAST_KOBITO, 'r') as fp:
                return float(fp.readline().rstrip())
        else:
            return 0
    def save_current_kobito_time():
        current_kobito_time = time.time() - TIME_OFFSET
        with open(LAST_KOBITO, 'w') as fp:
            fp.write(str(current_kobito_time) + '¥n')

    conn = sqlite3.connect(DB_PATH)

    tags = get_kobito_tags(conn)
    items_tags = get_kobito_items_tags(conn, tags)
    for item in get_kobito_items(conn, last_kobito_time(), items_tags):
        item.save_in_evernote()

    conn.close()
    save_current_kobito_time()


if __name__ == '__main__':
    save_recent_to_evernote()

Recommended Posts

kobitonote.py --Synchronize and save items edited with Kobito to Evernote
I tried to automatically read and save with VOICEROID2
Operate Jupyter with REST API to extract and save Python code
Correspondence analysis of sentences with COTOHA API and save to file
Save and retrieve files with Pepper
Get tweets with Google Cloud Function and automatically save images to Google Photos
How to query BigQuery with Kubeflow Pipelines and save the result and notes
How to split and save a DataFrame
Fractal to make and play with Python
Edit and save read-only files with vim
The file edited with vim was readonly but I want to save it
Ssh connect to Cisco Catalyst with CentOS7 + Python3 + netmiko and save config locally