-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
1,573 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# editorconfig.org | ||
root = true | ||
|
||
# Defaults | ||
[*] | ||
end_of_line = lf | ||
charset = utf-8 | ||
trim_trailing_whitespace = true | ||
insert_final_newline = true | ||
|
||
# Python | ||
[*.py] | ||
indent_style = space | ||
indent_size = 4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
# Project specific stuff | ||
testing/ | ||
|
||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
snsync, like rsync for Simplenote | ||
################################## | ||
|
||
snsync is a kinda rsync implementation for Simplenote where your notes can be downloaded (& and uploaded) from plain text files. | ||
|
||
The primary use case is for periodic synchronisation by cron, with all the *useful* output going to a log file and the console output being *pretty* for when humans sync manually. | ||
|
||
The configuration file | ||
---------------------- | ||
|
||
By default, you need `~/.snsync` but the command line options do allow to select another file, the minimal info needed is a username and password:: | ||
|
||
[snsync] | ||
cfg_sn_username = [email protected] | ||
cfg_sn_password = secret | ||
|
||
*IMPORTANT! Protect your .snsync file with the correct permissions and disk encryption* | ||
|
||
A few additional options are possible: | ||
|
||
* `cfg_nt_path = /Users/linickx/mynotes` to change the default note path (`~/Simplenote`) | ||
* `cfg_log_path = /Users/Library/Logs/snsync.log` to change the default log path (which is typically within `cfg_nt_path`). Use the keyword `DISABLED` to enable console logging. | ||
* `cfg_log_level = debug` the default logging level is `info`, the brave can change this to `error`, ninja's can enable `debug` | ||
|
||
The command line options | ||
------------------------ | ||
|
||
The following usage/options are available:: | ||
|
||
Usage: snsync [OPTIONS] | ||
|
||
OPTIONS: | ||
-h, --help Help! | ||
-d, --dry-run Dry Run Mode (no changes made/saved) | ||
-s, --silent Silent Mode (no std output) | ||
-c, --config= Config file to read (default: ~/.snsync) | ||
For example: just `snsync` on it's own should work, but something like this can be used for cron: `snsync -s --config=something.txt` | ||
|
||
File Deletions | ||
-------------- | ||
|
||
snsync doesn't delete any files, you can check the source code yourself ;) | ||
|
||
When a file is marked for deletion on Simplenote, the local note (*text file*) equivalent is moved to a `.trash` directory. When a file is deleted locally the Simplenote equivalent is marked with Trash tag. | ||
|
||
File Conflicts | ||
-------------- | ||
|
||
If your cron job is very sporadic it possible that a change could be made on the Simplenote server and locally, when this happens the local file is renamed, for example `hello world.txt` would become `DUP_date_hello world.txt` (*where date is the date/time the file was moved*). Duplicates are then uploaded back into Simplenote for safe keeping. | ||
|
||
Local file names are based on the first line of the Simplenote "note". Filenames are generated on a first come, first served basis, for example if you create a Simplenote online with the first line "hello world" then `hello world.txt` will be created, if you create a 2nd note, with completely different contents but the first line is "hello world" then the 2nd file will be called `date_hello world.txt` (*where date is the date/time the file was created*) | ||
|
||
File Modifications | ||
------------------ | ||
|
||
snsync works by maintaining a local sqlite database, typically `.snsycn.sqlite` inside your `cfg_nt_path`. The database maintains a copy of the Simplenote list and a meta table that links Simplenotes to text files. | ||
|
||
The script works by comparing the latest Simplenote list to the local cache, and then compares the last modified dates of local files; moves/adds/changes/deletions are then replicated by-directionally. The `--dry-run` option can be used to observe what is going to happen without making any changes. | ||
|
||
For those wondering what the log file strings like `agtzaW1wbZRiusssu5sIDAasdfuhas` are; that's the "key" used in the Simplenote cloud to store your note, the local meta database keeps track of those and associates a file name... the cloud don't need no file names dude! ;-) | ||
|
||
Large Note Databases | ||
-------------------- | ||
|
||
The Simplenote API is rate limited, if your note database is large (like mine -> 1,200 notes) then the first full sync will take a long time (mine -> approx 15mins) you will also find a high number of `HTTP ERRORS` reported, just wait and re-run the script, missed notes will be downloaded. | ||
|
||
AoB | ||
--- | ||
|
||
No warranty is offered, use this at your own risk; I use this for my personal production notes but I always keep backups. The recommended approach is to manually download all your notes for a backup, then use the `--dry-run` option to observe changes until you are happy. | ||
|
||
Credz, props and big-ups to https://github.com/insanum/sncli and https://github.com/mrtazz/Simplenote.py as without these opensource projects, snsync would not have got off the ground :) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
""" | ||
Configuration settings for snsync | ||
""" | ||
# pylint: disable=W0702 | ||
# pylint: disable=C0301 | ||
|
||
import os | ||
import collections | ||
import configparser | ||
|
||
class Config: | ||
""" | ||
Config Object | ||
""" | ||
|
||
def __init__(self, custom_file=None): | ||
""" | ||
Defult settings and the like. | ||
""" | ||
self.home = os.path.abspath(os.path.expanduser('~')) | ||
# Static Defaults | ||
defaults = \ | ||
{ | ||
'cfg_sn_username' : '', | ||
'cfg_sn_password' : '', | ||
'cfg_nt_ext' : 'txt', | ||
'cfg_nt_path' : os.path.join(self.home, 'Simplenote'), | ||
'cfg_nt_trashpath' : '.trash', | ||
'cfg_nt_filenamelen' : '60', | ||
'cfg_log_level' : 'info' | ||
} | ||
|
||
cp = configparser.SafeConfigParser(defaults) | ||
if custom_file is not None: | ||
self.configs_read = cp.read([custom_file]) | ||
else: | ||
self.configs_read = cp.read([os.path.join(self.home, '.snsync')]) | ||
|
||
cfg_sec = 'snsync' | ||
|
||
if not cp.has_section(cfg_sec): | ||
cp.add_section(cfg_sec) | ||
|
||
self.configs = collections.OrderedDict() | ||
self.configs['sn_username'] = [cp.get(cfg_sec, 'cfg_sn_username', raw=True), 'Simplenote Username'] | ||
self.configs['sn_password'] = [cp.get(cfg_sec, 'cfg_sn_password', raw=True), 'Simplenote Password'] | ||
self.configs['cfg_nt_ext'] = [cp.get(cfg_sec, 'cfg_nt_ext'), 'Note file extension'] | ||
self.configs['cfg_nt_path'] = [cp.get(cfg_sec, 'cfg_nt_path'), 'Note storage path'] | ||
self.configs['cfg_nt_trashpath'] = [cp.get(cfg_sec, 'cfg_nt_trashpath'), 'Note Trash Bin Folder for deleted notes'] | ||
self.configs['cfg_nt_filenamelen'] = [cp.get(cfg_sec, 'cfg_nt_filenamelen'), 'Length of Filename'] | ||
self.configs['cfg_log_level'] = [cp.get(cfg_sec, 'cfg_log_level'), 'snsync log level'] | ||
|
||
# Dynamic Defaults | ||
if cp.has_option(cfg_sec, 'cfg_db_path'): | ||
self.configs['cfg_db_path'] = [cp.get(cfg_sec, 'cfg_db_path'), 'snsync database location'] | ||
else: | ||
self.configs['cfg_db_path'] = [os.path.join(cp.get(cfg_sec, 'cfg_nt_path'), '.snsync.sqlite'), 'snsync database location'] | ||
|
||
if cp.has_option(cfg_sec, 'cfg_log_path'): | ||
self.configs['cfg_log_path'] = [cp.get(cfg_sec, 'cfg_log_path'), 'snsync log location'] | ||
else: | ||
self.configs['cfg_log_path'] = [os.path.join(cp.get(cfg_sec, 'cfg_nt_path'), '.snsync.log'), 'snsync log location'] | ||
|
||
def get_config(self, name): | ||
""" | ||
Return a config setting | ||
""" | ||
return self.configs[name][0] | ||
|
||
def get_config_descr(self, name): | ||
""" | ||
Return a config description (future use in docs) | ||
""" | ||
return self.configs[name][1] |
Oops, something went wrong.