From b5e57be17d6bf6d2ccf72b88e9d6d279a49a2e3f Mon Sep 17 00:00:00 2001 From: mr_destructive Date: Tue, 25 Jul 2023 21:03:56 +0530 Subject: [PATCH] feat: embed links for github/twitter on devto posts --- crossposter/app.py | 39 +++++++++++------------- crossposter/publications/codenewbie.py | 19 ++++++++---- crossposter/publications/dev.py | 22 +++++++++----- crossposter/utils.py | 42 ++++++++++++++++++-------- setup.py | 2 +- 5 files changed, 74 insertions(+), 50 deletions(-) diff --git a/crossposter/app.py b/crossposter/app.py index ac82711..a9b10eb 100644 --- a/crossposter/app.py +++ b/crossposter/app.py @@ -4,13 +4,11 @@ import argparse from rich import print from pathlib import Path -from .utils import generate_file -from .publications.dev import devto +from .publications.dev import devto, generate_devto_file from .publications.codenewbie import codenewbie from .publications.hashnode import hashnode from .publications.medium import medium - def get_default_or_input(dictionary, keys): for key in keys: if key in dictionary.keys(): @@ -20,7 +18,7 @@ def get_default_or_input(dictionary, keys): def main(): print("[bold green]Crossposter[/ bold green]") - if len(sys.argv) < 2: + if len(sys.argv)<2: file_markdown = input("Enter the filename: ") else: file_markdown = sys.argv[1] @@ -35,19 +33,12 @@ def main(): continue parser = argparse.ArgumentParser() - parser.add_argument( - "Path", - metavar="path", - type=str, - nargs="?", - const=1, - default=file_markdown, - help="the path to file", - ) - parser.add_argument("--dev", action="store_true", help="Post to dev.to") - parser.add_argument("--med", action="store_true", help="Post to medium.com") - parser.add_argument("--cdb", action="store_true", help="Post to codenewbie") - parser.add_argument("--opf", action="store_true", help="Save to a File") + parser.add_argument('Path', metavar='path', type=str, nargs='?', const=1, default=file_markdown, help='the path to file') + parser.add_argument("--dev", action="store_true", help='Post to dev.to') + parser.add_argument("--med", action="store_true", help='Post to medium.com') + parser.add_argument("--cdb", action="store_true", help='Post to codenewbie') + parser.add_argument("--output-file", action="store_true", help="Save to a File") + parser.add_argument("--embeds", action="store_true", help="Enable Embeds(only for devto/codenewbie)") args = parser.parse_args() post = frontmatter.load(file_markdown) @@ -65,13 +56,14 @@ def main(): article["title"] = get_default_or_input(post, ["title"]) article["description"] = get_default_or_input(post, ["subtitle", "description"]) slug = get_default_or_input(post, ["slug", "canonical_url"]) - # while True: + #while True: # if validators.url(slug): # break # else: # slug = input("Enter a valid URL: ") - if "slug" in post: + if "slug" in post.keys(): + print(blog_link) slug = blog_link + str(slug) image_url = get_default_or_input(post, ["image_url", "cover_image"]) @@ -88,6 +80,7 @@ def main(): if "series" in post: article["series"] = post["series"] + key_file = Path("keys.txt") if not key_file.exists(): key_file.touch(exist_ok=True) @@ -100,14 +93,16 @@ def main(): lines.append("codenewbie:\n") f.writelines(lines) + + allow_embeds = args.embeds if args.dev: - devto(article, output) + devto(article, output, allow_embeds) elif args.med: medium(article, output) elif args.cdb: - codenewbie(article, output) + codenewbie(article, output, allow_embeds) elif args.opf: - generate_file(article, output) + generate_devto_file(article, output) else: print(f"1. dev.to \n2. hashnode.com\n3. codenewbie\n4. medium.com\n") opt = input("Where you would like to post? (1/2/3/4) : ") diff --git a/crossposter/publications/codenewbie.py b/crossposter/publications/codenewbie.py index aeb0294..6fe35ba 100644 --- a/crossposter/publications/codenewbie.py +++ b/crossposter/publications/codenewbie.py @@ -1,7 +1,6 @@ import requests import json -import sys -from crossposter.utils import hard_to_soft_wraps, replace_line +from crossposter.utils import hard_to_soft_wraps, replace_line, embeds def codenewbie_file(article, output): @@ -18,22 +17,22 @@ def codenewbie_file(article, output): else: codenewbie_frontmatter += f"{key}: {post[key]}\n" + lines = hard_to_soft_wraps(codenewbie_frontmatter) filename = post["title"].replace(" ", "_").lower() output_file = output / f"{filename}_codenewbie_post.md" - with open(output_file, "w") as f: + with open(output_file, 'w') as f: f.writelines(lines) print("The Codenewbie frontmatter is generated in the file -> ", output_file) return post -def codenewbie(article, output): +def codenewbie(article, output, allow_embeds=False): from rich.progress import Progress - with Progress() as progress: - task = progress.add_task("Crossposting..", total=100) + task = progress.add_task("Crossposting..", total=100) while not progress.finished: progress.update(task, advance=10) @@ -48,6 +47,7 @@ def codenewbie(article, output): codenewbie_keys = input("Enter the Codenewbie API Key: ") replace_line("keys.txt", 4, f"dev.to: {codenewbie_keys}\n") + post = codenewbie_file(article, output) post = {} @@ -55,6 +55,10 @@ def codenewbie(article, output): for key in article: post[key] = article[key] + # replace github and other embed links + if allow_embeds: + post = embeds(post) + API_ENDPOINT = "https://community.codenewbie.org/api/articles" data = { @@ -87,3 +91,6 @@ def codenewbie(article, output): print("The article URL is: ", response) else: print("Article already published") + +def generate_codenewbie_file(article, output): + codenewbie_file(article, output) diff --git a/crossposter/publications/dev.py b/crossposter/publications/dev.py index e9e3e12..d8d6a0f 100644 --- a/crossposter/publications/dev.py +++ b/crossposter/publications/dev.py @@ -1,6 +1,6 @@ import requests import json -from crossposter.utils import hard_to_soft_wraps, replace_line +from crossposter.utils import embeds, hard_to_soft_wraps, replace_line def devto_file(article, output): @@ -19,19 +19,18 @@ def devto_file(article, output): else: dev_frontmatter += f"{key}: {post[key]}\n" + filename = post["title"].replace(" ", "_").lower() output_file = output / f"{filename}_dev_post.md" - import re - lines = hard_to_soft_wraps(dev_frontmatter) - with open(output_file, "w") as f: + with open(output_file, 'w') as f: f.writelines(lines) print("The DEV frontmatter is generated in the file -> ", output_file) return post -def devto(article, output): +def devto(article, output, allow_embeds=False): post = devto_file(article, output) @@ -47,6 +46,9 @@ def devto(article, output): replace_line("keys.txt", 0, f"dev.to: {dev_keys}\n") API_ENDPOINT = "https://dev.to/api/articles" + if allow_embeds: + post = embeds(post) + data = { "Content-Type": "application/json", "article": post, @@ -70,6 +72,8 @@ def devto(article, output): flag = True # author_data = json.loads(requests.get("https://dev.to/api/users/me", headers=header).content) # author_username = author_data["username"] + + author_articles_list = json.loads( requests.get("https://dev.to/api/articles/me/published", headers=header).content ) @@ -82,12 +86,14 @@ def devto(article, output): flag = False if flag: - response = requests.post( - url=API_ENDPOINT, json=data, headers={"api-key": dev_keys} - ).json() + response = requests.post(url=API_ENDPOINT, json=data, headers={"api-key": dev_keys}).json() if "url" in response: print("The article URL is: ", response["url"]) else: print("The article URL is: ", response) else: print("Article already published") + + +def generate_devto_file(article, output): + devto_file(article, output) diff --git a/crossposter/utils.py b/crossposter/utils.py index c1a5ce8..c48450b 100644 --- a/crossposter/utils.py +++ b/crossposter/utils.py @@ -1,7 +1,4 @@ import re -from crossposter.publications.codenewbie import codenewbie_file - -from crossposter.publications.dev import devto_file def replace_line(file_name, line_num, text): @@ -12,17 +9,16 @@ def replace_line(file_name, line_num, text): f.seek(0) f.writelines(lines) - def hard_to_soft_wraps(content): - # pre= re.findall(r'\n---\n(.*?)\n```.*$', content, re.DOTALL) - # mid = re.findall(r'\n```\n(.*?)\n```(.*?)',content, re.DOTALL) - # post = re.findall(r'\n```\n\n(.*$)', content, re.DOTALL) + #pre= re.findall(r'\n---\n(.*?)\n```.*$', content, re.DOTALL) + #mid = re.findall(r'\n```\n(.*?)\n```(.*?)',content, re.DOTALL) + #post = re.findall(r'\n```\n\n(.*$)', content, re.DOTALL) # get all fenced code block - fences = re.findall(r"\n```.*?```\n", content, re.DOTALL) + fences = re.findall(r'\n```.*?```\n', content, re.DOTALL) # get the frontmatter data - frontmatter = re.findall(r"---.*?---\n", content, re.DOTALL) + frontmatter = re.findall(r'---.*?---\n', content, re.DOTALL) for fence in fences: # set the new line character as some value //r to identify later @@ -41,12 +37,32 @@ def hard_to_soft_wraps(content): for w in content: # replace the newline character which is a hard wrap into a whitespace # then replace the special character with new line character - content = w.replace("\n", " ").replace("\\r", "\n") + content = w.replace("\n", " ").replace('\\r', "\n") # returned soft wrapped content return content -def generate_file(article, output): - devto_file(article, output) - codenewbie_file(article, output) +def embeds(post): + github_regex = re.compile(r'\[([^\]]+)\]\(\s*(https?://github\.com/[^)]+)\s*\)') + twitter_regex = re.compile(r'\[([^\]]+)\]\(\s*https?://twitter\.com/([^)]+)\s*\)') + + def embed_github_replace(match): + link_text = match.group(0) + github_link = match.group(2) + embeds = f'{link_text} {{% embed {github_link} %}}' + if len(github_link.split('/')) > 5: + return link_text + return embeds + + def embed_twitter_replace(match): + link_text = match.group(0) + twitter_link = match.group(2) + embeds = f"{link_text} {{% embed https://twitter.com/{twitter_link} %}}" + return embeds + + text = github_regex.sub(embed_github_replace, post["body_markdown"]) + text = twitter_regex.sub(embed_twitter_replace, text) + + post["body_markdown"] = text + return post diff --git a/setup.py b/setup.py index 990e9c0..d9ec8fe 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ HERE = pathlib.Path(__file__).parent -VERSION = "0.5.2" +VERSION = "0.6.0" PACKAGE_NAME = "crossposter" AUTHOR = "Meet Gor" AUTHOR_EMAIL = "gormeet711@gmail.com"