Upload current progress
This commit is contained in:
136
obsidian_automator/note_server.py
Normal file
136
obsidian_automator/note_server.py
Normal file
@@ -0,0 +1,136 @@
|
||||
import os
|
||||
import shutil
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import List
|
||||
|
||||
class NoteServer(ABC):
|
||||
@abstractmethod
|
||||
def list_notes(self, directory: str) -> List[str]:
|
||||
"""List all markdown files in the directory."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def read_note(self, file_path: str) -> str:
|
||||
"""Read content of a note."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def move_note(self, file_path: str, target_folder: str) -> str:
|
||||
"""Move a note to a target folder."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def flag_rewrite(self, file_path: str, reason: str, rewrite_tag: str) -> str:
|
||||
"""Append a rewrite tag and reason to the note."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def list_subfolders(self, directory: str) -> List[str]:
|
||||
"""List immediate subdirectories."""
|
||||
pass
|
||||
|
||||
class FileSystemServer(NoteServer):
|
||||
def list_subfolders(self, directory: str) -> List[str]:
|
||||
if not os.path.exists(directory):
|
||||
return []
|
||||
try:
|
||||
return [d for d in os.listdir(directory) if os.path.isdir(os.path.join(directory, d)) and not d.startswith(".")]
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
def list_notes(self, directory: str) -> List[str]:
|
||||
notes = []
|
||||
if not os.path.exists(directory):
|
||||
return []
|
||||
for root, _, files in os.walk(directory):
|
||||
for file in files:
|
||||
if file.endswith(".md"):
|
||||
# Only return absolute paths to keep things simple
|
||||
notes.append(os.path.abspath(os.path.join(root, file)))
|
||||
return notes
|
||||
|
||||
def read_note(self, file_path: str) -> str:
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
return f.read()
|
||||
except Exception as e:
|
||||
return f"Error reading file: {str(e)}"
|
||||
|
||||
def move_note(self, file_path: str, target_folder: str) -> str:
|
||||
try:
|
||||
filename = os.path.basename(file_path)
|
||||
|
||||
# Ensure target folder exists
|
||||
if not os.path.exists(target_folder):
|
||||
os.makedirs(target_folder)
|
||||
|
||||
new_path = os.path.join(target_folder, filename)
|
||||
|
||||
# Prevent overwriting by appending timestamp if exists, or just fail safely
|
||||
if os.path.exists(new_path):
|
||||
return f"Error: File {filename} already exists in {target_folder}"
|
||||
|
||||
shutil.move(file_path, new_path)
|
||||
return f"Moved {filename} to {target_folder}"
|
||||
except Exception as e:
|
||||
return f"Error moving file: {str(e)}"
|
||||
|
||||
def flag_rewrite(self, file_path: str, reason: str, rewrite_tag: str) -> str:
|
||||
try:
|
||||
# Check if file ends with newline to avoid appending on same line
|
||||
with open(file_path, "r+", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
prefix = "\n" if content and not content.endswith("\n") else ""
|
||||
f.write(f"{prefix}\n{rewrite_tag} {reason}\n")
|
||||
return f"Flagged {os.path.basename(file_path)} for rewrite: {reason}"
|
||||
except Exception as e:
|
||||
return f"Error flagging file: {str(e)}"
|
||||
|
||||
from .couch_manager import CouchDBManager
|
||||
|
||||
class CouchDBNoteServer(NoteServer):
|
||||
def __init__(self, url, user, password, db_name):
|
||||
self.manager = CouchDBManager(url, user, password, db_name)
|
||||
|
||||
def list_notes(self, directory: str) -> List[str]:
|
||||
# Directory here acts as a prefix filter
|
||||
files_dict = self.manager.list_files(prefix_filter=directory)
|
||||
return list(files_dict.keys())
|
||||
|
||||
def list_subfolders(self, directory: str) -> List[str]:
|
||||
# CouchDB is flat. We simulate folders by looking at paths.
|
||||
# This is expensive (scan all), but accurate.
|
||||
all_files_dict = self.manager.list_files()
|
||||
subfolders = set()
|
||||
|
||||
# If directory is "(All Notes)", we look at root folders
|
||||
# If directory is "Inbox", we look at "Inbox/Subfolder"
|
||||
|
||||
prefix = directory if directory != "(All Notes)" else ""
|
||||
prefix = prefix.strip("/")
|
||||
|
||||
for doc_id, path in all_files_dict.items():
|
||||
|
||||
# Normalize path
|
||||
path = path.replace("\\", "/")
|
||||
|
||||
if prefix and not path.startswith(prefix + "/"):
|
||||
continue
|
||||
|
||||
# Strip prefix
|
||||
relative_path = path[len(prefix)+1:] if prefix else path
|
||||
|
||||
if "/" in relative_path:
|
||||
top_level = relative_path.split("/")[0]
|
||||
subfolders.add(top_level)
|
||||
|
||||
return sorted(list(subfolders))
|
||||
|
||||
def read_note(self, file_path: str) -> str:
|
||||
return self.manager.read_file_content(file_path)
|
||||
|
||||
def move_note(self, file_path: str, target_folder: str) -> str:
|
||||
return self.manager.move_file(file_path, target_folder)
|
||||
|
||||
def flag_rewrite(self, file_path: str, reason: str, rewrite_tag: str) -> str:
|
||||
return self.manager.flag_rewrite(file_path, reason, rewrite_tag)
|
||||
Reference in New Issue
Block a user