101 lines
3.1 KiB
Python
101 lines
3.1 KiB
Python
import datetime
|
|
import json
|
|
from decimal import Decimal
|
|
from logging import getLogger
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import frontmatter
|
|
|
|
logger = getLogger(__name__)
|
|
|
|
StatisticKey = str
|
|
|
|
|
|
class ObsidianVault:
|
|
def __init__(self, vault_path: Path, read_only: bool = 'silent'):
|
|
self.vault_path = vault_path
|
|
|
|
assert (self.vault_path / '.obsidian').exists(), 'Not an Obsidian Vault'
|
|
|
|
with open(self.vault_path / '.obsidian' / 'daily-notes.json') as f:
|
|
daily_notes_config = json.load(f)
|
|
self.daily_folder = daily_notes_config['folder']
|
|
self.path_format = daily_notes_config['format']
|
|
self.template_file_path = daily_notes_config['template']
|
|
self.read_only = read_only
|
|
|
|
def get_statistic(
|
|
self, date: datetime.date, statistic_key: StatisticKey,
|
|
) -> Any | None:
|
|
try:
|
|
with open(self._date_file_path(date)) as f:
|
|
data = frontmatter.load(f)
|
|
except FileNotFoundError:
|
|
return None
|
|
|
|
return data.metadata.get(statistic_key)
|
|
|
|
def add_statistic(
|
|
self, date: datetime.date, statistic_key: StatisticKey, amount: Any,
|
|
) -> bool:
|
|
if self.read_only == 'silent':
|
|
logger.info(
|
|
'Real only ObsidianVault ignoring add_statistic(%s, "%s", %s)',
|
|
date,
|
|
statistic_key,
|
|
amount,
|
|
)
|
|
return False
|
|
|
|
self._create_date_if_not_present(date)
|
|
|
|
with open(self._date_file_path(date)) as f:
|
|
data = frontmatter.load(f)
|
|
|
|
if isinstance(amount, Decimal):
|
|
amount = float(amount)
|
|
|
|
if data.metadata.get(statistic_key) == amount:
|
|
return False
|
|
|
|
data.metadata[statistic_key] = amount
|
|
if amount is None:
|
|
del data.metadata[statistic_key]
|
|
|
|
with open(self._date_file_path(date), 'wb') as f:
|
|
frontmatter.dump(data, f)
|
|
|
|
return True
|
|
|
|
def add_event(self, date: datetime.date, verb: str, subject: str) -> None:
|
|
if self.read_only == 'silent':
|
|
logger.info(
|
|
'Real only ObsidianVault ignoring add_event(%s, "%s", ?)', date, verb,
|
|
)
|
|
return
|
|
|
|
self._create_date_if_not_present(date)
|
|
# TODO
|
|
|
|
def _create_date_if_not_present(self, date: datetime.date):
|
|
date_file = self._date_file_path(date)
|
|
if date_file.exists():
|
|
return
|
|
logger.info('File "%s" doesn\'t exist, creating...', date)
|
|
with open(self._daily_template_path()) as f:
|
|
template_text = f.read()
|
|
with open(date_file, 'w') as f:
|
|
f.write(template_text)
|
|
|
|
def _date_file_path(self, date: datetime.date):
|
|
path = (
|
|
self.path_format.replace('YYYY', str(date.year))
|
|
.replace('MM', f'{date.month:02d}')
|
|
.replace('DD', f'{date.day:02d}')
|
|
)
|
|
return (self.vault_path / self.daily_folder / path).with_suffix('.md')
|
|
|
|
def _daily_template_path(self):
|
|
return (self.vault_path / self.template_file_path).with_suffix('.md')
|