-
-
Notifications
You must be signed in to change notification settings - Fork 28
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
1 parent
fd17467
commit 4538e13
Showing
2 changed files
with
183 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,148 @@ | ||
/* | ||
* Script for minimizing big images (jpg,gif,png) when they are uploaded to GitHub and not edited otherwise. | ||
* Source: https://github.com/TeamNewPipe/NewPipe/blob/dev/.github/workflows/image-minimizer.js | ||
*/ | ||
module.exports = async ({github, context}) => { | ||
const IGNORE_KEY = '<!-- IGNORE IMAGE MINIFY -->'; | ||
const IGNORE_ALT_NAME_END = 'ignoreImageMinify'; | ||
// Targeted maximum height | ||
const IMG_MAX_HEIGHT_PX = 400; | ||
// maximum width of GitHub issues/comments | ||
const IMG_MAX_WIDTH_PX = 800; | ||
// all images that have a lower aspect ratio (-> have a smaller width) than this will be minimized | ||
const MIN_ASPECT_RATIO = IMG_MAX_WIDTH_PX / IMG_MAX_HEIGHT_PX | ||
|
||
// Get the body of the image | ||
let initialBody = null; | ||
if (context.eventName == 'issue_comment') { | ||
initialBody = context.payload.comment.body; | ||
} else if (context.eventName == 'issues') { | ||
initialBody = context.payload.issue.body; | ||
} else if (context.eventName == 'pull_request_target') { | ||
initialBody = context.payload.pull_request.body; | ||
} else { | ||
console.log('Aborting: No body found'); | ||
return; | ||
} | ||
console.log(`Found body: \n${initialBody}\n`); | ||
|
||
// Check if we should ignore the currently processing element | ||
if (initialBody.includes(IGNORE_KEY)) { | ||
console.log('Ignoring: Body contains IGNORE_KEY'); | ||
return; | ||
} | ||
|
||
// Regex for finding images (simple variant) ![ALT_TEXT](https://*.githubusercontent.com/<number>/<variousHexStringsAnd->.<fileExtension>) | ||
const REGEX_USER_CONTENT_IMAGE_LOOKUP = /\!\[(.*)\]\((https:\/\/[-a-z0-9]+\.githubusercontent\.com\/\d+\/[-0-9a-f]{32,512}\.(jpg|gif|png))\)/gm; | ||
const REGEX_ASSETS_IMAGE_LOCKUP = /\!\[(.*)\]\((https:\/\/github\.com\/user-attachments\/assets\/[\-0-9a-f]{36,})\)/gm; | ||
|
||
// Check if we found something | ||
let foundSimpleImages = REGEX_USER_CONTENT_IMAGE_LOOKUP.test(initialBody) | ||
|| REGEX_ASSETS_IMAGE_LOCKUP.test(initialBody); | ||
if (!foundSimpleImages) { | ||
console.log('Found no simple images to process'); | ||
return; | ||
} | ||
|
||
console.log('Found at least one simple image to process'); | ||
|
||
// Require the probe lib for getting the image dimensions | ||
const probe = require('probe-image-size'); | ||
|
||
var wasMatchModified = false; | ||
|
||
// Try to find and replace the images with minimized ones | ||
let newBody = await replaceAsync(initialBody, REGEX_USER_CONTENT_IMAGE_LOOKUP, minimizeAsync); | ||
newBody = await replaceAsync(newBody, REGEX_ASSETS_IMAGE_LOCKUP, minimizeAsync); | ||
|
||
if (!wasMatchModified) { | ||
console.log('Nothing was modified. Skipping update'); | ||
return; | ||
} | ||
|
||
// Update the corresponding element | ||
if (context.eventName == 'issue_comment') { | ||
console.log('Updating comment with id', context.payload.comment.id); | ||
await github.rest.issues.updateComment({ | ||
comment_id: context.payload.comment.id, | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
body: newBody | ||
}) | ||
} else if (context.eventName == 'issues') { | ||
console.log('Updating issue', context.payload.issue.number); | ||
await github.rest.issues.update({ | ||
issue_number: context.payload.issue.number, | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
body: newBody | ||
}); | ||
} else if (context.eventName == 'pull_request_target') { | ||
console.log('Updating pull request', context.payload.pull_request.number); | ||
await github.rest.pulls.update({ | ||
pull_number: context.payload.pull_request.number, | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
body: newBody | ||
}); | ||
} | ||
|
||
// Async replace function from https://stackoverflow.com/a/48032528 | ||
async function replaceAsync(str, regex, asyncFn) { | ||
const promises = []; | ||
str.replace(regex, (match, ...args) => { | ||
const promise = asyncFn(match, ...args); | ||
promises.push(promise); | ||
}); | ||
const data = await Promise.all(promises); | ||
return str.replace(regex, () => data.shift()); | ||
} | ||
|
||
async function minimizeAsync(match, g1, g2) { | ||
console.log(`Found match '${match}'`); | ||
|
||
if (g1.endsWith(IGNORE_ALT_NAME_END)) { | ||
console.log(`Ignoring match '${match}': IGNORE_ALT_NAME_END`); | ||
return match; | ||
} | ||
|
||
let probeAspectRatio = 0; | ||
let shouldModify = false; | ||
try { | ||
console.log(`Probing ${g2}`); | ||
let probeResult = await probe(g2); | ||
if (probeResult == null) { | ||
throw 'No probeResult'; | ||
} | ||
if (probeResult.hUnits != 'px') { | ||
throw `Unexpected probeResult.hUnits (expected px but got ${probeResult.hUnits})`; | ||
} | ||
if (probeResult.height <= 0) { | ||
throw `Unexpected probeResult.height (height is invalid: ${probeResult.height})`; | ||
} | ||
if (probeResult.wUnits != 'px') { | ||
throw `Unexpected probeResult.wUnits (expected px but got ${probeResult.wUnits})`; | ||
} | ||
if (probeResult.width <= 0) { | ||
throw `Unexpected probeResult.width (width is invalid: ${probeResult.width})`; | ||
} | ||
console.log(`Probing resulted in ${probeResult.width}x${probeResult.height}px`); | ||
|
||
probeAspectRatio = probeResult.width / probeResult.height; | ||
shouldModify = probeResult.height > IMG_MAX_HEIGHT_PX && probeAspectRatio < MIN_ASPECT_RATIO; | ||
} catch(e) { | ||
console.log('Probing failed:', e); | ||
// Immediately abort | ||
return match; | ||
} | ||
|
||
if (shouldModify) { | ||
wasMatchModified = true; | ||
console.log(`Modifying match '${match}'`); | ||
return `<img alt="${g1}" src="${g2}" width=${Math.min(600, Math.floor(IMG_MAX_HEIGHT_PX * probeAspectRatio))} />`; | ||
} | ||
|
||
console.log(`Match '${match}' is ok/will not be modified`); | ||
return match; | ||
} | ||
} |
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,35 @@ | ||
name: Image Minimizer | ||
|
||
on: | ||
issue_comment: | ||
types: [created, edited] | ||
issues: | ||
types: [opened, edited] | ||
pull_request_target: | ||
types: [opened, edited] | ||
|
||
permissions: | ||
issues: write | ||
pull-requests: write | ||
|
||
jobs: | ||
try-minimize: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- uses: actions/setup-node@v4 | ||
with: | ||
node-version: 16 | ||
|
||
- name: Install probe-image-size | ||
run: npm i [email protected] --ignore-scripts | ||
|
||
- name: Minimize simple images | ||
uses: actions/github-script@v7 | ||
timeout-minutes: 3 | ||
with: | ||
script: | | ||
const script = require('.github/workflows/image-minimizer.js'); | ||
await script({github, context}); |