2021-08-16 07:49:09 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
# Import Modules
|
2021-08-17 02:37:44 +02:00
|
|
|
from processor.org_mode import orgnode
|
2021-08-17 01:33:43 +02:00
|
|
|
from utils.helpers import get_absolute_path, is_none_or_empty
|
2021-08-16 07:49:09 +02:00
|
|
|
import json
|
|
|
|
import argparse
|
|
|
|
import pathlib
|
|
|
|
import glob
|
|
|
|
import gzip
|
|
|
|
|
|
|
|
|
|
|
|
# Define Functions
|
2021-08-17 02:37:44 +02:00
|
|
|
def org_to_jsonl(org_files, org_file_filter, output_file, verbose=0):
|
2021-08-17 00:59:13 +02:00
|
|
|
# Get Org Files to Process
|
2021-08-17 02:37:44 +02:00
|
|
|
org_files = get_org_files(org_files, org_file_filter, verbose)
|
2021-08-17 00:59:13 +02:00
|
|
|
|
|
|
|
# Extract Entries from specified Org files
|
|
|
|
entries = extract_org_entries(org_files)
|
|
|
|
|
|
|
|
# Process Each Entry from All Notes Files
|
2021-08-17 02:37:44 +02:00
|
|
|
jsonl_data = convert_org_entries_to_jsonl(entries, verbose=verbose)
|
2021-08-17 00:59:13 +02:00
|
|
|
|
|
|
|
# Compress JSONL formatted Data
|
2021-08-17 02:37:44 +02:00
|
|
|
if output_file.suffix == ".gz":
|
|
|
|
compress_jsonl_data(jsonl_data, output_file, verbose=verbose)
|
|
|
|
elif output_file.suffix == ".jsonl":
|
|
|
|
dump_jsonl(jsonl_data, output_file, verbose=verbose)
|
2021-08-17 00:59:13 +02:00
|
|
|
|
|
|
|
return entries
|
|
|
|
|
2021-08-16 07:49:09 +02:00
|
|
|
def dump_jsonl(jsonl_data, output_path, verbose=0):
|
|
|
|
"Write List of JSON objects to JSON line file"
|
2021-08-16 22:22:46 +02:00
|
|
|
with open(get_absolute_path(output_path), 'w', encoding='utf-8') as f:
|
2021-08-16 07:49:09 +02:00
|
|
|
f.write(jsonl_data)
|
|
|
|
|
|
|
|
if verbose > 0:
|
2021-08-17 03:50:29 +02:00
|
|
|
print(f'Wrote {len(jsonl_data)} lines to jsonl at {output_path}')
|
2021-08-16 07:49:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
def compress_jsonl_data(jsonl_data, output_path, verbose=0):
|
2021-08-16 22:44:42 +02:00
|
|
|
with gzip.open(get_absolute_path(output_path), 'wt') as gzip_file:
|
2021-08-16 07:49:09 +02:00
|
|
|
gzip_file.write(jsonl_data)
|
|
|
|
|
|
|
|
if verbose > 0:
|
2021-08-17 03:50:29 +02:00
|
|
|
print(f'Wrote {len(jsonl_data)} lines to gzip compressed jsonl at {output_path}')
|
2021-08-16 07:49:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
def load_jsonl(input_path, verbose=0):
|
|
|
|
"Read List of JSON objects from JSON line file"
|
|
|
|
data = []
|
2021-08-16 22:22:46 +02:00
|
|
|
with open(get_absolute_path(input_path), 'r', encoding='utf-8') as f:
|
2021-08-16 07:49:09 +02:00
|
|
|
for line in f:
|
|
|
|
data.append(json.loads(line.rstrip('\n|\r')))
|
|
|
|
|
|
|
|
if verbose > 0:
|
|
|
|
print(f'Loaded {len(data)} records from {input_path}')
|
|
|
|
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
2021-08-17 02:15:41 +02:00
|
|
|
def get_org_files(org_files=None, org_file_filter=None, verbose=0):
|
2021-08-16 07:49:09 +02:00
|
|
|
"Get Org files to process"
|
2021-08-16 20:17:42 +02:00
|
|
|
absolute_org_files, filtered_org_files = set(), set()
|
2021-08-16 07:49:09 +02:00
|
|
|
if org_files:
|
2021-08-16 20:17:42 +02:00
|
|
|
absolute_org_files = {get_absolute_path(org_file)
|
|
|
|
for org_file
|
|
|
|
in org_files}
|
|
|
|
if org_file_filter:
|
|
|
|
filtered_org_files = set(glob.glob(get_absolute_path(org_file_filter)))
|
|
|
|
|
|
|
|
all_org_files = absolute_org_files | filtered_org_files
|
2021-08-16 22:26:49 +02:00
|
|
|
|
|
|
|
files_with_non_org_extensions = {org_file for org_file in all_org_files if not org_file.endswith(".org")}
|
|
|
|
if any(files_with_non_org_extensions):
|
|
|
|
print(f"[Warning] There maybe non org-mode files in the input set: {files_with_non_org_extensions}")
|
|
|
|
|
2021-08-17 02:37:44 +02:00
|
|
|
if verbose > 0:
|
2021-08-16 20:17:42 +02:00
|
|
|
print(f'Processing files: {all_org_files}')
|
2021-08-16 07:49:09 +02:00
|
|
|
|
2021-08-16 20:17:42 +02:00
|
|
|
return all_org_files
|
2021-08-16 07:49:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
def extract_org_entries(org_files):
|
|
|
|
"Extract entries from specified Org files"
|
|
|
|
entries = []
|
|
|
|
for org_file in org_files:
|
|
|
|
entries.extend(
|
|
|
|
orgnode.makelist(
|
|
|
|
str(org_file)))
|
|
|
|
|
|
|
|
return entries
|
|
|
|
|
2021-08-16 20:17:42 +02:00
|
|
|
|
2021-08-16 22:05:35 +02:00
|
|
|
def convert_org_entries_to_jsonl(entries, verbose=0):
|
|
|
|
"Convert each Org-Mode entries to JSON and collate as JSONL"
|
2021-08-16 07:49:09 +02:00
|
|
|
jsonl = ''
|
|
|
|
for entry in entries:
|
|
|
|
entry_dict = dict()
|
|
|
|
|
|
|
|
entry_dict["Title"] = entry.Heading()
|
|
|
|
if verbose > 1:
|
|
|
|
print(f"Title: {entry.Heading()}")
|
|
|
|
|
|
|
|
if entry.Tags():
|
|
|
|
tags_str = " ".join([tag for tag in entry.Tags()])
|
|
|
|
entry_dict["Tags"] = tags_str
|
|
|
|
if verbose > 1:
|
|
|
|
print(f"Tags: {tags_str}")
|
|
|
|
|
|
|
|
if entry.Body():
|
|
|
|
entry_dict["Body"] = entry.Body()
|
|
|
|
if verbose > 2:
|
|
|
|
print(f"Body: {entry.Body()}")
|
|
|
|
|
|
|
|
if entry_dict:
|
|
|
|
# Convert Dictionary to JSON and Append to JSONL string
|
|
|
|
jsonl += f'{json.dumps(entry_dict, ensure_ascii=False)}\n'
|
|
|
|
|
2021-08-17 03:50:29 +02:00
|
|
|
if verbose > 0:
|
|
|
|
print(f"Converted {len(entries)} to jsonl format")
|
|
|
|
|
2021-08-16 07:49:09 +02:00
|
|
|
return jsonl
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2021-08-16 22:22:46 +02:00
|
|
|
# Setup Argument Parser
|
2021-08-16 20:17:42 +02:00
|
|
|
parser = argparse.ArgumentParser(description="Map Org-Mode notes into (compressed) JSONL format")
|
2021-08-16 22:44:42 +02:00
|
|
|
parser.add_argument('--output-file', '-o', type=pathlib.Path, required=True, help="Output file for (compressed) JSONL formatted notes. Expected file extensions: jsonl or jsonl.gz")
|
|
|
|
parser.add_argument('--input-files', '-i', nargs='*', help="List of org-mode files to process")
|
|
|
|
parser.add_argument('--input-filter', type=str, default=None, help="Regex filter for org-mode files to process")
|
2021-08-16 07:49:09 +02:00
|
|
|
parser.add_argument('--verbose', '-v', action='count', help="Show verbose conversion logs")
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
2021-08-16 22:44:42 +02:00
|
|
|
# Input Validation
|
|
|
|
if is_none_or_empty(args.input_files) and is_none_or_empty(args.input_filter):
|
2021-08-16 20:17:42 +02:00
|
|
|
print("At least one of org-files or org-file-filter is required to be specified")
|
2021-08-16 22:22:46 +02:00
|
|
|
exit(1)
|
2021-08-16 20:17:42 +02:00
|
|
|
|
2021-08-17 00:59:13 +02:00
|
|
|
# Map notes in Org-Mode files to (compressed) JSONL formatted file
|
|
|
|
org_to_jsonl(args.input_files, args.input_filter, args.output_file, args.verbose)
|