]> git.rmz.io Git - dotfiles.git/commitdiff
isync: use mbsync instead of offlineimap
authorSamir Benmendil <me@rmz.io>
Mon, 1 Jan 2018 23:14:38 +0000 (23:14 +0000)
committerSamir Benmendil <me@rmz.io>
Mon, 1 Jan 2018 23:14:38 +0000 (23:14 +0000)
isync/config [new file with mode: 0644]
isync/parse-mail.py [new file with mode: 0755]
isync/sync-mail [new file with mode: 0755]
systemd/user/mbsync.service [new file with mode: 0644]
systemd/user/mbsync.timer [new file with mode: 0644]

diff --git a/isync/config b/isync/config
new file mode 100644 (file)
index 0000000..a45fe55
--- /dev/null
@@ -0,0 +1,68 @@
+# write state file into each slaves mailbox
+SyncState *
+CopyArrivalDate yes
+
+IMAPAccount     gmail
+Host            imap.gmail.com
+User            samir.benmendil@gmail.com
+PassCmd         "sed -rn '/imap.gmail.com/ s/.*password (.*)/\\1/p' ~/.netrc"
+SSLType         IMAPS
+CertificateFile /etc/ssl/certs/ca-certificates.crt
+
+IMAPStore gmail-remote
+Account gmail
+
+MaildirStore gmail-local
+Path         ~/mail/gmail/
+Inbox        ~/mail/gmail/inbox/
+SubFolders   Verbatim
+
+Channel gmail-default
+Master  :gmail-remote:
+Slave   :gmail-local:
+Patterns "INBOX"
+
+Channel gmail-youtube
+Master  :gmail-remote:
+Slave   :gmail-local:
+Patterns "youtube"
+
+Channel gmail-youtube-orig
+Master  :gmail-remote:
+Slave   :gmail-local:
+Patterns "youtube-orig"
+
+Channel gmail-archive
+Master :gmail-remote:"[Google Mail]/All Mail"
+Slave :gmail-local:"archive"
+
+Channel gmail-drafts
+Master :gmail-remote:"[Google Mail]/Drafts"
+Slave :gmail-local:"drafts"
+
+Channel gmail-sent
+Master :gmail-remote:"[Google Mail]/Sent Mail"
+Slave :gmail-local:"sent"
+
+Channel gmail-spam
+Master :gmail-remote:"[Google Mail]/Spam"
+Slave :gmail-local:"spam"
+
+Channel gmail-flagged
+Master :gmail-remote:"[Google Mail]/Starred"
+Slave :gmail-local:"flagged"
+
+Channel gmail-bin
+Master :gmail-remote:"[Google Mail]/Bin"
+Slave :gmail-local:"bin"
+
+Group gmail
+Channel gmail-default
+Channel gmail-youtube
+Channel gmail-youtube-orig
+Channel gmail-archive
+Channel gmail-drafts
+Channel gmail-sent
+Channel gmail-spam
+Channel gmail-flagged
+Channel gmail-bin
diff --git a/isync/parse-mail.py b/isync/parse-mail.py
new file mode 100755 (executable)
index 0000000..a72e768
--- /dev/null
@@ -0,0 +1,69 @@
+#!/usr/bin/env python3
+
+from datetime import timedelta
+from email import message_from_file
+import re
+import sys
+import youtube_dl
+
+
+FROM    = "{uploader} <noreply@youtube.com>"
+SUBJECT = "{title}"
+CONTENT = """\
+{uploader} just uploaded a video
+{title} ({duration})
+
+{webpage_url}
+
+Description
+───────────────────────────────────────────────────────────────────────
+
+{description}
+
+───────────────────────────────────────────────────────────────────────
+
+Manage notifications: https://www.youtube.com/subscription_manager
+"""
+
+
+def parse_file(fd):
+    msg = message_from_file(fd)
+
+    payload = ""
+    if msg.is_multipart():
+        for part in msg.get_payload():
+            if part.get_content_type() != 'text/plain':
+                continue
+            charset = part.get_content_charset()
+            payload = part.get_payload(decode=True).decode(charset)
+    else:
+        payload = msg.get_payload(decode=True).decode(charset)
+
+    url = re.search(r'^https?://www.youtube.com/watch\?v=[\w-]{11}', payload, re.MULTILINE).group()
+    # print(url)
+    with youtube_dl.YoutubeDL({'quiet' : True}) as ytdl:
+        info = ytdl.extract_info(url, download=False, force_generic_extractor=True)
+
+    if info is None:
+        return False
+
+    info['duration'] = timedelta(seconds=info['duration'])
+
+    del msg['From']
+    msg['From'] = FROM.format(**info)
+
+    del msg['Subject']
+    msg['Subject'] = SUBJECT.format(**info)
+
+    msg.set_payload(CONTENT.format(**info))
+
+    return msg
+
+
+if __name__ == "__main__":
+    if len(sys.argv) == 1:
+        msg = parse_file(sys.stdin)
+    else:
+        with open(sys.argv[1], 'r') as fd:
+            msg = parse_file(fd)
+    print(msg)
diff --git a/isync/sync-mail b/isync/sync-mail
new file mode 100755 (executable)
index 0000000..a3b8a7a
--- /dev/null
@@ -0,0 +1,60 @@
+#!/usr/bin/env bash
+
+dir="$(dirname "${BASH_SOURCE[0]}")"
+config=$dir/config
+
+### pre-sync {{{
+
+### }}}
+
+### sync {{{
+mbsync -c "$config" -a
+errno=$?
+
+if [[ $errno -ne 0 ]]; then
+    echo "mbsync failed, ignoring post-sync commands." >&2
+    exit $errno
+fi
+### }}}
+
+### post-sync {{{
+yt_src_mb=youtube-orig
+yt_dst_mb=youtube
+yt_parser=$dir/parse-mail.py
+maildir=$(sed -nr 's/^Path\s*(.*)$/\1/p' $config)
+
+
+if [[ -z $maildir ]]; then
+    echo "Could not extract 'Path' from 'MaildirStore' in '$config'" >&2
+    exit 1
+fi
+
+# expand tilde
+maildir=${maildir/#~/$HOME}
+
+shopt -s extglob
+shopt -s nullglob
+for mail in "$maildir"/$yt_src_mb/new/* ; do
+    mangled_mail=${mail/$yt_src_mb/$yt_dst_mb}
+    # remove UID for mbsync to regenerate it
+    mangled_mail="${mangled_mail/,U=+([0-9])}"
+
+    echo -n "Parsing new message '$(basename "$mail")'..."
+    $yt_parser <"$mail" >"$mangled_mail"
+
+    if [[ $? -eq 0 ]]; then
+        echo " Success."
+    else
+        echo " Failure! Copying message as is."
+        cp "$mail" "$mangled_mail"
+    fi
+
+    # sync {a,m}time
+    touch --reference "$mail" "$mangled_mail"
+    mv "$mail" "${mail/new/cur}S"
+done
+# resync new yt_dst_mb
+mbsync -c "$config" gmail-$yt_src_mb gmail-$yt_dst_mb
+
+### }}}
+
diff --git a/systemd/user/mbsync.service b/systemd/user/mbsync.service
new file mode 100644 (file)
index 0000000..27f04ca
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Mailbox synchronization service
+After=network.target network-online.target dbus.socket
+
+[Service]
+Type=oneshot
+ExecStart=%h/.config/isync/sync-mail
diff --git a/systemd/user/mbsync.timer b/systemd/user/mbsync.timer
new file mode 100644 (file)
index 0000000..f07d76a
--- /dev/null
@@ -0,0 +1,10 @@
+[Unit]
+Description=Mailbox synchronization timer
+
+[Timer]
+# every 5 minutes
+OnCalendar=*:00/5:00
+Persistent=true
+
+[Install]
+WantedBy=timers.target