{"id":14070344,"url":"https://github.com/maximegel/blogster","last_synced_at":"2025-07-30T07:31:26.041Z","repository":{"id":144175552,"uuid":"315426043","full_name":"maximegel/blogster","owner":"maximegel","description":"Crosspost to Medium and Dev.to automagically from the CLI","archived":false,"fork":false,"pushed_at":"2020-12-21T20:45:31.000Z","size":739,"stargazers_count":10,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-08-13T07:17:45.402Z","etag":null,"topics":["blog","cli","crosspost","devto","medium"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maximegel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-23T19:57:29.000Z","updated_at":"2024-07-10T12:07:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"28870ff6-06bd-46a7-9151-22e91b8e6604","html_url":"https://github.com/maximegel/blogster","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maximegel%2Fblogster","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maximegel%2Fblogster/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maximegel%2Fblogster/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maximegel%2Fblogster/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maximegel","download_url":"https://codeload.github.com/maximegel/blogster/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228102712,"owners_count":17869907,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blog","cli","crosspost","devto","medium"],"created_at":"2024-08-13T07:07:40.757Z","updated_at":"2024-12-04T11:31:40.001Z","avatar_url":"https://github.com/maximegel.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"![Blogster Banner](https://raw.githubusercontent.com/maximegel/blogster/master/assets/banner.png)\n\n\u003ch2 align=\"center\"\u003eCrosspost to Medium and Dev.to automagically from the CLI\u003c/h2\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/maximegel/blogster/actions?query=workflow%3Abuild\"\u003e\n    \u003cimg alt=\"build status\" src=\"https://img.shields.io/github/workflow/status/maximegel/blogster/build/master?style=flat-square\u0026logo=github\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/@blogster/cli\"\u003e\n    \u003cimg alt=\"npm version\" src=\"https://img.shields.io/npm/v/@blogster/cli?style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/@blogster/cli\"\u003e\n    \u003cimg alt=\"downloads\" src=\"https://img.shields.io/npm/dm/@blogster/cli?style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/semantic-release/semantic-release\"\u003e\n    \u003cimg alt=\"semantic-release\" src=\"https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"http://commitizen.github.io/cz-cli\"\u003e\n    \u003cimg alt=\"Commitizen friendly\" src=\"https://img.shields.io/badge/commitizen-friendly-brightgreen.svg?style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://lerna.js.org\"\u003e\n    \u003cimg alt=\"maintained with Lerna\" src=\"https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg?style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/prettier/prettier\"\u003e\n    \u003cimg alt=\"prettier code style\" src=\"https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n## Introduction\n\nBlogster is an extendable CLI tool allowing you to your write blog posts once in Markdown and then publish them on\nmultiple platforms in a single command.\n\n### Highlights\n\n- Posts written in [Markdown](https://commonmark.org/help/)\n- Crosspost to [Medium][medium] and [Dev.to][devto]\n- Automatic conversion between inline code blocks and embedded gists\n- Changes visualization between local and published posts\n\n## Installation\n\nInstall via `npm`:\n\n```bash\nnpm install @blogster/cli --save-dev\n```\n\nBlogster also requires [Prettier][prettier] as a peer dependency to format published posts\nand perform proper changes detection:\n\n```bash\nnpm install prettier --save-dev\n```\n\nThen, since Blogster is useless without plugins, you have to install some of them too:\n\n| Plugins                                     |                                                      |\n| :------------------------------------------ | ---------------------------------------------------- |\n| [@blogster/plugin-devto][devto-plugin-gh]   | [![npm][devto-plugin-npm-badge]][devto-plugin-npm]   |\n| [@blogster/plugin-medium][medium-plugin-gh] | [![npm][medium-plugin-npm-badge]][medium-plugin-npm] |\n\n## Getting started\n\nAssuming you’ve successfully [installed the Blogster CLI](#installation) you are now ready to write and publish your\nfirst post.\n\nIn this example, we will configure Blogster to publish to both [Medium][medium] and [Dev.to][devto] so make sure\n[@blogster/plugin-devto][devto-plugin-gh] and [@blogster/plugin-medium][medium-plugin-gh] are installed too.\n\n### Step 1: Add a post file\n\nFirst, let's create a new Markdown file for our post. In our case, this new file will be added under\n`posts/sample-post/post.md`, but it can be everywhere you want.\n\nNow, open up your favorite IDE and some content to our `post.md` file:\n\n```markdown\n---\ntitle: My First Post\ndescription:\ncoverImage: https://unsplash.com/photos/ualbj7tyJH0\ntags:\n  - blogster\n  - first-post\n  - so-excited\n---\n\n## Hi there!\n\nThis is my first post published with [Blogster](https://github.com/maximegel/blogster)! 🎉\n```\n\nNoticed the [YAML front matter](https://jekyllrb.com/docs/front-matter) separated by `---` at the top? Blogster\nuse this metadata to track and publish your posts. For now, the only options available are those above.\n\n\u003e _Warning:_  \n\u003e Blogster uses the `title` metadata to match your local posts with your published posts, so make sure the title used in\n\u003e your post file is the same for all of your published posts\n\n### Step 2: Add a configuration file\n\nAdd a `.blogsterrc.json` file at the root of your project and add the locations of your post files as well as the\ninstalled plugins:\n\n```json\n{\n  \"plugins\": [\"@blogster/plugin-devto\", \"@blogster/plugin-medium\"],\n  \"include\": [\"posts/**/post.md\"]\n}\n```\n\nFor all available options see the [configuration](#configuration).\n\n### Step 3: Set environment variables\n\nBecause we are using [@blogster/plugin-devto][devto-plugin-gh] and [@blogster/plugin-medium][medium-plugin-gh]\nwe need some tokens/keys to be set as environment variables.\n\nTo obtain them, please follow these steps:\n\n- [Generate a Medium access token](https://github.com/Medium/medium-api-docs#21-self-issued-access-tokens)\n- [Generate a Dev.to API key](https://docs.dev.to/api/#getting-an-api-key)\n- [Generate a GitHub personal access token](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token)\n\n\u003e _Info_: The GitHub token is used to replace code blocks by embeded Gists while publishing to Medium.\n\nOnce you did this, create a `.env` file at the root of your project and add your previously generated tokens/keys:\n\n```text\nBLOGSTER_MEDIUM_TOKEN=\"YOUR SECRET TOKEN\"\nBLOGSTER_DEVTO_API_KEY=\"YOUR SECRET KEY\"\nBLOGSTER_GH_TOKEN=\"YOUR SECRET TOKEN\"\n```\n\n\u003e _Danger_: **Do not commit your `.env` file!**\n\n### Step 4: Publish your post\n\nCongrats! The only things left his to publish our post and it is sample as:\n\n```bash\nnpx bgs push\n```\n\n\u003e _Info:_ Posts will be published as draft so you can review them before really publishing them.\n\n## Command line\n\nTo run a command, you’ll need to prefix each command in order to properly locate the executable:\n\n```bash\n./node_modules/.bin/bgs [options] [command]\n```\n\nOr you can use npx (requires [npm@5.2.0](https://www.npmjs.com/package/npm/v/5.2.0) or greater):\n\n```bash\nnpx bgs [options] [command]\n```\n\n### `bgs diff`\n\nOutputs changes between post files and published posts in diff format.\n\n```bash\nbgs diff [options] [file/dir/glob...]\n```\n\n| Arguments            |                                                         |\n| -------------------- | ------------------------------------------------------- |\n| `[file/dir/glob...]` | Globs of post files to include e.g. `posts/**/post.md`. |\n\n| Options                   |                                                                                                                                                                                    |\n| :------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `--p --platforms \u003cnames\u003e` | List of platforms to include e.g. `dev.to, medium`. When none, all platforms are included. See the documentation of your configured plugins to know which platforms are available. |\n\n### `bgs push`\n\nPublishes or updates posts. Posts will be published as draft so you can review them before really publishing them.\n\n```bash\nbgs push [options] [file/dir/glob...]\n```\n\n| Arguments            |                                                         |\n| :------------------- | ------------------------------------------------------- |\n| `[file/dir/glob...]` | Globs of post files to include e.g. `posts/**/post.md`. |\n\n| Options                   |                                                                                                                                                                                    |\n| :------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `--p --platforms \u003cnames\u003e` | List of platforms to include e.g. `dev.to, medium`. When none, all platforms are included. See the documentation of your configured plugins to know which platforms are available. |\n\n### `bgs status`\n\nOutputs the status of each post i.e. \"unpublished\", \"synced\" or \"desynced\".\n\n```bash\nbgs status [options] [file/dir/glob...]\n```\n\n| Arguments            |                                                         |\n| :------------------- | ------------------------------------------------------- |\n| `[file/dir/glob...]` | Globs of post files to include e.g. `posts/**/post.md`. |\n\n| Options                   |                                                                                                                                                                                    |\n| :------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `--p --platforms \u003cnames\u003e` | List of platforms to include e.g. `dev.to, medium`. When none, all platforms are included. See the documentation of your configured plugins to know which platforms are available. |\n\n## Configuration\n\nThe default behavior of Blogster can be modified by supplying any of the configuration options:\n\n| Option    | Default | Description                                                                              |\n| --------- | ------- | ---------------------------------------------------------------------------------------- |\n| `plugins` | `[]`    | A list of plugin names e.g. `@blogster/plugin-medium`                                    |\n| `env`     | `[]`    | Any values to be set as environment variables                                            |\n| `include` | `[]`    | A list of filenames or patterns to include in tracked blog posts e.g. `posts/**/post.md` |\n| `exclude` | `[]`    | A list of filenames or patterns to exclude from tracked blog posts                       |\n\nThanks to [Cosmiconfig](https://github.com/davidtheclark/cosmiconfig), the configuration can be loaded from\neither of the following places:\n\n- a `blogster` property in package.json\n- a `.blogsterrc` file in JSON or YAML format\n- a `.blogsterrc.json`, `.blogsterrc.yaml`, `.blogsterrc.yml`, `.blogsterrc.js`, or `.blogsterrc.cjs` file\n- a `blogster.config.js` or `blogster.config.cjs` CommonJS module exporting an object\n\n## Environment variables\n\nEnvironment variables are used by plugins to load extra configuration required by them.\n\nSee the documentation of your configured plugins to know which environment variables need to be set.\n\nThere are different ways to set environment variables. Each has a slightly different use case.\n\n### Option 1: configuration file\n\nAny key/value you set in your configuration file (e.g. `.blogsterrc.json`) under the `env` key will become an\nenvironment variable:\n\n```json\n\"env\": {\n  \"myBlogUrl\": \"https://my-blog.com\"\n}\n```\n\n### Option 2: `BLOGSTER_*`\n\nAny OS-level environment variable on your machine that starts with either `BLOGSTER_` or `blogster_` will automatically\nbe added to environment variables.\n\nBlogster will strip off the `BLOGSTER_` and convert the remaining part to camel-case when adding your environment\nvariables.\n\n### Option 3: dotenv\n\nThanks to [dotenv](https://github.com/motdotla/dotenv), Blogster will loads environment variables from a `.env` file as\nif they were native environment variables (see: [option 2](#option-2-blogster)).\n\nCreate a `.env` file in the root directory of your project. Add environment-specific variables on new lines in the form\nof `NAME=VALUE`. For example:\n\n```text\nBLOGSTER_MY_BLOG_URL=\"https://my-blog.com\"\n```\n\n## Tooling\n\nThe best part about writing posts in Markdown is that there are a variety of tools available. Here is some you might\nlike:\n\n### Prettier\n\nUse [Prettier][prettier] to format your Mardown files. We recommend you to create a `.prettierrc` file under the\ndirectory containing your post files and add those options:\n\n```json\n{\n  \"printWidth\": 120,\n  \"proseWrap\": \"always\"\n}\n```\n\n### Markdownlint\n\nUse [Markdownlint](https://github.com/DavidAnson/markdownlint) to enforce rules in your Markdown files. We recommend you\nto create a `.markdownlintrc` file under the directory containing your post files and add those rule\noptions:\n\n```json\n{\n  \"line-length\": { \"line_length\": 120 },\n  \"no-trailing-punctuation\": { \"punctuation\": \".,;:!。，；：！？\" },\n  \"first-line-heading\": { \"level\": 2 }\n}\n```\n\n### Visual Studio Code\n\nHere is some [Visual Studio Code](https://code.visualstudio.com) handy extensions:\n\n- [Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)\n- [markdownlint](https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint)\n- [Read Time](https://marketplace.visualstudio.com/items?itemName=johnpapa.read-time) by John Papa to estimate your\n  posts read time.\n- [:emojisense:](https://marketplace.visualstudio.com/items?itemName=bierner.emojisense) for addind emojis to your posts.\n\n## Example\n\nTake a look a this [repository](https://github.com/maximegel/maximegel.github.io) for a real world example on how to use\nBlogster.\n\n## Known issues\n\n- As this time, [Medium API](https://github.com/Medium/medium-api-docs) still do not support updating posts. Until then,\n  the easiest way is to use the `diff` command and make changes manually.\n\n\u003c!-- References: --\u003e\n\n[devto]: https://dev.to/\n[devto-plugin-gh]: https://github.com/maximegel/blogster/tree/master/packages/plugin-devto\n[devto-plugin-npm]: https://www.npmjs.com/package/@blogster/plugin-devto\n[devto-plugin-npm-badge]: https://img.shields.io/npm/v/@blogster/plugin-devto?style=flat-square\n[medium]: https://medium.com\n[medium-plugin-gh]: https://github.com/maximegel/blogster/tree/master/packages/plugin-medium\n[medium-plugin-npm]: https://www.npmjs.com/package/@blogster/plugin-medium\n[medium-plugin-npm-badge]: https://img.shields.io/npm/v/@blogster/plugin-medium?style=flat-square\n[prettier]: https://github.com/prettier/prettier\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaximegel%2Fblogster","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaximegel%2Fblogster","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaximegel%2Fblogster/lists"}