-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 305f58a
Showing
4 changed files
with
298 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
name: Releases | ||
on: | ||
push: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
changelog: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- name: conventional Changelog Action | ||
id: changelog | ||
uses: TriPSs/conventional-changelog-action@v3.7.1 | ||
with: | ||
github-token: ${{ secrets.CHANGELOG_RELEASE }} | ||
|
||
- name: create release | ||
uses: actions/create-release@v1 | ||
if: ${{ steps.changelog.outputs.skipped == 'false' }} | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.CHANGELOG_RELEASE }} | ||
with: | ||
tag_name: ${{ steps.changelog.outputs.tag }} | ||
release_name: ${{ steps.changelog.outputs.tag }} | ||
body: ${{ steps.changelog.outputs.clean_changelog }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
keys.txt | ||
config.txt | ||
temp.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
## Crossposter | ||
|
||
> Crosspost your articles to dev.to/medium.com/hashnode.com from the command line | ||
Crosspost.sh is a shellscript(BASH) to automate crossposting to platforms like dev.to, medium.com and hashnode.com. The script takes in markdown version of your post with a few inputs from you and posts it to those platforms. You would require a token/key for each of those platforms to post it from the command line. | ||
|
||
The actual script is still not perfect (has a few bugs). Though it posts on `dev.to` and `medium.com` easily, the `hashnode.com` is buggy as it parses the raw markdown into the post and doesn't render as desired. So, **its a under-development script**, fell free to raise any issues or PRs on the official GitHub repo. | ||
|
||
Run the script on a bash interpreter with the command: | ||
|
||
`bash crosspost.sh` | ||
|
||
For posting the article you need to provide the following details: | ||
|
||
## Front-Matter | ||
|
||
### Meta data about the post | ||
|
||
- Title of Post | ||
- Subtitle of Post | ||
- Publish status of post(`true` or `false`) | ||
- Tags for the post (comma separated values) | ||
- Canonical Url (original url of the post) | ||
- Cover Image (URL of the post's image/thumbnail) | ||
|
||
This information is a must for `dev.to` especially the `title`. This should be provide in the same order as given below: | ||
|
||
``` | ||
--- | ||
title: The title of the post | ||
subtitle: The description of your article | ||
published: true | ||
tags: programming, anythingelse | ||
canonical url: url of your original blog | ||
cover_image: coverimage_url | ||
--- | ||
``` | ||
|
||
There is no need to enclose any of them with quotation marks. `Published` argument will be `true` if you want to publish it and `false` if you want to keep it in your Drafts. | ||
|
||
In the demonstrations, we just need to enter the tokens once. The tokens will be stored locally in the `keys.txt` file and retrieved later within the script. | ||
|
||
### Posting on **dev.to**: | ||
|
||
Posting on dev.to requires their `API key` which can be generated by going on the [Dev Community API Keys](https://dev.to/settings/account/). From there you can generate a new key with any name you like. You just need to enter the key to CLI once or manually enter in the `keys.txt` file with the format `dev.to:key` on the first line. This will be used for the future cross-posting whenever you execute the shell script(`bash crosspost.sh`) | ||
|
||
You can provide the [front matter](#front-matter) manually in your markdown file or you will be prompted for the input. So, that is all you will require for posting on dev.to from the Command line. | ||
|
||
Lets see the script in action | ||
|
||
![dev.to](https://gitlab.com/MR_DESTRUCTIVE/tblog-img/-/raw/main/devto.gif) | ||
|
||
If you want to add in more stuff to the post, you can check out the [DEV.to API docs](https://developers.forem.com/api#operation/createArticle) which is powered by [Forem](https://www.forem.com/), there a ton of options you can hook to the front-matter in the shellscript. | ||
|
||
**NOTE: There is a limit of 10 requests per 30 seconds, so keep in mind while testing the script and don't try to spam** | ||
|
||
### Posting on **hashnode.com**: | ||
|
||
This part is still under development as it only displays the raw markdown in the post, also the `tags` are too heavy to implement from the API as `id` of every tag is required along with the `slug` and `name`. Still it serves some purpose at least. For posting on `hashnode.com`, we need `Personal Access Token`. This can be generated by going to [Developer Settings](https://hashnode.com/settings/developer). You will also require the user-id of your `hashnode` account. You can get your user-id/username from the [settings](https://hashnode.com/settings) tab under profile information. We require Username for posting to the Publication Blog if any. As usual, the `Personal Access Token` for interacting with the [Hashnodes' GraphQL API](https://api.hashnode.com/). The API is quite user friendly and provides everything in one place. There are docs for running each and every `query` and `mutations` present in the API. | ||
|
||
You can paste the token when prompted from the script or manually type in the `keys.txt` text file as `hashnode:token` on the 4th line. Yes, that should be on the `4th` line, thats make retrieving much more easier and safe. Next also input in the `username` when the script asks for the input or again type in on the `5th` line, `hashnode_id:username` in the text file `keys.txt`. Please enter the credentials from the script prompt so as to avoid errors and misconfigurations when doing manually | ||
|
||
This will create the Post on hashnode with the title, subtitle, cover image correctly but will mess up the content. I tried hard but its just not happening. There needs to be some character for newline as the API rejects the `rn` characters passed in, so I have substited them with `br` and the result is raw markdown. **As the Hashnode API is still under development and they are bringing changes and new features in, the API should improve in its core functionality and make it much easier for creating some common queries**. So, I'll create issue on GitHub for posting the actual content via the script. | ||
|
||
So, this is the demonstration of posting on hashnode. | ||
|
||
[hashnode](https://gitlab.com/MR_DESTRUCTIVE/tblog-img/-/raw/main/hashnode.gif) | ||
|
||
### Posting on **medium.com**: | ||
|
||
Medium API is much more versatile and markdown friendly, though it has some limitation on the number of posts you can make in a day. For posting on `Medium.com`, we will require the `Integration Token` which can be generated on the [settings tab](https://medium.com/me/settings). As similar to `hashnode`, you can name the token whatever you like and then get the token. Paste the token when prompted from the script or manually type in the `keys.txt` text file as `medium:token` on the `2nd` line. We also require the Medium_id, but we can get that from the token itself, so inside the script once the token is obtained, the curl command is executed to fetch in the `id` and it is stored on the next(`3rd`) line in the `keys.txt` file for actually posting on `medium.com`. So that is all the configuration you need for posting on `medium.com`. | ||
|
||
There is some documentation on [Medium API](https://github.com/Medium/medium-api-docs), we can even post to a Publication, that shall be created in future. Also the cover images can be posted on medium, it is not currently done but that can again be a #TODO. **The tags are not rendered on Medium yet with the script.** The way we can parse strings is limited in BASH, so this might still be a doable thing later. Most of the checkboxes are ticked like title, subtitle, cover-image, canonical url, and importantly the content. | ||
|
||
Let's look at post on medium from the script. | ||
|
||
[medium](https://gitlab.com/MR_DESTRUCTIVE/tblog-img/-/raw/main/medium.gif) | ||
|
||
### All platforms: | ||
|
||
Now, once you have configured every thing, you can opt for the `4` choice that is post on all platforms(dev.to, hashnode and medium), but as hashnode is not looking a good option right now, so there is the `5` option for only `dev.to` and `medium`. | ||
|
||
[all-platforms](https://gitlab.com/MR_DESTRUCTIVE/tblog-img/-/raw/main/crossposter.gif) | ||
|
||
## Contributions | ||
|
||
This is not a perfect script and has a lot of bugs due to encoding the markdown in BASH. It is subject to improve over time as I get to understand more string manipulation in BASH and render the post as expected. Please feel free to open up a genuine and smallest of issues. | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
#!/usr/bin/env bash | ||
|
||
function dev() | ||
{ | ||
if [[ -z $(sed -n -e 's/.*dev.to://p' $keys) ]];then | ||
read -p "Enter the dev.to API key : " dev_key | ||
sed -i "/dev.to:/ s/$/$dev_key/" $keys | ||
fi | ||
curl -s -X POST -H "Content-Type: application/json" \ | ||
-H "api-key: $dev_key" -d "{\"article\":{\"body_markdown\":\"$body\"}}" \ | ||
https://dev.to/api/articles | ||
|
||
if [[ $? ]];then | ||
echo -e "\nPosted on dev.to\n" | ||
else | ||
echo -e "Error...\nFailed to post on dev.to" | ||
fi | ||
} | ||
|
||
function hashnode() | ||
{ | ||
if [[ -z $(sed -n -e 's/.*hashnode://p' $keys ) ]]; then | ||
read -p "Enter the hashnode.com token : " hashtoken | ||
sed -i "/hashnode:/ s/$/$hashtoken/" $keys | ||
fi | ||
|
||
if [[ -z $(sed -n -e 's/.*node_id://p' $keys ) ]]; then | ||
read -p "Enter the hashnode username : " hash_uname | ||
curl -s 'https://api.hashnode.com/' -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Connection: keep-alive' -H 'DNT: 1' -H 'Origin: https://api.hashnode.com' -H 'Authorization: \"'"$hash_token"'\"' --data-binary '{"query":"query user {\n user(username: \"'"$hash_uname"'\") {\n publication {\n _id\n }\n }\n}\n"}' --compressed >temp.json | ||
hash_id=$(grep -o -P '(?<=id":").*(?=")' temp.json) | ||
sed -i "/hashnode_id:/ s/$/$hash_id/" $keys | ||
fi | ||
|
||
|
||
|
||
awk '{print $0"\\r\\n"}' temp.txt >temp.md | ||
cat temp.md | tr -d '\r\n' | sed 's/\\r\\n/<br>/g' >body.md | ||
body=$(cat body.md) | ||
|
||
# comment out the below two lines for non-publication posts | ||
#curl 'https://api.hashnode.com/' -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/json' -H 'Accept: application/json'\ | ||
# -H 'Connection: keep-alive' -H 'DNT: 1' -H 'Origin: https://api.hashnode.com' -H 'Authorization: '$hash_token'' --data-binary '{"query":"mutation {\n createStory(\n input: {\n title: \"'"$title"'\",\n contentMarkdown: \"'"$body"'\"\n tags: [\n {\n _id: \"56744721958ef13879b94ff1\",\n name: \"General Programming\",\n slug: \"programming\"\n }\n ]\n }\n ) {\n message\n post{\n title\n }\n }\n}\n\n "}' --compressed | ||
|
||
curl -s 'https://api.hashnode.com/' -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/json' -H 'Accept: application/json'\ | ||
-H 'Connection: keep-alive' -H 'DNT: 1' -H 'Origin: https://api.hashnode.com' -H 'Authorization: '$hashtoken'' --data-binary '{"query":"mutation {\n createPublicationStory(\n input: {\n title: \"'"$title"'\",\n contentMarkdown: \"'"$body"'\"\n tags: [\n {\n _id: \"56744721958ef13879b94ffc\",\n name: \"General Programming\",\n slug: \"programming\"\n }\n ]\n coverImageURL:\"'"$cover_image"'\" }\n publicationId:\"'"$hash_id"'\",\n hideFromHashnodeFeed:false\n ) {\n message\n post{\n title\ncoverImage\n }\n }\n}\n"}' --compressed | ||
|
||
if [[ $? ]];then | ||
echo -e "\nPosted on hashnode.com\n" | ||
else | ||
echo -e "Error...\nFailed to post on hashnode.com" | ||
fi | ||
} | ||
|
||
function medium() | ||
{ | ||
if [[ -z $(sed -n -e 's/.*ium://p' $keys ) ]]; then | ||
read -p "Enter the medium.com API token : " med_token | ||
med_id=$(curl -s -H "Authorization: Bearer $med_token" https://api.medium.com/v1/me | json_pp >temp.json) | ||
med_id=$(grep -o -P '(?<=id).*(?=,)' temp.json ) | ||
med_id=$(echo ${med_id:3} | tr -d '"') | ||
sed -i "/medium:/ s/$/$med_token/" $keys | ||
sed -i "/medium_id:/ s/$/$med_id/" $keys | ||
fi | ||
|
||
tags=$(echo $tags | sed "s/ //g") | ||
tags=$(echo $tags | sed "s/,/','/g" | sed "s/$/'/" | sed "s/^/'/" | sed "s/\b\(.\)/\u\1/g") | ||
if [[ $statusp = "true" ]];then | ||
mstatus="public" | ||
else | ||
mstatus="draft" | ||
fi | ||
sed -i "1a # $title" temp.txt | ||
sed -i "1a ![]($cover_image)" temp.txt | ||
sed -i "2a ## $subtitle" temp.txt | ||
|
||
|
||
awk '{print $0"\\r\\n"}' temp.txt >temp.md | ||
cat temp.md | tr -d '\r\n' > body.md | ||
body=$(cat body.md) | ||
|
||
curl -s -H "Authorization: Bearer $med_token " -H "Content-Type: application/json" \ | ||
-H "Accept: application/json" -H "Accept-Charset: utf-8" --request "POST" \ | ||
-d '{ "title": "'"$title"'", "contentFormat": "markdown", "content": "'"$body"'", "canonicalUrl": "'"$canonical_url"'", "tags": ["'"$tags"'"],"publishStatus": "'"$mstatus"'" }'\ | ||
"https://api.medium.com/v1/users/$med_id/posts" | ||
|
||
if [[ $? ]];then | ||
echo -e "\nPosted on medium.com\n" | ||
else | ||
echo -e "Error...\nFailed to post on medium.com" | ||
fi | ||
} | ||
|
||
|
||
touch keys.txt body.md temp.md temp.txt | ||
keys=keys.txt | ||
|
||
if [[ ! -s $keys ]];then | ||
head -n 1 $keys | echo "dev.to:" >$keys | ||
sed -i "1a medium:" $keys | ||
sed -i "2a medium_id:" $keys | ||
sed -i "3a hashnode:" $keys | ||
sed -i "4a hashnode_id:" $keys | ||
else | ||
dev_key=$(sed -n -e 's/dev.to://p' $keys) | ||
med_token=$(sed -n -e 's/medium://p' $keys) | ||
med_id=$(sed -n -e 's/medium_id://p' $keys) | ||
hashtoken=$(sed -n -e 's/hashnode://p' $keys) | ||
hash_id=$(sed -n -e 's/hashnode_id://p' $keys) | ||
fi | ||
|
||
read -p "Enter the name of the file : " file | ||
|
||
if [[ -z $(sed '/^---/p;q' $file) ]];then | ||
read -p "Enter the title of your post : " title | ||
read -p "Enter the subtitle of your post : " subtitle | ||
read -p "Enter the status of your post(true/false) : " statusp | ||
read -p "Enter the tags for your post : " tags | ||
read -p "Enter the canonical url of the post : " canonical_url | ||
read -p "Enter the cover_image url of the post : " cover_image | ||
|
||
sed -i "1i ---" $file | ||
sed -i "1a title: $title" $file | ||
sed -i "2a subtitle: $subtitle" $file | ||
sed -i "3a published: $statusp" $file | ||
sed -i "4a tags: $tags" $file | ||
sed -i "5a canonical_url: $canonical_url" $file | ||
sed -i "6a cover_image: $cover_image" $file | ||
sed -i "7a ---" $file | ||
fi | ||
|
||
title=$(sed -n '2 s/^[^=]*title: *//p' $file) | ||
subtitle=$(sed -n '3 s/^[^=]*subtitle: *//p' $file) | ||
tags=$(sed -n '5 s/^[^=]*tags: *//p' $file) | ||
canonical_url=$(sed -n '6 s/^[^=]*url: *//p' $file) | ||
cover_image=$(sed -n '7 s/^[^=]*age: *//p' $file) | ||
|
||
cat $file | sed '1,10{/^---/!{/^\---/!d}}' | sed '1,2d' >temp.txt | ||
awk '{print $0"\\r\\n"}' $file >temp.md | ||
cat temp.md | tr -d '\r\n' > body.md | ||
body=$(cat body.md) | ||
|
||
|
||
echo -e "\n1. dev.to \n" | ||
echo -e "2. hashnode.com \n" | ||
echo -e "3. medium.com \n" | ||
echo -e "4. All of the above\n" | ||
echo -e "5. dev.to and medium\n" | ||
|
||
read -p "Where you want to cross post to? " num | ||
|
||
if [[ $num -eq 1 ]];then | ||
|
||
dev | ||
|
||
elif [[ $num -eq 2 ]];then | ||
|
||
hashnode | ||
|
||
elif [[ $num -eq 3 ]];then | ||
|
||
medium | ||
|
||
elif [[ $num -eq 4 ]];then | ||
|
||
dev | ||
hashnode | ||
medium | ||
|
||
elif [[ $num -eq 5 ]];then | ||
|
||
dev | ||
medium | ||
|
||
else | ||
echo "Invalid Input" | ||
fi | ||
|
||
rm temp.md temp.txt body.md |