diff --git a/helpers/README.md b/helpers/README.md index 457e7dd..6fe3878 100644 --- a/helpers/README.md +++ b/helpers/README.md @@ -6,6 +6,20 @@ These are helper tools to work with Fabric. Examples include things like getting `yt` is a command that uses the YouTube API to pull transcripts, get video duration, and other functions. It's primary function is to get a transcript from a video that can then be stitched (piped) into other Fabric Patterns. +```bash +usage: yt [-h] [--duration] [--transcript] [url] + +vm (video meta) extracts metadata about a video, such as the transcript and the video's duration. By Daniel Miessler. + +positional arguments: + url YouTube video URL + +options: + -h, --help show this help message and exit + --duration Output only the duration + --transcript Output only the transcript +``` + ## ts (Audio transcriptions) 'ts' is a command that uses the OpenApi Whisper API to transcribe audio files. Due to the context window, this tool uses pydub to split the files into 10 minute segments. for more information on pydub, please refer https://github.com/jiaaro/pydub @@ -24,9 +38,6 @@ windows: download instructions https://www.ffmpeg.org/download.html ``` -````bash -usage: yt [-h] [--duration] [--transcript] [url] - ```bash ts -h @@ -39,4 +50,43 @@ positional arguments: options: -h, --help show this help message and exit -```` + +## save + +`save` is a "tee-like" utility to pipeline saving of content, while keeping the output stream intact. Can optionally generate "frontmatter" for PKM utilities like Obsidian via the +"FABRIC_FRONTMATTER" environment variable + + + +If you'd like to default variables, set them in `~/.config/fabric/.env`. `FABRIC_OUTPUT_PATH` needs to be set so `save` where to write. `FABRIC_FRONTMATTER_TAGS` is optional, but useful for tracking how tags have entered your PKM, if that's important to you. + +### usage +```bash +usage: save [-h] [-t, TAG] [-n] [-s] [stub] + +save: a "tee-like" utility to pipeline saving of content, while keeping the output stream intact. Can optionally generate "frontmatter" for PKM utilities like Obsidian via the +"FABRIC_FRONTMATTER" environment variable + +positional arguments: + stub stub to describe your content. Use quotes if you have spaces. Resulting format is YYYY-MM-DD-stub.md by default + +options: + -h, --help show this help message and exit + -t, TAG, --tag TAG add an additional frontmatter tag. Use this argument multiple timesfor multiple tags + -n, --nofabric don't use the fabric tags, only use tags from --tag + -s, --silent don't use STDOUT for output, only save to the file +``` +### example + +```bash +echo test | save --tag extra-tag stub-for-name +test + +$ cat ~/obsidian/Fabric/2024-03-02-stub-for-name.md +--- +generation_date: 2024-03-02 10:43 +tags: fabric-extraction stub-for-name extra-tag +--- +test +``` + diff --git a/helpers/save.py b/helpers/save.py new file mode 100755 index 0000000..9c67744 --- /dev/null +++ b/helpers/save.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 +import argparse +import os +import sys +from datetime import datetime + +from dotenv import load_dotenv + +DEFAULT_CONFIG = "~/.config/fabric/.env" +PATH_KEY = "FABRIC_OUTPUT_PATH" +FM_KEY = "FABRIC_FRONTMATTER_TAGS" +DATE_FORMAT = "%Y-%m-%d" +load_dotenv(os.path.expanduser(DEFAULT_CONFIG)) + + +def main(tag, tags, silent, fabric): + out = os.getenv(PATH_KEY) + if out is None: + print(f"'{PATH_KEY}' not set in {DEFAULT_CONFIG} or in your environment.") + sys.exit(1) + + out = os.path.expanduser(out) + + if not os.path.isdir(out): + print(f"'{out}' does not exist. Create it and try again.") + sys.exit(1) + + if not out.endswith("/"): + out += "/" + + if len(sys.argv) < 2: + print(f"'{sys.argv[0]}' takes a single argument to tag your summary") + sys.exit(1) + + yyyymmdd = datetime.now().strftime(DATE_FORMAT) + target = f"{out}{yyyymmdd}-{tag}.md" + + # don't clobber existing files- add an incremented number to the end instead + would_clobber = True + inc = 0 + while would_clobber: + if inc > 0: + target = f"{out}{yyyymmdd}-{tag}-{inc}.md" + if os.path.exists(target): + inc += 1 + else: + would_clobber = False + + # YAML frontmatter stubs for things like Obsidian + # Prevent a NoneType ending up in the tags + frontmatter_tags = "" + if fabric: + frontmatter_tags = os.getenv(FM_KEY) + + with open(target, "w") as fp: + if frontmatter_tags or len(tags) != 0: + fp.write("---\n") + now = datetime.now().strftime(f"{DATE_FORMAT} %H:%M") + fp.write(f"generation_date: {now}\n") + fp.write(f"tags: {frontmatter_tags} {tag} {' '.join(tags)}\n") + fp.write("---\n") + + # function like 'tee' and split the output to a file and STDOUT + for line in sys.stdin: + if not silent: + print(line, end="") + fp.write(line) + + +def cli(): + parser = argparse.ArgumentParser( + description=( + 'save: a "tee-like" utility to pipeline saving of content, ' + "while keeping the output stream intact. Can optionally generate " + '"frontmatter" for PKM utilities like Obsidian via the ' + '"FABRIC_FRONTMATTER" environment variable' + ) + ) + parser.add_argument( + "stub", + nargs="?", + help=( + "stub to describe your content. Use quotes if you have spaces. " + "Resulting format is YYYY-MM-DD-stub.md by default" + ), + ) + parser.add_argument( + "-t,", + "--tag", + required=False, + action="append", + default=[], + help=( + "add an additional frontmatter tag. Use this argument multiple times" + "for multiple tags" + ), + ) + parser.add_argument( + "-n", + "--nofabric", + required=False, + action="store_false", + help="don't use the fabric tags, only use tags from --tag", + ) + parser.add_argument( + "-s", + "--silent", + required=False, + action="store_true", + help="don't use STDOUT for output, only save to the file", + ) + args = parser.parse_args() + + if args.stub: + main(args.stub, args.tag, args.silent, args.nofabric) + else: + parser.print_help() + + +if __name__ == "__main__": + cli() diff --git a/helpers/yt.py b/helpers/yt.py index 4c84ee4..2b096b7 100644 --- a/helpers/yt.py +++ b/helpers/yt.py @@ -52,7 +52,7 @@ def main_function(url, options): transcript_text = " ".join([item["text"] for item in transcript_list]) transcript_text = transcript_text.replace("\n", " ") except Exception as e: - transcript_text = "Transcript not available." + transcript_text = f"Transcript not available. ({e})" # Output based on options if options.duration: @@ -65,13 +65,20 @@ def main_function(url, options): # Print JSON object print(json.dumps(output)) except HttpError as e: - print( - "Error: Failed to access YouTube API. Please check your YOUTUBE_API_KEY and ensure it is valid." - ) + + print(f"Error: Failed to access YouTube API. Please check your YOUTUBE_API_KEY and ensure it is valid: {e}") + def main(): parser = argparse.ArgumentParser( + + description='yt (video meta) extracts metadata about a video, such as the transcript and the video\'s duration. By Daniel Miessler.') + parser.add_argument('url', nargs='?', help='YouTube video URL') + parser.add_argument('--duration', action='store_true', + help='Output only the duration') + parser.add_argument('--transcript', action='store_true', + help='Output only the transcript') description="vm (video meta) extracts metadata about a video, such as the transcript and the video's duration. By Daniel Miessler." ) parser.add_argument("url", nargs="?", help="YouTube video URL") @@ -81,13 +88,3 @@ def main(): parser.add_argument( "--transcript", action="store_true", help="Output only the transcript" ) - args = parser.parse_args() - - if args.url: - main_function(args.url, args) - else: - parser.print_help() - - -if __name__ == "__main__": - main() diff --git a/pyproject.toml b/pyproject.toml index 0b8b0ee..92c81b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,3 +69,4 @@ fabric-api = 'installer:run_api_server' fabric-webui = 'installer:run_webui_server' ts = 'helpers.ts:main' yt = 'helpers.yt:main' +save = 'helpers.save:cli'