Skip to content

Commit

Permalink
Add GitHub Skyline plugin (#147)
Browse files Browse the repository at this point in the history
  • Loading branch information
lowlighter committed Feb 20, 2021
1 parent 66d7c79 commit 91bebb4
Show file tree
Hide file tree
Showing 9 changed files with 734 additions and 4 deletions.
546 changes: 543 additions & 3 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"express-rate-limit": "^5.2.6",
"faker": "^5.4.0",
"image-to-base64": "^2.1.1",
"jimp": "^0.16.1",
"js-yaml": "^4.0.0",
"memory-cache": "^0.2.0",
"prismjs": "^1.23.0",
Expand Down
18 changes: 18 additions & 0 deletions source/app/metrics/utils.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
import imgb64 from "image-to-base64"
import git from "simple-git"
import twemojis from "twemoji-parser"
import jimp from "jimp"

//Exports
export {fs, os, paths, url, util, processes, axios, puppeteer, imgb64, git}

/**Returns module __dirname */
Expand Down Expand Up @@ -189,3 +191,19 @@
export async function wait(seconds) {
await new Promise(solve => setTimeout(solve, seconds*1000)) //eslint-disable-line no-promise-executor-return
}

/**Create gif from puppeteer browser */
export async function puppeteergif({page, width, height, frames, scale = 1, quality = 80, x = 0, y = 0, delay = 150}) {
//Register images frames
const images = []
for (let i = 0; i < frames; i++) {
images.push(await page.screenshot({type:"png", clip:{width, height, x, y}}))
await wait(delay/1000)
if (i%10 === 0)
console.debug(`metrics/puppeteergif > processed ${i}/${frames} frames`)
}
console.debug(`metrics/puppeteergif > processed ${frames}/${frames} frames`)
//Post-processing
console.debug("metrics/puppeteergif > applying post-processing")
return Promise.all(images.map(async buffer => (await jimp.read(buffer)).scale(scale).quality(quality).getBase64Async("image/png")))
}
27 changes: 27 additions & 0 deletions source/plugins/skyline/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
### 🌇 GitHub Skyline 3D calendar

⚠️ This plugin significantly increase file size, prefer using it as standalone.

The *skyline* plugin lets you display your 3D commits calendar from [skyline.github.com](https://skyline.github.com/).

<table>
<td align="center">
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.skyline.svg">
<img width="900" height="1" alt="">
</td>
</table>

This uses puppeteer to generate collect image frames, and use CSS animations to create an animated rendering (GIF images are not animated in GitHub flavored markdown rendering which is why this design choice was made).

#### ℹ️ Examples workflows

[➡️ Available options for this plugin](metadata.yml)

```yaml
- uses: lowlighter/metrics@latest
with:
# ... other options
plugin_skyline: yes
plugin_skyline_year: 0 # Set to 0 to display current year
plugin_skyline_frames: 60 # Use 60 frames (half-loop)
```
49 changes: 49 additions & 0 deletions source/plugins/skyline/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//Setup
export default async function({login, q, imports, data, account}, {enabled = false} = {}) {
//Plugin execution
try {
//Check if plugin is enabled and requirements are met
if ((!enabled)||(!q.skyline))
return null

//Load inputs
let {year, frames} = imports.metadata.plugins.skyline.inputs({data, account, q})
if (Number.isNaN(year)) {
year = new Date().getFullYear()
console.debug(`metrics/compute/${login}/plugins > skyline > year set to ${year}`)
}
const width = 454
const height = 284

//Start puppeteer and navigate to skyline.github.com
console.debug(`metrics/compute/${login}/plugins > skyline > starting browser`)
const browser = await imports.puppeteer.launch({headless:true, executablePath:process.env.PUPPETEER_BROWSER_PATH, args:["--no-sandbox", "--disable-extensions", "--disable-setuid-sandbox", "--disable-dev-shm-usage"]})
console.debug(`metrics/compute/${login}/plugins > skyline > started ${await browser.version()}`)
const page = await browser.newPage()
await page.setViewport({width, height})

//Load page
console.debug(`metrics/compute/${login}/plugins > skyline > loading skyline.github.com/${login}/${year}`)
await page.goto(`https://skyline.github.com/${login}/${year}`, {timeout:90*1000})
console.debug(`metrics/compute/${login}/plugins > skyline > waiting for initial render`)
const frame = page.mainFrame()
await page.waitForFunction('[...document.querySelectorAll("span")].map(span => span.innerText).includes("Download STL file")', {timeout:90*1000})
await frame.evaluate(() => [...document.querySelectorAll("button, footer, a")].map(element => element.remove()))

//Generate gif
console.debug(`metrics/compute/${login}/plugins > skyline > generating frames`)
const framed = await imports.puppeteergif({page, width, height, frames, scale:0.5})

//Close puppeteer
await browser.close()

//Results
return {frames:framed}
}
//Handle errors
catch (error) {
throw {error:{message:"An error occured", instance:error}}
}
}


28 changes: 28 additions & 0 deletions source/plugins/skyline/metadata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: "🌇 GitHub Skyline 3D calendar"
cost: N/A
categorie: github
supports:
- user
inputs:

# Enable or disable plugin
plugin_skyline:
description: Display GitHub Skyline 3D calendar
type: boolean
default: no

# Displayed year
plugin_skyline_year:
description: Displayed year
type: number
default: "current-year"
min: 2008

# Number of frames
# Use 120 for a full-loop and 60 for a half-loop
plugin_skyline_frames:
description: Number of frames
type: number
default: 60
min: 1
max: 120
8 changes: 8 additions & 0 deletions source/plugins/skyline/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
- name: Skyline plugin (default)
uses: lowlighter/metrics@latest
with:
token: NOT_NEEDED
plugin_skyline: yes
timeout: 1800000
modes:
- action
3 changes: 2 additions & 1 deletion source/templates/classic/partials/_.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
"people",
"activity",
"anilist",
"wakatime"
"wakatime",
"skyline"
]
58 changes: 58 additions & 0 deletions source/templates/classic/partials/skyline.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<% if (plugins.skyline) { %>
<section>
<h2 class="field">
<svg xmlns="http:https://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path></svg>
GitHub Skyline
</h2>
<div class="row">
<section>
<% if (plugins.skyline.error) { %>
<div class="field error">
<svg xmlns="http:https://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= plugins.skyline.error.message %>
</div>
<% } else { %>
<div class="skyline-animation">
<div class="frames">
<% for (const frame of plugins.skyline.frames) { %>
<div class="frame">
<img class="skyline" src="<%= frame %>" width="454" height="284" alt=""/>
</div>
<% } %>
</div>
</div>
<% { const n = plugins.skyline.frames.length, width = 454, height = 284 %>
<style>
@keyframes skyline-animation-frame {
100% { transform: translateX(-100%); }
}
.skyline-animation {
margin: 2px 13px 6px;
border-radius: 10px;
width: <%= width %>px;
height: <%= height %>px;
background-color: #030D21;
overflow: hidden;
}
.skyline-animation .frames {
animation: skyline-animation-frame <%= 150*n %>ms infinite;
animation-timing-function: steps(<%= n %>);
display: flex;
width: <%= n*width %>px;
height: <%= height %>px;
}
.skyline-animation .frames .frame {
display: block;
width: <%= width %>px;
flex-basis: <%= width %>px;
}
.skyline-animation .frames .frame img {
width: <%= width %>px;
}
</style>
<% } %>
<% } %>
</section>
</div>
</section>
<% } %>

0 comments on commit 91bebb4

Please sign in to comment.