├── .github └── workflows │ └── schedule.yml ├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── TEMPLATE.md ├── index.js ├── main.js ├── package.json ├── pnpm-lock.yaml ├── request.js └── test.js /.github/workflows/schedule.yml: -------------------------------------------------------------------------------- 1 | name: Update README 2 | on: # 触发时机 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | schedule: 10 | - cron: "0 0 * * SAT" 11 | # - cron: "0 0 * * SAT,SUN" # 每周一,周六触发,也可以 0 0 * * 1,6 12 | jobs: 13 | update-readme: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout code repository 17 | uses: actions/checkout@v2 18 | 19 | - name: Setup node.js 20 | uses: actions/setup-node@v2 21 | with: 22 | node-version: 16 23 | 24 | - name: Setup pnpm 25 | uses: pnpm/action-setup@v4 26 | with: 27 | version: 8 28 | 29 | - name: Install dependencies 30 | run: pnpm install --no-frozen-lockfile 31 | 32 | - name: Update README 33 | run: node index.js ${{ secrets.GIT_UPDATE_README_TOKEN }} 34 | 35 | - name: Show branch and remote 36 | run: | 37 | git branch 38 | git remote -v 39 | 40 | - name: Commit and push if changed # 将README.md更新到仓库 41 | run: | 42 | git config --global user.email "wangrongding@qq.com" 43 | git config --global user.name "wangrongding" 44 | git add . 45 | git commit -m "Updated Readme" || exit 46 | git push 47 | 48 | - name: Keepalive Workflow 49 | uses: gautamkrishnar/keepalive-workflow@1.0.9 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.enabled": false 3 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 wangrongding 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Github University 2 | 3 | Aggregate quality learning resources, useful tools, interesting projects in github... 4 | Updated every Monday. 5 | 6 | 汇总 github 中优质的学习资源,好用的工具,有趣的项目... 7 | 每周一更新。 8 | 9 | > 开发中,后续会加上分类 10 | > WIP, will add categories later 11 | 12 | ## 优质的学习资源,好用的工具,有趣的项目... 13 | 14 | |             name/url             |           stars           | desc | 15 | | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------- | 16 | | [github-university](https://github.com/wangrongding/github-university) | stars: ∞ ⭐️ | Haha, this is the project | 17 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import { start } from "./main.js"; 2 | 3 | start(process.argv[2]); 4 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | import request from "./request.js"; 2 | import fs from "fs"; 3 | 4 | let TOKEN = ""; 5 | 6 | // 获取star列表 7 | export async function getStarList(data, options) { 8 | const res = await request.get( 9 | `https://api.github.com/users/wangrongding/starred`, 10 | { 11 | data, 12 | ...options, 13 | headers: { 14 | Authorization: `token ${TOKEN}`, 15 | }, 16 | } 17 | ); 18 | return res; 19 | } 20 | 21 | // 写入文件 22 | export async function writeFile(list) { 23 | let content = ``; 24 | list.forEach((item) => { 25 | content += `| [${item.name}](${item.html_url}) | stars:${item.stargazers_count}⭐️ | ${item.description} | \n`; 26 | }); 27 | // 追加内容 28 | fs.appendFile("./README.md", content, (err) => { 29 | if (err) { 30 | console.log("出错"); 31 | } 32 | }); 33 | } 34 | 35 | export async function getStarPages() { 36 | const res = await getStarList({ per_page: 1 }); 37 | // 获取star总数 38 | const total = res.headers.link 39 | .split('>; rel="last"')[0] 40 | .split("per_page=1&page=")[2]; 41 | // star总页数 42 | const pages = Math.ceil(total / 100); 43 | 44 | let starList = []; 45 | for (let i = 0; i < pages; i++) { 46 | const tempRes = await getStarList({ per_page: 100, page: i + 1 }); 47 | console.log(`🚀🚀page${i}✅`); 48 | starList = starList.concat(tempRes.data); 49 | } 50 | // 总star数 51 | console.log("🚀🚀🚀 / starList", starList.length); 52 | return starList; 53 | } 54 | 55 | // 复制文件内容到README 56 | export function copyToReadme() { 57 | fs.copyFileSync("./TEMPLATE.md", "./README.md"); 58 | } 59 | 60 | // 开始执行 61 | export async function start(token) { 62 | TOKEN = token; 63 | copyToReadme(); 64 | const starList = await getStarPages(); 65 | await writeFile(starList); 66 | } 67 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "github-university", 3 | "version": "1.0.0", 4 | "description": "Collect the best learning resources in github.", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "bin": "./index.js", 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/wangrongding/github-university.git" 14 | }, 15 | "keywords": [], 16 | "author": "", 17 | "license": "ISC", 18 | "bugs": { 19 | "url": "https://github.com/wangrongding/github-university/issues" 20 | }, 21 | "homepage": "https://github.com/wangrongding/github-university#readme", 22 | "dependencies": { 23 | "axios": "^0.27.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | axios: 9 | specifier: ^0.27.2 10 | version: 0.27.2 11 | 12 | packages: 13 | 14 | /asynckit@0.4.0: 15 | resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} 16 | dev: false 17 | 18 | /axios@0.27.2: 19 | resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==} 20 | dependencies: 21 | follow-redirects: 1.15.1 22 | form-data: 4.0.0 23 | transitivePeerDependencies: 24 | - debug 25 | dev: false 26 | 27 | /combined-stream@1.0.8: 28 | resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} 29 | engines: {node: '>= 0.8'} 30 | dependencies: 31 | delayed-stream: 1.0.0 32 | dev: false 33 | 34 | /delayed-stream@1.0.0: 35 | resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} 36 | engines: {node: '>=0.4.0'} 37 | dev: false 38 | 39 | /follow-redirects@1.15.1: 40 | resolution: {integrity: sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==} 41 | engines: {node: '>=4.0'} 42 | peerDependencies: 43 | debug: '*' 44 | peerDependenciesMeta: 45 | debug: 46 | optional: true 47 | dev: false 48 | 49 | /form-data@4.0.0: 50 | resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} 51 | engines: {node: '>= 6'} 52 | dependencies: 53 | asynckit: 0.4.0 54 | combined-stream: 1.0.8 55 | mime-types: 2.1.35 56 | dev: false 57 | 58 | /mime-db@1.52.0: 59 | resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} 60 | engines: {node: '>= 0.6'} 61 | dev: false 62 | 63 | /mime-types@2.1.35: 64 | resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} 65 | engines: {node: '>= 0.6'} 66 | dependencies: 67 | mime-db: 1.52.0 68 | dev: false 69 | -------------------------------------------------------------------------------- /request.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | // 创建axios实例 3 | const request = axios.create({ 4 | timeout: 60 * 1000, // 请求超时时间 5 | }); 6 | // request请求拦截器 7 | request.interceptors.request.use( 8 | (config) => { 9 | const { data = {}, method } = config; 10 | if (method === "post") { 11 | config.data = data.data; 12 | } 13 | // get请求转参数key为params 14 | if (method === "get" || method === "delete") { 15 | config.params = data; 16 | } 17 | if (method === "put") { 18 | config.data = { ...data.data }; 19 | } 20 | return config; 21 | }, 22 | (error) => error 23 | ); 24 | 25 | // 请求成功回调 26 | function successCallback(response) { 27 | // console.log(response); 28 | return Promise.resolve(response); 29 | } 30 | // 请求错误回调 31 | function errorCallback(error) { 32 | console.log(error); 33 | return Promise.reject(error); 34 | } 35 | // response返回拦截器 36 | request.interceptors.response.use(successCallback, errorCallback); 37 | 38 | export default request; 39 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | import { getStarList } from "./main.js"; 2 | import parse from "parse-link-header"; 3 | 4 | async function test() { 5 | const res = await getStarList({ per_page: 100 }); 6 | } 7 | test(); 8 | // test action --------------------------------------------------------------------------------