diff --git a/.github/workflows/Gmeek.yml b/.github/workflows/Gmeek.yml new file mode 100644 index 0000000..f4d92a5 --- /dev/null +++ b/.github/workflows/Gmeek.yml @@ -0,0 +1,53 @@ +name: build Gmeek + +on: + workflow_dispatch: + issues: + types: [opened, edited] + +env: + GITHUB_NAME: Meekdai + GITHUB_EMAIL: meekdai@163.com + +jobs: + sync: + name: Generate blog + runs-on: ubuntu-20.04 + if: github.event.repository.owner.id == github.event.sender.id + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: 3.8 + + - name: Configure pip cache + uses: actions/cache@v1 + id: pip-cache + with: + path: venv + key: pip-1-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + pip- + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m venv venv + source venv/bin/activate + pip install -r requirements.txt + if: steps.pip-cache.outputs.cache-hit != 'true' + + - name: Generate new html + run: | + source venv/bin/activate + python Gmeek.py ${{ secrets.meblog }} ${{ github.repository }} --issue_number '${{ github.event.issue.number }}' + + - name: update html + run: | + git config --local user.email "${{ env.GITHUB_EMAIL }}" + git config --local user.name "${{ env.GITHUB_NAME }}" + git add . + git commit -a -m '🎉auto update by action' || echo "nothing to commit" + git push || echo "nothing to push" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2d531a0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +__pycache__ +nohup.out +.git-credentials +venv/ diff --git a/Gmeek.py b/Gmeek.py new file mode 100644 index 0000000..ee48037 --- /dev/null +++ b/Gmeek.py @@ -0,0 +1,169 @@ +# -*- coding: utf-8 -*- +import os +import json +import time +import datetime +import shutil +import requests +import argparse +from github import Github +from xpinyin import Pinyin + +###################################################################################### +class GMEEK(): + def __init__(self,options): + self.options=options + self.config=json.loads(open('config.json', 'r', encoding='utf-8').read()) + + self.root_dir='docs/' + self.post_folder='post/' + self.post_dir=self.root_dir+self.post_folder + + self.plist_example=open('plist_example.html', 'r', encoding='utf-8').read() + self.post_example=open('post_example.html', 'r', encoding='utf-8').read() + + user = Github(self.options.github_token) + self.repo = self.get_repo(user, options.repo_name) + + self.labelColorDict=json.loads('{}') + for label in self.repo.get_labels(): + self.labelColorDict[label.name]='#'+label.color + + print(self.labelColorDict) + + self.blogBase=self.config.copy() + self.blogBase["postListJson"]=json.loads('{}') + + def cleanFile(self): + if os.path.exists("backup/"): + shutil.rmtree("backup/") + + if os.path.exists(self.post_dir): + shutil.rmtree(self.post_dir) + + os.mkdir("backup/") + os.mkdir(self.post_dir) + + + def get_repo(self,user: Github, repo: str): + return user.get_repo(repo) + + def markdown2html(self,mdstr): + payload = {"text": mdstr, "mode": "markdown"} + ret=requests.post("https://api.github.com/markdown", json=payload,headers={"Authorzation":"token {}".format(self.options.github_token)}) + if ret.status_code==200: + return ret.text + else: + raise Exception("markdown2html error status_code=%d"%(ret.status_code)) + + def createPostHtml(self,issue): + if issue["label"] in self.blogBase["singlePage"]: + gen_Html = 'docs/{}.html'.format(issue["label"]) + else: + gen_Html = self.post_dir+'{}.html'.format(Pinyin().get_pinyin(issue["postTitle"])) + + f = open("backup/"+issue["postTitle"]+".md", 'r', encoding='UTF-8') + post_body=self.markdown2html(f.read()) + f.close() + + postBase=json.loads('{}') + postBase["postTitle"]=issue["postTitle"] + postBase["postBody"]=post_body + postBase["title"]=self.blogBase["title"] + postBase["homeUrl"]=self.blogBase["homeUrl"] + postBase["postSourceUrl"]=issue["postSourceUrl"] + postBase["faviconUrl"]=self.blogBase["faviconUrl"] + postBase["filingNum"]=self.blogBase["filingNum"] + postBase["startSite"]=self.blogBase["startSite"] + postBase["commentNum"]=issue["commentNum"] + postBase["repoName"]=options.repo_name + + f = open(gen_Html, 'w', encoding='UTF-8') + f.write(self.post_example % json.dumps(postBase)) + f.close() + print("create postPage title=%s file=%s " % (issue["postTitle"],gen_Html)) + + def creatPlistHtml(self): + self.blogBase["postListJson"]=dict(sorted(self.blogBase["postListJson"].items(),key=lambda x:x[1]["createdAt"],reverse=True))#使列表由时间排序 + + f = open(self.root_dir+"index.html", 'w', encoding='UTF-8') + f.write(self.plist_example % json.dumps(self.blogBase)) + f.close() + print("create docs/index.html") + + def addOnePostJson(self,issue): + if len(issue.labels)==1: + postNum="P"+str(issue.number) + self.blogBase["postListJson"][postNum]=json.loads('{}') + self.blogBase["postListJson"][postNum]["label"]=issue.labels[0].name + self.blogBase["postListJson"][postNum]["labelColor"]=self.labelColorDict[issue.labels[0].name] + self.blogBase["postListJson"][postNum]["postTitle"]=issue.title + self.blogBase["postListJson"][postNum]["postUrl"]=self.post_folder+'{}.html'.format(Pinyin().get_pinyin(issue.title)) + self.blogBase["postListJson"][postNum]["postSourceUrl"]="https://github.com/"+options.repo_name+"/issues/"+str(issue.number) + self.blogBase["postListJson"][postNum]["commentNum"]=issue.get_comments().totalCount + + try: + modifyTime=json.loads(issue.body.split("\r\n")[-1:][0].split("##")[1]) + self.blogBase["postListJson"][postNum]["createdAt"]=modifyTime["timestamp"] + except: + self.blogBase["postListJson"][postNum]["createdAt"]=int(time.mktime(issue.created_at.timetuple())) + + thisYear=datetime.datetime.fromtimestamp(self.blogBase["postListJson"][postNum]["createdAt"]).year + self.blogBase["postListJson"][postNum]["dateLabelColor"]=self.blogBase["yearColorList"][int(thisYear)%len(self.blogBase["yearColorList"])] + + f = open("backup/"+issue.title+".md", 'w', encoding='UTF-8') + f.write(issue.body) + f.close() + + def runAll(self): + print("====== start create static html ======") + self.cleanFile() + + issues=self.repo.get_issues() + for issue in issues: + self.addOnePostJson(issue) + + for issue in self.blogBase["postListJson"].values(): + self.createPostHtml(issue) + + self.creatPlistHtml() + print("====== create static html end ======") + + def runOne(self,number_str): + print("====== start create static html ======") + issue=self.repo.get_issue(int(number_str)) + self.addOnePostJson(issue) + self.createPostHtml(self.blogBase["postListJson"]["P"+number_str]) + self.creatPlistHtml() + print("====== create static html end ======") + +###################################################################################### + +parser = argparse.ArgumentParser() +parser.add_argument("github_token", help="github_token") +parser.add_argument("repo_name", help="repo_name") +parser.add_argument("--issue_number", help="issue_number", default=0, required=False) +options = parser.parse_args() + +blog=GMEEK(options) + +if not os.path.exists("blogBase.json"): + print("blogBase is not exists, runAll") + blog.runAll() +else: + if options.issue_number=="0" or options.issue_number=="": + print("issue_number=='0', runAll") + blog.runAll() + else: + f=open("blogBase.json","r") + print("blogBase is exists and issue_number!=0, runOne") + blog.blogBase=json.loads(f.read()) + f.close() + blog.runOne(options.issue_number) + +listFile=open("blogBase.json","w") +listFile.write(json.dumps(blog.blogBase)) +listFile.close() + + +###################################################################################### \ No newline at end of file diff --git a/config.json b/config.json new file mode 100644 index 0000000..0774c44 --- /dev/null +++ b/config.json @@ -0,0 +1,12 @@ +{ + "title":"Meekdai", + "subTitle":"童话是一种生活态度,仅此而已。", + "homeUrl":"http://blog.meekdai.com", + "avatarUrl":"http://meekdai.com/avatar.jpg", + "faviconUrl":"http://meekdai.com/favicon.ico", + "startSite":"02/16/2015", + "filingNum":"浙ICP备20023628号", + "singlePage":["link","about"], + "commentLabelColor":"#006b75", + "yearColorList":["#bc4c00", "#0969da", "#1f883d", "#A333D0"] +} diff --git a/docs/static/github-light.css b/docs/static/github-light.css new file mode 100644 index 0000000..0066210 --- /dev/null +++ b/docs/static/github-light.css @@ -0,0 +1,129 @@ +/*! + * GitHub Light v0.5.0 + * Copyright (c) 2012 - 2017 GitHub, Inc. + * Licensed under MIT (https://github.com/primer/github-syntax-theme-generator/blob/master/LICENSE) + */ + + .pl-c /* comment, punctuation.definition.comment, string.comment */ { + color: #6a737d; + } + + .pl-c1 /* constant, entity.name.constant, variable.other.constant, variable.language, support, meta.property-name, support.constant, support.variable, meta.module-reference, markup.raw, meta.diff.header, meta.output */, + .pl-s .pl-v /* string variable */ { + color: #005cc5; + } + + .pl-e /* entity */, + .pl-en /* entity.name */ { + color: #6f42c1; + } + + .pl-smi /* variable.parameter.function, storage.modifier.package, storage.modifier.import, storage.type.java, variable.other */, + .pl-s .pl-s1 /* string source */ { + color: #24292e; + } + + .pl-ent /* entity.name.tag, markup.quote */ { + color: #22863a; + } + + .pl-k /* keyword, storage, storage.type */ { + color: #d73a49; + } + + .pl-s /* string */, + .pl-pds /* punctuation.definition.string, source.regexp, string.regexp.character-class */, + .pl-s .pl-pse .pl-s1 /* string punctuation.section.embedded source */, + .pl-sr /* string.regexp */, + .pl-sr .pl-cce /* string.regexp constant.character.escape */, + .pl-sr .pl-sre /* string.regexp source.ruby.embedded */, + .pl-sr .pl-sra /* string.regexp string.regexp.arbitrary-repitition */ { + color: #032f62; + } + + .pl-v /* variable */, + .pl-smw /* sublimelinter.mark.warning */ { + color: #e36209; + } + + .pl-bu /* invalid.broken, invalid.deprecated, invalid.unimplemented, message.error, brackethighlighter.unmatched, sublimelinter.mark.error */ { + color: #b31d28; + } + + .pl-ii /* invalid.illegal */ { + color: #fafbfc; + background-color: #b31d28; + } + + .pl-c2 /* carriage-return */ { + color: #fafbfc; + background-color: #d73a49; + } + + .pl-c2::before /* carriage-return */ { + content: "^M"; + } + + .pl-sr .pl-cce /* string.regexp constant.character.escape */ { + font-weight: bold; + color: #22863a; + } + + .pl-ml /* markup.list */ { + color: #735c0f; + } + + .pl-mh /* markup.heading */, + .pl-mh .pl-en /* markup.heading entity.name */, + .pl-ms /* meta.separator */ { + font-weight: bold; + color: #005cc5; + } + + .pl-mi /* markup.italic */ { + font-style: italic; + color: #24292e; + } + + .pl-mb /* markup.bold */ { + font-weight: bold; + color: #24292e; + } + + .pl-md /* markup.deleted, meta.diff.header.from-file, punctuation.definition.deleted */ { + color: #b31d28; + background-color: #ffeef0; + } + + .pl-mi1 /* markup.inserted, meta.diff.header.to-file, punctuation.definition.inserted */ { + color: #22863a; + background-color: #f0fff4; + } + + .pl-mc /* markup.changed, punctuation.definition.changed */ { + color: #e36209; + background-color: #ffebda; + } + + .pl-mi2 /* markup.ignored, markup.untracked */ { + color: #f6f8fa; + background-color: #005cc5; + } + + .pl-mdr /* meta.diff.range */ { + font-weight: bold; + color: #6f42c1; + } + + .pl-ba /* brackethighlighter.tag, brackethighlighter.curly, brackethighlighter.round, brackethighlighter.square, brackethighlighter.angle, brackethighlighter.quote */ { + color: #586069; + } + + .pl-sg /* sublimelinter.gutter-mark */ { + color: #959da5; + } + + .pl-corl /* constant.other.reference.link, string.other.link */ { + text-decoration: underline; + color: #032f62; + } \ No newline at end of file diff --git a/docs/static/icon.js b/docs/static/icon.js new file mode 100644 index 0000000..d440086 --- /dev/null +++ b/docs/static/icon.js @@ -0,0 +1,12 @@ + +var IconList={ + "post":"M0 3.75C0 2.784.784 2 1.75 2h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25Zm1.75-.25a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-8.5a.25.25 0 0 0-.25-.25ZM3.5 6.25a.75.75 0 0 1 .75-.75h7a.75.75 0 0 1 0 1.5h-7a.75.75 0 0 1-.75-.75Zm.75 2.25h4a.75.75 0 0 1 0 1.5h-4a.75.75 0 0 1 0-1.5Z", + "link":"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z", + "person":"M10.561 8.073a6.005 6.005 0 0 1 3.432 5.142.75.75 0 1 1-1.498.07 4.5 4.5 0 0 0-8.99 0 .75.75 0 0 1-1.498-.07 6.004 6.004 0 0 1 3.431-5.142 3.999 3.999 0 1 1 5.123 0ZM10.5 5a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z", + "github":"M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z", + "sun":"M8 10.5a2.5 2.5 0 100-5 2.5 2.5 0 000 5zM8 12a4 4 0 100-8 4 4 0 000 8zM8 0a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0V.75A.75.75 0 018 0zm0 13a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 018 13zM2.343 2.343a.75.75 0 011.061 0l1.06 1.061a.75.75 0 01-1.06 1.06l-1.06-1.06a.75.75 0 010-1.06zm9.193 9.193a.75.75 0 011.06 0l1.061 1.06a.75.75 0 01-1.06 1.061l-1.061-1.06a.75.75 0 010-1.061zM16 8a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 0116 8zM3 8a.75.75 0 01-.75.75H.75a.75.75 0 010-1.5h1.5A.75.75 0 013 8zm10.657-5.657a.75.75 0 010 1.061l-1.061 1.06a.75.75 0 11-1.06-1.06l1.06-1.06a.75.75 0 011.06 0zm-9.193 9.193a.75.75 0 010 1.06l-1.06 1.061a.75.75 0 11-1.061-1.06l1.06-1.061a.75.75 0 011.061 0z", + "moon":"M9.598 1.591a.75.75 0 01.785-.175 7 7 0 11-8.967 8.967.75.75 0 01.961-.96 5.5 5.5 0 007.046-7.046.75.75 0 01.175-.786zm1.616 1.945a7 7 0 01-7.678 7.678 5.5 5.5 0 107.678-7.678z", + "search":"M15.7 13.3l-3.81-3.83A5.93 5.93 0 0 0 13 6c0-3.31-2.69-6-6-6S1 2.69 1 6s2.69 6 6 6c1.3 0 2.48-.41 3.47-1.11l3.83 3.81c.19.2.45.3.7.3.25 0 .52-.09.7-.3a.996.996 0 0 0 0-1.41v.01zM7 10.7c-2.59 0-4.7-2.11-4.7-4.7 0-2.59 2.11-4.7 4.7-4.7 2.59 0 4.7 2.11 4.7 4.7 0 2.59-2.11 4.7-4.7 4.7z", + "home":"M6.906.664a1.749 1.749 0 0 1 2.187 0l5.25 4.2c.415.332.657.835.657 1.367v7.019A1.75 1.75 0 0 1 13.25 15h-3.5a.75.75 0 0 1-.75-.75V9H7v5.25a.75.75 0 0 1-.75.75h-3.5A1.75 1.75 0 0 1 1 13.25V6.23c0-.531.242-1.034.657-1.366l5.25-4.2Zm1.25 1.171a.25.25 0 0 0-.312 0l-5.25 4.2a.25.25 0 0 0-.094.196v7.019c0 .138.112.25.25.25H5.5V8.25a.75.75 0 0 1 .75-.75h3.5a.75.75 0 0 1 .75.75v5.25h2.75a.25.25 0 0 0 .25-.25V6.23a.25.25 0 0 0-.094-.195Z", + "email":"M1.75 2h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25v-8.5C0 2.784.784 2 1.75 2ZM1.5 12.251c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V5.809L8.38 9.397a.75.75 0 0 1-.76 0L1.5 5.809v6.442Zm13-8.181v-.32a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25v.32L8 7.88Z" +} diff --git a/plist_example.html b/plist_example.html new file mode 100644 index 0000000..81458d2 --- /dev/null +++ b/plist_example.html @@ -0,0 +1,184 @@ + +
+ + + + + + + + + + + + + + + diff --git a/post_example.html b/post_example.html new file mode 100644 index 0000000..cdc2abc --- /dev/null +++ b/post_example.html @@ -0,0 +1,142 @@ + + + + + + + + + + + + +