From 3bb1bb28445cad965d0fd7f9ab51dcdd61fe2ff3 Mon Sep 17 00:00:00 2001 From: Daniel Vu Date: Fri, 1 Nov 2024 02:22:45 -0400 Subject: [PATCH 1/8] Initial commit per FAST-1611 --- contrib/roll20-sheet-fonts/.gitignore | 5 + contrib/roll20-sheet-fonts/README.md | 43 ++++++ contrib/roll20-sheet-fonts/bun.lockb | Bin 0 -> 2685 bytes contrib/roll20-sheet-fonts/package.json | 14 ++ contrib/roll20-sheet-fonts/src/config.js | 11 ++ .../src/lib/SheetFontsProcessor.js | 146 ++++++++++++++++++ .../src/scripts/processSheet.js | 29 ++++ contrib/roll20-sheet-fonts/tsconfig.json | 22 +++ 8 files changed, 270 insertions(+) create mode 100644 contrib/roll20-sheet-fonts/.gitignore create mode 100644 contrib/roll20-sheet-fonts/README.md create mode 100755 contrib/roll20-sheet-fonts/bun.lockb create mode 100644 contrib/roll20-sheet-fonts/package.json create mode 100644 contrib/roll20-sheet-fonts/src/config.js create mode 100644 contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js create mode 100644 contrib/roll20-sheet-fonts/src/scripts/processSheet.js create mode 100644 contrib/roll20-sheet-fonts/tsconfig.json diff --git a/contrib/roll20-sheet-fonts/.gitignore b/contrib/roll20-sheet-fonts/.gitignore new file mode 100644 index 0000000000..1d3023e8b6 --- /dev/null +++ b/contrib/roll20-sheet-fonts/.gitignore @@ -0,0 +1,5 @@ +node_modules +.env +.DS_Store +tmp +dist diff --git a/contrib/roll20-sheet-fonts/README.md b/contrib/roll20-sheet-fonts/README.md new file mode 100644 index 0000000000..e4cd3303d4 --- /dev/null +++ b/contrib/roll20-sheet-fonts/README.md @@ -0,0 +1,43 @@ +# Roll20 Sheet Fonts Processor + +Processes Google Fonts from Roll20 character sheets and generates proxy-friendly CSS. + +## Environment Variables + +Required: +- `DISCORD_ACTIVITY_CLIENT_ID`: Discord client ID for font proxy URLs + +Optional: +- `OUTPUT_DIR`: Directory for output files (default: ~/dist) +- `LOG_LEVEL`: Logging level (default: info) +- `SHEET_NAME`: Character sheet to process + +## Setup +```bash +bun install +``` + +## Usage +```bash +# Set required environment variable +export DISCORD_ACTIVITY_CLIENT_ID="1199270539278164008" + +# Process Alien RPG sheet +bun run alienyz + +# Process any sheet +SHEET_NAME="Your Sheet Name" bun run process-sheet + +# With custom output directory +SHEET_NAME="Your Sheet Name" OUTPUT_DIR=./output bun run process-sheet + +# With debug logging +SHEET_NAME="Your Sheet Name" LOG_LEVEL=debug bun run process-sheet +``` + +## Development + +Create a `.env` file in the project root: +```env +DISCORD_ACTIVITY_CLIENT_ID=1199270539278164008 +``` diff --git a/contrib/roll20-sheet-fonts/bun.lockb b/contrib/roll20-sheet-fonts/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..567237ef56302dfce52bfbce8c0d7d460df1e112 GIT binary patch literal 2685 zcmY#Z)GsYA(of3F(@)JSQ%EY!;{sycoc!eMw9K4T-L(9o+{6;yG6OCq1_p*-;bIFW zxNM$jzIC@$^EDy9P4ZlC)-7q>_~G0Z=JTiBOx|(=6#)Sogks=8qZ^?7JeUG7UxQ&onYsr~!bL>^%tlf)G�WAbt#h(sE-l=@-+xZ1F;3r9U${So`i`5nRo$A zT`*9UHB>*y3`M-U5Rx$ci-1B_K>Z>>8WeT?1?dI3fmi@C17;44%>onyg#*kTAR5F60hk(OHg5I*`2WE)f^}1Y0Gh|h z05KQYXcjqUHLgXR9!#qiuUEaaWgFwlBauH1Gv^hUDYE9zP?+tn%6C3|deTO=(C@b9 zQvB(PEN2s9*yJDItv61||1d}D6q32H@Bq1%#pAK=o$`+RjYe?|I>yqLEBohtJaNIQ zKL3h{>ffnGSETt8yC>O*ObiiYd17&E*D}+b2VxQd%3<%_zD-%i`8GNn$y{b6@3U+? zdHDI2%mn+=V-?ztOvfhp?+V&@#ooLtH6yV{WY(RMC5Ox|6xZ9WF3C^~G&ssQ@o=$S z|BOr%X1i&u<%Ln&vyjXMg+C0is0H*`KVMkl#I-80aPlJgum+K^4CA*)tw@B94vL# z>Tp)MVmJ|K?oa_k$f;Be(hbmZ{|J=kvMDY~*2~N*E=kPE(SubwdLc!rsdfrR1`5TQ zRjK)DItnHVi8-0+dHHEvAjkas4*?)HDE)kZn#RHo5@BHAvMDt-vIAA;>^(^!Z85m%7AgpdrJz&)68G z)d6g=et9vJk(Zy6ipMx4RX_tligh8uZ)gHCtu!wsGdYu>XONWvjX~z>g5%7TfUn@L T2I?*^)&-{xa7aL+b?}h@Vy)oB literal 0 HcmV?d00001 diff --git a/contrib/roll20-sheet-fonts/package.json b/contrib/roll20-sheet-fonts/package.json new file mode 100644 index 0000000000..2fbe8a1510 --- /dev/null +++ b/contrib/roll20-sheet-fonts/package.json @@ -0,0 +1,14 @@ +{ + "name": "roll20-sheet-fonts", + "version": "1.0.0", + "type": "module", + "scripts": { + "alienyz": "SHEET_NAME=\"Alien Roleplaying Game\" bun run src/scripts/processSheet.js" + }, + "dependencies": { + "loglevel": "^1.8.1" + }, + "devDependencies": { + "bun-types": "latest" + } + } diff --git a/contrib/roll20-sheet-fonts/src/config.js b/contrib/roll20-sheet-fonts/src/config.js new file mode 100644 index 0000000000..df7df0edf7 --- /dev/null +++ b/contrib/roll20-sheet-fonts/src/config.js @@ -0,0 +1,11 @@ +if (!process.env.DISCORD_ACTIVITY_CLIENT_ID) { + throw new Error('DISCORD_ACTIVITY_CLIENT_ID environment variable is required'); +} + +export const CONFIG = { + DISCORD_ACTIVITY_CLIENT_ID: process.env.DISCORD_ACTIVITY_CLIENT_ID, + OUTPUT_DIR: process.env.OUTPUT_DIR || '/tmp', + LOG_LEVEL: process.env.LOG_LEVEL || 'info', + GITHUB_BASE_URL: 'https://raw.githubusercontent.com/Roll20/roll20-character-sheets/refs/heads/master', + USER_AGENT: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' +}; diff --git a/contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js b/contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js new file mode 100644 index 0000000000..6cd95ec214 --- /dev/null +++ b/contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js @@ -0,0 +1,146 @@ +// src/lib/SheetFontsProcessor.js +import log from 'loglevel'; +import { mkdir } from 'node:fs/promises'; +import { join } from 'path'; +import { CONFIG } from '../config.js'; + +export default class SheetFontsProcessor { + constructor(options = {}) { + this.clientId = CONFIG.DISCORD_ACTIVITY_CLIENT_ID; + this.baseGithubUrl = CONFIG.GITHUB_BASE_URL; + this.userAgent = CONFIG.USER_AGENT; + this.outputDir = options.outputDir || CONFIG.OUTPUT_DIR; + + // Initialize logger + this.log = log.getLogger('SheetFontsProcessor'); + this.log.setLevel(options.logLevel || CONFIG.LOG_LEVEL); + } + + getSheetJsonUrl(sheetName) { + return `${this.baseGithubUrl}/${encodeURIComponent(sheetName)}/sheet.json`; + } + + getSheetCssUrl(sheetName, cssFilename) { + return `${this.baseGithubUrl}/${encodeURIComponent(sheetName)}/${cssFilename}`; + } + + extractGoogleFontsUrls(cssContent) { + const urls = []; + const lines = cssContent.split('\n'); + + for (const line of lines) { + if (line.trim().startsWith('/*')) continue; + + const match = line.match(/url\(['"]?(https:\/\/fonts\.googleapis\.com[^'")\s]+)['"]?\)/); + if (match) { + urls.push(match[1]); + } + } + + return urls; + } + + async ensureOutputDir() { + try { + await mkdir(this.outputDir, { recursive: true }); + } catch (error) { + this.log.error('Error creating output directory:', error); + throw error; + } + } + + async writeOutput(sheetName, content) { + try { + const sanitizedName = sheetName.replace(/[^a-z0-9]/gi, '-').toLowerCase(); + const outputPath = join(this.outputDir, `${sanitizedName}-fonts.css`); + + await this.ensureOutputDir(); + await Bun.write(outputPath, content); + + this.log.info(`Output written to: ${outputPath}`); + return outputPath; + } catch (error) { + this.log.error('Error writing output file:', error); + throw error; + } + } + + async fetchWithHeaders(url) { + try { + this.log.debug(`Fetching URL: ${url}`); + const response = await fetch(url, { + headers: { + 'User-Agent': this.userAgent + } + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + return await response.text(); + } catch (error) { + this.log.error(`Error fetching ${url}:`, error); + throw error; + } + } + + async transformGoogleFontsCss(fontsUrl) { + try { + this.log.debug(`Transforming fonts from: ${fontsUrl}`); + const cssContent = await this.fetchWithHeaders(fontsUrl); + return cssContent.replace( + /fonts\.gstatic\.com/g, + `${this.clientId}.discordsays.com/.proxy/gstatic/fonts` + ); + } catch (error) { + this.log.error(`Error transforming Google Fonts CSS from ${fontsUrl}:`, error); + return ''; + } + } + + async process(sheetName) { + try { + this.log.info(`Processing sheet: ${sheetName}`); + + // Fetch sheet.json + const sheetJsonUrl = this.getSheetJsonUrl(sheetName); + const sheetDataText = await this.fetchWithHeaders(sheetJsonUrl); + const sheetData = JSON.parse(sheetDataText); + + // Fetch CSS content + const cssUrl = this.getSheetCssUrl(sheetName, sheetData.css); + const cssContent = await this.fetchWithHeaders(cssUrl); + + // Extract and process Google Fonts URLs + const fontUrls = this.extractGoogleFontsUrls(cssContent); + this.log.debug(`Found ${fontUrls.length} font URLs`); + + // Transform each Google Fonts CSS + const transformedFontsCss = await Promise.all( + fontUrls.map(url => this.transformGoogleFontsCss(url)) + ); + + const combinedCss = transformedFontsCss.join('\n\n'); + + // Write to file + const outputPath = await this.writeOutput(sheetName, combinedCss); + + return { + originalUrls: fontUrls, + transformedCss: combinedCss, + sheetData, + outputPath + }; + + } catch (error) { + this.log.error(`Error processing sheet ${sheetName}:`, error); + return { + originalUrls: [], + transformedCss: '', + sheetData: null, + error: error.message + }; + } + } +} diff --git a/contrib/roll20-sheet-fonts/src/scripts/processSheet.js b/contrib/roll20-sheet-fonts/src/scripts/processSheet.js new file mode 100644 index 0000000000..4b01ecbfa3 --- /dev/null +++ b/contrib/roll20-sheet-fonts/src/scripts/processSheet.js @@ -0,0 +1,29 @@ +import log from 'loglevel'; +import SheetFontsProcessor from '../lib/SheetFontsProcessor.js'; +import { CONFIG } from '../config.js'; + +// Configure root logger +log.setLevel(CONFIG.LOG_LEVEL); + +const sheetName = process.env.SHEET_NAME; + +if (!sheetName) { + log.error('No sheet name provided. Set SHEET_NAME environment variable.'); + process.exit(1); +} + +const processor = new SheetFontsProcessor({ + outputDir: CONFIG.OUTPUT_DIR, + logLevel: CONFIG.LOG_LEVEL +}); + +const result = await processor.process(sheetName); + +if (result.error) { + log.error('Processing failed:', result.error); + process.exit(1); +} else { + log.info('Processing complete.'); + log.info('Output written to:', result.outputPath); + log.debug('Original Font URLs:', result.originalUrls); +} diff --git a/contrib/roll20-sheet-fonts/tsconfig.json b/contrib/roll20-sheet-fonts/tsconfig.json new file mode 100644 index 0000000000..2e668515bf --- /dev/null +++ b/contrib/roll20-sheet-fonts/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "lib": ["ESNext"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noEmit": true, + "composite": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "jsx": "preserve", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "types": [ + "bun-types" + ] + } +} From 4740672efbe170854c3e4a0bb8400157aad48969 Mon Sep 17 00:00:00 2001 From: Daniel Vu Date: Tue, 5 Nov 2024 01:28:29 -0500 Subject: [PATCH 2/8] Initial commit of Discord CSS files for Alien sheet as example --- Alien Roleplaying Game/production.css | 192 ++++++++++++++++++ Alien Roleplaying Game/staging.css | 192 ++++++++++++++++++ .../src/lib/SheetFontsProcessor.js | 4 +- 3 files changed, 387 insertions(+), 1 deletion(-) create mode 100644 Alien Roleplaying Game/production.css create mode 100644 Alien Roleplaying Game/staging.css diff --git a/Alien Roleplaying Game/production.css b/Alien Roleplaying Game/production.css new file mode 100644 index 0000000000..bbbb505421 --- /dev/null +++ b/Alien Roleplaying Game/production.css @@ -0,0 +1,192 @@ +/* latin-ext */ +@font-face { + font-family: 'Courier Prime'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/courierprime/v9/u-450q2lgwslOqpF_6gQ8kELaw9pWt_-.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Courier Prime'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/courierprime/v9/u-450q2lgwslOqpF_6gQ8kELawFpWg.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* latin */ +@font-face { + font-family: 'Graduate'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/graduate/v17/C8cg4cs3o2n15t_2YygW43w.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* fallback */ +@font-face { + font-family: 'Material Icons'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/materialicons/v142/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2'); +} +/* fallback */ +@font-face { + font-family: 'Material Symbols Outlined'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/materialsymbolsoutlined/v215/kJF1BvYX7BgnkSrUwT8OhrdQw4oELdPIeeII9v6oDMzByHX9rA6RzaxHMPdY43zj-jCxv3fzvRNU22ZXGJpEpjC_1v-p_4MrImHCIJIZrDCvHOej.woff2) format('woff2'); +} +/* cyrillic-ext */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw0aXpsog.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw9aXpsog.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* vietnamese */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw2aXpsog.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw3aXpsog.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw5aXo.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu72xKOzY.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu5mxKOzY.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu7mxKOzY.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu4WxKOzY.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu7WxKOzY.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu7GxKOzY.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu4mxK.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* latin */ +@font-face { + font-family: 'Share Tech Mono'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/sharetechmono/v15/J7aHnp1uDWRBEqV98dVQztYldFcLowEF.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +.material-icons { + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 24px; + line-height: 1; + letter-spacing: normal; + text-transform: none; + display: inline-block; + white-space: nowrap; + word-wrap: normal; + direction: ltr; + -webkit-font-feature-settings: 'liga'; + -webkit-font-smoothing: antialiased; +} + +.material-symbols-outlined { + font-family: 'Material Symbols Outlined'; + font-weight: normal; + font-style: normal; + font-size: 24px; + line-height: 1; + letter-spacing: normal; + text-transform: none; + display: inline-block; + white-space: nowrap; + word-wrap: normal; + direction: ltr; + -webkit-font-feature-settings: 'liga'; + -webkit-font-smoothing: antialiased; +} diff --git a/Alien Roleplaying Game/staging.css b/Alien Roleplaying Game/staging.css new file mode 100644 index 0000000000..1e3bb37d1c --- /dev/null +++ b/Alien Roleplaying Game/staging.css @@ -0,0 +1,192 @@ +/* latin-ext */ +@font-face { + font-family: 'Courier Prime'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/courierprime/v9/u-450q2lgwslOqpF_6gQ8kELaw9pWt_-.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Courier Prime'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/courierprime/v9/u-450q2lgwslOqpF_6gQ8kELawFpWg.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* latin */ +@font-face { + font-family: 'Graduate'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/graduate/v17/C8cg4cs3o2n15t_2YygW43w.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* fallback */ +@font-face { + font-family: 'Material Icons'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/materialicons/v142/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2'); +} +/* fallback */ +@font-face { + font-family: 'Material Symbols Outlined'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/materialsymbolsoutlined/v215/kJF1BvYX7BgnkSrUwT8OhrdQw4oELdPIeeII9v6oDMzByHX9rA6RzaxHMPdY43zj-jCxv3fzvRNU22ZXGJpEpjC_1v-p_4MrImHCIJIZrDCvHOej.woff2) format('woff2'); +} +/* cyrillic-ext */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw0aXpsog.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw9aXpsog.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* vietnamese */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw2aXpsog.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw3aXpsog.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw5aXo.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu72xKOzY.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu5mxKOzY.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu7mxKOzY.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu4WxKOzY.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu7WxKOzY.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu7GxKOzY.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu4mxK.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* latin */ +@font-face { + font-family: 'Share Tech Mono'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/sharetechmono/v15/J7aHnp1uDWRBEqV98dVQztYldFcLowEF.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +.material-icons { + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 24px; + line-height: 1; + letter-spacing: normal; + text-transform: none; + display: inline-block; + white-space: nowrap; + word-wrap: normal; + direction: ltr; + -webkit-font-feature-settings: 'liga'; + -webkit-font-smoothing: antialiased; +} + +.material-symbols-outlined { + font-family: 'Material Symbols Outlined'; + font-weight: normal; + font-style: normal; + font-size: 24px; + line-height: 1; + letter-spacing: normal; + text-transform: none; + display: inline-block; + white-space: nowrap; + word-wrap: normal; + direction: ltr; + -webkit-font-feature-settings: 'liga'; + -webkit-font-smoothing: antialiased; +} diff --git a/contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js b/contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js index 6cd95ec214..d674475ea9 100644 --- a/contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js +++ b/contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js @@ -4,7 +4,7 @@ import { mkdir } from 'node:fs/promises'; import { join } from 'path'; import { CONFIG } from '../config.js'; -export default class SheetFontsProcessor { +export class SheetFontsProcessor { constructor(options = {}) { this.clientId = CONFIG.DISCORD_ACTIVITY_CLIENT_ID; this.baseGithubUrl = CONFIG.GITHUB_BASE_URL; @@ -144,3 +144,5 @@ export default class SheetFontsProcessor { } } } + +export default SheetFontsProcessor; From 0b3e114ede526847fd8e52b5318fbb018d95943f Mon Sep 17 00:00:00 2001 From: Daniel Vu Date: Tue, 5 Nov 2024 23:38:01 -0500 Subject: [PATCH 3/8] Adds documentation --- .../{ => discord}/production.css | 0 .../{ => discord}/staging.css | 0 Alien Roleplaying Game/sheet.json | 3 +- contrib/roll20-sheet-fonts/README.md | 71 ++++++++++++++---- contrib/roll20-sheet-fonts/package.json | 25 +++---- contrib/roll20-sheet-fonts/src/config.js | 3 +- .../src/lib/SheetFontsProcessor.js | 72 ++++++++----------- .../src/scripts/processSheet.js | 52 ++++++++++---- 8 files changed, 140 insertions(+), 86 deletions(-) rename Alien Roleplaying Game/{ => discord}/production.css (100%) rename Alien Roleplaying Game/{ => discord}/staging.css (100%) diff --git a/Alien Roleplaying Game/production.css b/Alien Roleplaying Game/discord/production.css similarity index 100% rename from Alien Roleplaying Game/production.css rename to Alien Roleplaying Game/discord/production.css diff --git a/Alien Roleplaying Game/staging.css b/Alien Roleplaying Game/discord/staging.css similarity index 100% rename from Alien Roleplaying Game/staging.css rename to Alien Roleplaying Game/discord/staging.css diff --git a/Alien Roleplaying Game/sheet.json b/Alien Roleplaying Game/sheet.json index d8258a15dc..0fcc3dadf6 100644 --- a/Alien Roleplaying Game/sheet.json +++ b/Alien Roleplaying Game/sheet.json @@ -126,5 +126,6 @@ "description": "Provides an option to add a modifier to all rolls for each skill, and represents bonuses from gear or talents.", "descriptiontranslationkey": "config-perm-modifier-desc" } - ] + ], + "discord": {"fonts": true } } \ No newline at end of file diff --git a/contrib/roll20-sheet-fonts/README.md b/contrib/roll20-sheet-fonts/README.md index e4cd3303d4..8502f055a4 100644 --- a/contrib/roll20-sheet-fonts/README.md +++ b/contrib/roll20-sheet-fonts/README.md @@ -8,9 +8,7 @@ Required: - `DISCORD_ACTIVITY_CLIENT_ID`: Discord client ID for font proxy URLs Optional: -- `OUTPUT_DIR`: Directory for output files (default: ~/dist) - `LOG_LEVEL`: Logging level (default: info) -- `SHEET_NAME`: Character sheet to process ## Setup ```bash @@ -18,26 +16,69 @@ bun install ``` ## Usage + +The script requires two arguments: +1. Sheet name: The name of the Roll20 character sheet +2. Output path: Where to save the processed CSS file + ```bash -# Set required environment variable -export DISCORD_ACTIVITY_CLIENT_ID="1199270539278164008" +# Basic usage +bun run src/scripts/processSheet.js "Sheet Name" ./path/to/output.css -# Process Alien RPG sheet +# Example with actual sheet +bun run src/scripts/processSheet.js "Alien Roleplaying Game" + +# Using the Alien RPG sheet shortcut bun run alienyz - -# Process any sheet -SHEET_NAME="Your Sheet Name" bun run process-sheet - -# With custom output directory -SHEET_NAME="Your Sheet Name" OUTPUT_DIR=./output bun run process-sheet - -# With debug logging -SHEET_NAME="Your Sheet Name" LOG_LEVEL=debug bun run process-sheet ``` ## Development Create a `.env` file in the project root: + ```env -DISCORD_ACTIVITY_CLIENT_ID=1199270539278164008 +DISCORD_ACTIVITY_CLIENT_ID=1199271093882589195 ``` + +## Examples + +Process different sheets: +```bash +# Bladerunner +bun run src/scripts/processSheet.js "blade_runner_rpg" ./dist/bladerunner.css + +# Warhammer 4e +bun run src/scripts/processSheet.js "Warhammer Fantasy Roleplay 4e Official" ../../Warhammer\ Fantasy\ Roleplay\ 4e\ Official/discord/production.css +``` + +## Opening Pull Requests for Discord + +There are times you'll want to make sure that fonts for a certain sheet load as expected in Discord. The following steps outline the process for adding support for certain Fonts in a semi-automated manner. + +### 1. Generate CSS for proxied font URLs + +For each sheet, note that a `discord` directory will be auto-generated and auto-managed as a result of the commands below but you'll still need manually commit and push the directory changes to GitHub. Run the font processor script to generate proxied font URLs for the following environments: + +- Staging. Example: `DISCORD_ACTIVITY_CLIENT_ID=1199270539278164008 bun run src/scripts/processSheet.js "Alien Roleplaying Game" ../../Alien\ Roleplaying\ Game/discord/staging.css` +- Production. Example: `DISCORD_ACTIVITY_CLIENT_ID=1199271093882589195 bun run src/scripts/processSheet.js "Alien Roleplaying Game" ../../Alien\ Roleplaying\ Game/discord/production.css` + +### 2. Update sheet.json to indicate that this sheet has been updated for Discord + +Ensure that the following exists in the corresponding sheet.json for your sheet at the root level of the object: + +```json + "discord": { "fonts": true } +``` + +This is what will let those working on Discord know that a sheet has already had font proxying support added upstream per the working process documented here. So make sure that you commit and push this change to GitHub. + +### 3. Create and merge a pull request with your changes + +You'll now need to get these changes merged into the master branch: https://github.com/Roll20/roll20-character-sheets/pulls + +## Debug Logging + +Enable debug logging: +```bash +LOG_LEVEL=debug bun run src/scripts/processSheet.js "Sheet Name" ./output.css +``` \ No newline at end of file diff --git a/contrib/roll20-sheet-fonts/package.json b/contrib/roll20-sheet-fonts/package.json index 2fbe8a1510..a6b6900deb 100644 --- a/contrib/roll20-sheet-fonts/package.json +++ b/contrib/roll20-sheet-fonts/package.json @@ -1,14 +1,15 @@ { - "name": "roll20-sheet-fonts", - "version": "1.0.0", - "type": "module", - "scripts": { - "alienyz": "SHEET_NAME=\"Alien Roleplaying Game\" bun run src/scripts/processSheet.js" - }, - "dependencies": { - "loglevel": "^1.8.1" - }, - "devDependencies": { - "bun-types": "latest" - } + "name": "roll20-sheet-fonts", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "bun run src/index.js", + "alienyz": "bun run src/scripts/processSheet.js \"Alien Roleplaying Game\" ./dist/alien.css" + }, + "dependencies": { + "loglevel": "^1.8.1" + }, + "devDependencies": { + "bun-types": "latest" } +} \ No newline at end of file diff --git a/contrib/roll20-sheet-fonts/src/config.js b/contrib/roll20-sheet-fonts/src/config.js index df7df0edf7..ae2922cc4d 100644 --- a/contrib/roll20-sheet-fonts/src/config.js +++ b/contrib/roll20-sheet-fonts/src/config.js @@ -4,8 +4,7 @@ if (!process.env.DISCORD_ACTIVITY_CLIENT_ID) { export const CONFIG = { DISCORD_ACTIVITY_CLIENT_ID: process.env.DISCORD_ACTIVITY_CLIENT_ID, - OUTPUT_DIR: process.env.OUTPUT_DIR || '/tmp', LOG_LEVEL: process.env.LOG_LEVEL || 'info', GITHUB_BASE_URL: 'https://raw.githubusercontent.com/Roll20/roll20-character-sheets/refs/heads/master', USER_AGENT: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' -}; +}; \ No newline at end of file diff --git a/contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js b/contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js index d674475ea9..a59642ab50 100644 --- a/contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js +++ b/contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js @@ -5,15 +5,14 @@ import { join } from 'path'; import { CONFIG } from '../config.js'; export class SheetFontsProcessor { - constructor(options = {}) { + constructor() { this.clientId = CONFIG.DISCORD_ACTIVITY_CLIENT_ID; this.baseGithubUrl = CONFIG.GITHUB_BASE_URL; this.userAgent = CONFIG.USER_AGENT; - this.outputDir = options.outputDir || CONFIG.OUTPUT_DIR; // Initialize logger this.log = log.getLogger('SheetFontsProcessor'); - this.log.setLevel(options.logLevel || CONFIG.LOG_LEVEL); + this.log.setLevel(CONFIG.LOG_LEVEL); } getSheetJsonUrl(sheetName) { @@ -99,50 +98,41 @@ export class SheetFontsProcessor { } } - async process(sheetName) { - try { - this.log.info(`Processing sheet: ${sheetName}`); + // Remove outputDir-related methods as we're now handling file output in the script + async process(sheetName) { + try { + this.log.info(`Processing sheet: ${sheetName}`); - // Fetch sheet.json - const sheetJsonUrl = this.getSheetJsonUrl(sheetName); - const sheetDataText = await this.fetchWithHeaders(sheetJsonUrl); - const sheetData = JSON.parse(sheetDataText); + const sheetJsonUrl = this.getSheetJsonUrl(sheetName); + const sheetDataText = await this.fetchWithHeaders(sheetJsonUrl); + const sheetData = JSON.parse(sheetDataText); - // Fetch CSS content - const cssUrl = this.getSheetCssUrl(sheetName, sheetData.css); - const cssContent = await this.fetchWithHeaders(cssUrl); + const cssUrl = this.getSheetCssUrl(sheetName, sheetData.css); + const cssContent = await this.fetchWithHeaders(cssUrl); - // Extract and process Google Fonts URLs - const fontUrls = this.extractGoogleFontsUrls(cssContent); - this.log.debug(`Found ${fontUrls.length} font URLs`); - - // Transform each Google Fonts CSS - const transformedFontsCss = await Promise.all( - fontUrls.map(url => this.transformGoogleFontsCss(url)) - ); + const fontUrls = this.extractGoogleFontsUrls(cssContent); + this.log.debug(`Found ${fontUrls.length} font URLs`); + + const transformedFontsCss = await Promise.all( + fontUrls.map(url => this.transformGoogleFontsCss(url)) + ); - const combinedCss = transformedFontsCss.join('\n\n'); - - // Write to file - const outputPath = await this.writeOutput(sheetName, combinedCss); + return { + originalUrls: fontUrls, + transformedCss: transformedFontsCss.join('\n\n'), + sheetData + }; - return { - originalUrls: fontUrls, - transformedCss: combinedCss, - sheetData, - outputPath - }; - - } catch (error) { - this.log.error(`Error processing sheet ${sheetName}:`, error); - return { - originalUrls: [], - transformedCss: '', - sheetData: null, - error: error.message - }; - } + } catch (error) { + this.log.error(`Error processing sheet ${sheetName}:`, error); + return { + originalUrls: [], + transformedCss: '', + sheetData: null, + error: error.message + }; } } +} export default SheetFontsProcessor; diff --git a/contrib/roll20-sheet-fonts/src/scripts/processSheet.js b/contrib/roll20-sheet-fonts/src/scripts/processSheet.js index 4b01ecbfa3..ccb1966712 100644 --- a/contrib/roll20-sheet-fonts/src/scripts/processSheet.js +++ b/contrib/roll20-sheet-fonts/src/scripts/processSheet.js @@ -1,29 +1,51 @@ import log from 'loglevel'; +import { dirname } from 'path'; +import { mkdir } from 'node:fs/promises'; import SheetFontsProcessor from '../lib/SheetFontsProcessor.js'; import { CONFIG } from '../config.js'; // Configure root logger log.setLevel(CONFIG.LOG_LEVEL); -const sheetName = process.env.SHEET_NAME; +// Get command line arguments +const [,, sheetName, outputPath] = process.argv; -if (!sheetName) { - log.error('No sheet name provided. Set SHEET_NAME environment variable.'); +if (!sheetName || !outputPath) { + log.error('Usage: bun run processSheet.js '); process.exit(1); } -const processor = new SheetFontsProcessor({ - outputDir: CONFIG.OUTPUT_DIR, - logLevel: CONFIG.LOG_LEVEL -}); +class FileProcessor { + static async ensureDir(filePath) { + await mkdir(dirname(filePath), { recursive: true }); + } -const result = await processor.process(sheetName); + static async process(sheetName, outputPath) { + try { + // Ensure output directory exists + await this.ensureDir(outputPath); -if (result.error) { - log.error('Processing failed:', result.error); - process.exit(1); -} else { - log.info('Processing complete.'); - log.info('Output written to:', result.outputPath); - log.debug('Original Font URLs:', result.originalUrls); + const processor = new SheetFontsProcessor(); + + // Fetch and transform the CSS + const result = await processor.process(sheetName); + + if (result.error) { + throw new Error(result.error); + } + + // Write to specified path + await Bun.write(outputPath, result.transformedCss); + + log.info('Processing complete.'); + log.info('Output written to:', outputPath); + log.debug('Original Font URLs:', result.originalUrls); + + } catch (error) { + log.error('Processing failed:', error); + process.exit(1); + } + } } + +await FileProcessor.process(sheetName, outputPath); From 8f95f4ca646e9addffb3963a01a41596c3a4a81b Mon Sep 17 00:00:00 2001 From: Daniel Vu Date: Fri, 8 Nov 2024 19:49:19 -0500 Subject: [PATCH 4/8] Switches to CI/CD action so that sheet authors don't have to do much --- .github/workflows/discord-fonts.yml | 51 ++++++ contrib/roll20-sheet-fonts/.gitignore | 5 - contrib/roll20-sheet-fonts/README.md | 84 --------- contrib/roll20-sheet-fonts/bun.lockb | Bin 2685 -> 0 bytes contrib/roll20-sheet-fonts/package.json | 15 -- contrib/roll20-sheet-fonts/src/config.js | 10 -- .../src/lib/SheetFontsProcessor.js | 138 --------------- .../src/scripts/processSheet.js | 51 ------ contrib/roll20-sheet-fonts/tsconfig.json | 22 --- process-fonts.sh | 165 ++++++++++++++++++ 10 files changed, 216 insertions(+), 325 deletions(-) create mode 100644 .github/workflows/discord-fonts.yml delete mode 100644 contrib/roll20-sheet-fonts/.gitignore delete mode 100644 contrib/roll20-sheet-fonts/README.md delete mode 100755 contrib/roll20-sheet-fonts/bun.lockb delete mode 100644 contrib/roll20-sheet-fonts/package.json delete mode 100644 contrib/roll20-sheet-fonts/src/config.js delete mode 100644 contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js delete mode 100644 contrib/roll20-sheet-fonts/src/scripts/processSheet.js delete mode 100644 contrib/roll20-sheet-fonts/tsconfig.json create mode 100755 process-fonts.sh diff --git a/.github/workflows/discord-fonts.yml b/.github/workflows/discord-fonts.yml new file mode 100644 index 0000000000..c00ffdd4b1 --- /dev/null +++ b/.github/workflows/discord-fonts.yml @@ -0,0 +1,51 @@ +name: Process and Upload Fonts + +on: + push: + branches: + - staging + - master + paths: + - '**.css' + +jobs: + process-fonts: + environment: ${{ github.ref_name == 'master' && 'production' || 'staging' }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install required tools + run: sudo apt-get update && sudo apt-get install -y zsh perl curl + + - id: 'auth' + uses: 'google-github-actions/auth@v1' + with: + credentials_json: '${{ secrets.SHEET_HTTP_GCP_KEYFILE }}' + + - name: 'Set up Cloud SDK' + uses: 'google-github-actions/setup-gcloud@v1' + + - name: Process Font URLs + run: | + chmod +x ./process-fonts.sh + CLIENT_ID=${{ github.ref_name == 'master' && '1199271093882589195' || '1199270539278164008' }} + DISCORD_ACTIVITY_CLIENT_ID=$CLIENT_ID \ + ./process-fonts.sh --no-prompt fonts.css + + - name: Upload to GCS + run: | + DEST_NAME="${{ github.ref_name == 'master' && 'production' || 'staging' }}.css" + + # Create temp directory and copy fonts.css to it + TEMP_DIR="${{ runner.temp }}/fonts" + mkdir -p "$TEMP_DIR" + cp fonts.css "$TEMP_DIR/$DEST_NAME" + + # Sync to GCS + gcloud storage rsync \ + --project=roll20-actual \ + "$TEMP_DIR" \ + gs://roll20-cdn/discord/fonts \ + --cache-control='no-cache' \ + --recursive diff --git a/contrib/roll20-sheet-fonts/.gitignore b/contrib/roll20-sheet-fonts/.gitignore deleted file mode 100644 index 1d3023e8b6..0000000000 --- a/contrib/roll20-sheet-fonts/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -.env -.DS_Store -tmp -dist diff --git a/contrib/roll20-sheet-fonts/README.md b/contrib/roll20-sheet-fonts/README.md deleted file mode 100644 index 8502f055a4..0000000000 --- a/contrib/roll20-sheet-fonts/README.md +++ /dev/null @@ -1,84 +0,0 @@ -# Roll20 Sheet Fonts Processor - -Processes Google Fonts from Roll20 character sheets and generates proxy-friendly CSS. - -## Environment Variables - -Required: -- `DISCORD_ACTIVITY_CLIENT_ID`: Discord client ID for font proxy URLs - -Optional: -- `LOG_LEVEL`: Logging level (default: info) - -## Setup -```bash -bun install -``` - -## Usage - -The script requires two arguments: -1. Sheet name: The name of the Roll20 character sheet -2. Output path: Where to save the processed CSS file - -```bash -# Basic usage -bun run src/scripts/processSheet.js "Sheet Name" ./path/to/output.css - -# Example with actual sheet -bun run src/scripts/processSheet.js "Alien Roleplaying Game" - -# Using the Alien RPG sheet shortcut -bun run alienyz -``` - -## Development - -Create a `.env` file in the project root: - -```env -DISCORD_ACTIVITY_CLIENT_ID=1199271093882589195 -``` - -## Examples - -Process different sheets: -```bash -# Bladerunner -bun run src/scripts/processSheet.js "blade_runner_rpg" ./dist/bladerunner.css - -# Warhammer 4e -bun run src/scripts/processSheet.js "Warhammer Fantasy Roleplay 4e Official" ../../Warhammer\ Fantasy\ Roleplay\ 4e\ Official/discord/production.css -``` - -## Opening Pull Requests for Discord - -There are times you'll want to make sure that fonts for a certain sheet load as expected in Discord. The following steps outline the process for adding support for certain Fonts in a semi-automated manner. - -### 1. Generate CSS for proxied font URLs - -For each sheet, note that a `discord` directory will be auto-generated and auto-managed as a result of the commands below but you'll still need manually commit and push the directory changes to GitHub. Run the font processor script to generate proxied font URLs for the following environments: - -- Staging. Example: `DISCORD_ACTIVITY_CLIENT_ID=1199270539278164008 bun run src/scripts/processSheet.js "Alien Roleplaying Game" ../../Alien\ Roleplaying\ Game/discord/staging.css` -- Production. Example: `DISCORD_ACTIVITY_CLIENT_ID=1199271093882589195 bun run src/scripts/processSheet.js "Alien Roleplaying Game" ../../Alien\ Roleplaying\ Game/discord/production.css` - -### 2. Update sheet.json to indicate that this sheet has been updated for Discord - -Ensure that the following exists in the corresponding sheet.json for your sheet at the root level of the object: - -```json - "discord": { "fonts": true } -``` - -This is what will let those working on Discord know that a sheet has already had font proxying support added upstream per the working process documented here. So make sure that you commit and push this change to GitHub. - -### 3. Create and merge a pull request with your changes - -You'll now need to get these changes merged into the master branch: https://github.com/Roll20/roll20-character-sheets/pulls - -## Debug Logging - -Enable debug logging: -```bash -LOG_LEVEL=debug bun run src/scripts/processSheet.js "Sheet Name" ./output.css -``` \ No newline at end of file diff --git a/contrib/roll20-sheet-fonts/bun.lockb b/contrib/roll20-sheet-fonts/bun.lockb deleted file mode 100755 index 567237ef56302dfce52bfbce8c0d7d460df1e112..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2685 zcmY#Z)GsYA(of3F(@)JSQ%EY!;{sycoc!eMw9K4T-L(9o+{6;yG6OCq1_p*-;bIFW zxNM$jzIC@$^EDy9P4ZlC)-7q>_~G0Z=JTiBOx|(=6#)Sogks=8qZ^?7JeUG7UxQ&onYsr~!bL>^%tlf)G�WAbt#h(sE-l=@-+xZ1F;3r9U${So`i`5nRo$A zT`*9UHB>*y3`M-U5Rx$ci-1B_K>Z>>8WeT?1?dI3fmi@C17;44%>onyg#*kTAR5F60hk(OHg5I*`2WE)f^}1Y0Gh|h z05KQYXcjqUHLgXR9!#qiuUEaaWgFwlBauH1Gv^hUDYE9zP?+tn%6C3|deTO=(C@b9 zQvB(PEN2s9*yJDItv61||1d}D6q32H@Bq1%#pAK=o$`+RjYe?|I>yqLEBohtJaNIQ zKL3h{>ffnGSETt8yC>O*ObiiYd17&E*D}+b2VxQd%3<%_zD-%i`8GNn$y{b6@3U+? zdHDI2%mn+=V-?ztOvfhp?+V&@#ooLtH6yV{WY(RMC5Ox|6xZ9WF3C^~G&ssQ@o=$S z|BOr%X1i&u<%Ln&vyjXMg+C0is0H*`KVMkl#I-80aPlJgum+K^4CA*)tw@B94vL# z>Tp)MVmJ|K?oa_k$f;Be(hbmZ{|J=kvMDY~*2~N*E=kPE(SubwdLc!rsdfrR1`5TQ zRjK)DItnHVi8-0+dHHEvAjkas4*?)HDE)kZn#RHo5@BHAvMDt-vIAA;>^(^!Z85m%7AgpdrJz&)68G z)d6g=et9vJk(Zy6ipMx4RX_tligh8uZ)gHCtu!wsGdYu>XONWvjX~z>g5%7TfUn@L T2I?*^)&-{xa7aL+b?}h@Vy)oB diff --git a/contrib/roll20-sheet-fonts/package.json b/contrib/roll20-sheet-fonts/package.json deleted file mode 100644 index a6b6900deb..0000000000 --- a/contrib/roll20-sheet-fonts/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "roll20-sheet-fonts", - "version": "1.0.0", - "type": "module", - "scripts": { - "start": "bun run src/index.js", - "alienyz": "bun run src/scripts/processSheet.js \"Alien Roleplaying Game\" ./dist/alien.css" - }, - "dependencies": { - "loglevel": "^1.8.1" - }, - "devDependencies": { - "bun-types": "latest" - } -} \ No newline at end of file diff --git a/contrib/roll20-sheet-fonts/src/config.js b/contrib/roll20-sheet-fonts/src/config.js deleted file mode 100644 index ae2922cc4d..0000000000 --- a/contrib/roll20-sheet-fonts/src/config.js +++ /dev/null @@ -1,10 +0,0 @@ -if (!process.env.DISCORD_ACTIVITY_CLIENT_ID) { - throw new Error('DISCORD_ACTIVITY_CLIENT_ID environment variable is required'); -} - -export const CONFIG = { - DISCORD_ACTIVITY_CLIENT_ID: process.env.DISCORD_ACTIVITY_CLIENT_ID, - LOG_LEVEL: process.env.LOG_LEVEL || 'info', - GITHUB_BASE_URL: 'https://raw.githubusercontent.com/Roll20/roll20-character-sheets/refs/heads/master', - USER_AGENT: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' -}; \ No newline at end of file diff --git a/contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js b/contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js deleted file mode 100644 index a59642ab50..0000000000 --- a/contrib/roll20-sheet-fonts/src/lib/SheetFontsProcessor.js +++ /dev/null @@ -1,138 +0,0 @@ -// src/lib/SheetFontsProcessor.js -import log from 'loglevel'; -import { mkdir } from 'node:fs/promises'; -import { join } from 'path'; -import { CONFIG } from '../config.js'; - -export class SheetFontsProcessor { - constructor() { - this.clientId = CONFIG.DISCORD_ACTIVITY_CLIENT_ID; - this.baseGithubUrl = CONFIG.GITHUB_BASE_URL; - this.userAgent = CONFIG.USER_AGENT; - - // Initialize logger - this.log = log.getLogger('SheetFontsProcessor'); - this.log.setLevel(CONFIG.LOG_LEVEL); - } - - getSheetJsonUrl(sheetName) { - return `${this.baseGithubUrl}/${encodeURIComponent(sheetName)}/sheet.json`; - } - - getSheetCssUrl(sheetName, cssFilename) { - return `${this.baseGithubUrl}/${encodeURIComponent(sheetName)}/${cssFilename}`; - } - - extractGoogleFontsUrls(cssContent) { - const urls = []; - const lines = cssContent.split('\n'); - - for (const line of lines) { - if (line.trim().startsWith('/*')) continue; - - const match = line.match(/url\(['"]?(https:\/\/fonts\.googleapis\.com[^'")\s]+)['"]?\)/); - if (match) { - urls.push(match[1]); - } - } - - return urls; - } - - async ensureOutputDir() { - try { - await mkdir(this.outputDir, { recursive: true }); - } catch (error) { - this.log.error('Error creating output directory:', error); - throw error; - } - } - - async writeOutput(sheetName, content) { - try { - const sanitizedName = sheetName.replace(/[^a-z0-9]/gi, '-').toLowerCase(); - const outputPath = join(this.outputDir, `${sanitizedName}-fonts.css`); - - await this.ensureOutputDir(); - await Bun.write(outputPath, content); - - this.log.info(`Output written to: ${outputPath}`); - return outputPath; - } catch (error) { - this.log.error('Error writing output file:', error); - throw error; - } - } - - async fetchWithHeaders(url) { - try { - this.log.debug(`Fetching URL: ${url}`); - const response = await fetch(url, { - headers: { - 'User-Agent': this.userAgent - } - }); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - return await response.text(); - } catch (error) { - this.log.error(`Error fetching ${url}:`, error); - throw error; - } - } - - async transformGoogleFontsCss(fontsUrl) { - try { - this.log.debug(`Transforming fonts from: ${fontsUrl}`); - const cssContent = await this.fetchWithHeaders(fontsUrl); - return cssContent.replace( - /fonts\.gstatic\.com/g, - `${this.clientId}.discordsays.com/.proxy/gstatic/fonts` - ); - } catch (error) { - this.log.error(`Error transforming Google Fonts CSS from ${fontsUrl}:`, error); - return ''; - } - } - - // Remove outputDir-related methods as we're now handling file output in the script - async process(sheetName) { - try { - this.log.info(`Processing sheet: ${sheetName}`); - - const sheetJsonUrl = this.getSheetJsonUrl(sheetName); - const sheetDataText = await this.fetchWithHeaders(sheetJsonUrl); - const sheetData = JSON.parse(sheetDataText); - - const cssUrl = this.getSheetCssUrl(sheetName, sheetData.css); - const cssContent = await this.fetchWithHeaders(cssUrl); - - const fontUrls = this.extractGoogleFontsUrls(cssContent); - this.log.debug(`Found ${fontUrls.length} font URLs`); - - const transformedFontsCss = await Promise.all( - fontUrls.map(url => this.transformGoogleFontsCss(url)) - ); - - return { - originalUrls: fontUrls, - transformedCss: transformedFontsCss.join('\n\n'), - sheetData - }; - - } catch (error) { - this.log.error(`Error processing sheet ${sheetName}:`, error); - return { - originalUrls: [], - transformedCss: '', - sheetData: null, - error: error.message - }; - } -} -} - -export default SheetFontsProcessor; diff --git a/contrib/roll20-sheet-fonts/src/scripts/processSheet.js b/contrib/roll20-sheet-fonts/src/scripts/processSheet.js deleted file mode 100644 index ccb1966712..0000000000 --- a/contrib/roll20-sheet-fonts/src/scripts/processSheet.js +++ /dev/null @@ -1,51 +0,0 @@ -import log from 'loglevel'; -import { dirname } from 'path'; -import { mkdir } from 'node:fs/promises'; -import SheetFontsProcessor from '../lib/SheetFontsProcessor.js'; -import { CONFIG } from '../config.js'; - -// Configure root logger -log.setLevel(CONFIG.LOG_LEVEL); - -// Get command line arguments -const [,, sheetName, outputPath] = process.argv; - -if (!sheetName || !outputPath) { - log.error('Usage: bun run processSheet.js '); - process.exit(1); -} - -class FileProcessor { - static async ensureDir(filePath) { - await mkdir(dirname(filePath), { recursive: true }); - } - - static async process(sheetName, outputPath) { - try { - // Ensure output directory exists - await this.ensureDir(outputPath); - - const processor = new SheetFontsProcessor(); - - // Fetch and transform the CSS - const result = await processor.process(sheetName); - - if (result.error) { - throw new Error(result.error); - } - - // Write to specified path - await Bun.write(outputPath, result.transformedCss); - - log.info('Processing complete.'); - log.info('Output written to:', outputPath); - log.debug('Original Font URLs:', result.originalUrls); - - } catch (error) { - log.error('Processing failed:', error); - process.exit(1); - } - } -} - -await FileProcessor.process(sheetName, outputPath); diff --git a/contrib/roll20-sheet-fonts/tsconfig.json b/contrib/roll20-sheet-fonts/tsconfig.json deleted file mode 100644 index 2e668515bf..0000000000 --- a/contrib/roll20-sheet-fonts/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "lib": ["ESNext"], - "module": "esnext", - "target": "esnext", - "moduleResolution": "bundler", - "moduleDetection": "force", - "allowImportingTsExtensions": true, - "noEmit": true, - "composite": true, - "strict": true, - "downlevelIteration": true, - "skipLibCheck": true, - "jsx": "preserve", - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "allowJs": true, - "types": [ - "bun-types" - ] - } -} diff --git a/process-fonts.sh b/process-fonts.sh new file mode 100755 index 0000000000..2dbc053c93 --- /dev/null +++ b/process-fonts.sh @@ -0,0 +1,165 @@ +#!/bin/zsh + +setopt ERR_EXIT +setopt PIPE_FAIL +setopt NO_UNSET + +if [[ -z "${DISCORD_ACTIVITY_CLIENT_ID}" ]]; then + print "Error: DISCORD_ACTIVITY_CLIENT_ID environment variable is required" >&2 + exit 1 +fi + +# Process arguments +test_mode=0 +no_prompt=0 +output_file="fonts.css" + +while [[ $# -gt 0 ]]; do + case $1 in + --test) + test_mode=1 + shift + ;; + --no-prompt) + no_prompt=1 + shift + ;; + *) + output_file="$1" + shift + ;; + esac +done + +print "Starting directory search..." >&2 + +# Get directories +dirs=(*(/)) +dirs=(${dirs:#contrib}) # Exclude contrib +dirs=(${dirs:#.git}) # Exclude .git +dirs=(${dirs:#node_modules}) # Exclude node_modules + +if [[ ${#dirs} -eq 0 ]]; then + print "No directories found!" >&2 + exit 1 +fi + +if [[ $test_mode -eq 1 ]]; then + print "Test mode: processing first 5 directories" >&2 + dirs=(${dirs[1,5]}) +fi + +print "\nFound directories:" >&2 +print -l " ${dirs[@]}" >&2 + +# First collect all URLs +urls_file=$(mktemp) +trap "rm -f '$urls_file'" EXIT + +extract_font_urls() { + perl -ne ' + next if /^\s*\/\*/; # Skip comment lines + while (/url\(['"'"'"]?(https:\/\/fonts\.googleapis\.com[^'"'"'"\s\)]+)['"'"'"]?\)/g) { + print "$1\n"; + } + ' "$1" +} + +# Process each directory to collect URLs +for dir in ${dirs[@]}; do + print "Checking directory: $dir" >&2 + + # Find CSS files directly in this directory + css_files=($dir/*.css(.N)) + + if [[ ${#css_files} -gt 0 ]]; then + print "Found CSS files in $dir:" >&2 + print -l " ${css_files[@]}" >&2 + + for css_file in ${css_files[@]}; do + print "Processing: $css_file" >&2 + + found_urls=$(extract_font_urls "$css_file") + + if [[ -n "$found_urls" ]]; then + print "Found font URLs in $css_file:" >&2 + print -l " $found_urls" >&2 + print "$found_urls" >> "$urls_file" + fi + done + else + print "No CSS files found in $dir" >&2 + fi +done + +# Get unique URLs and show summary +unique_urls=($(sort -u "$urls_file")) +total_urls=${#unique_urls} + +if [[ $total_urls -eq 0 ]]; then + print "No Google Font URLs found" >&2 + exit 1 +fi + +print "\nFound $total_urls unique Google Font URLs:" >&2 +print -l " ${unique_urls[@]}" >&2 + +if [[ $no_prompt -eq 0 ]]; then + print "\nProceed with fetching and transforming these URLs? [y/N] " >&2 + read -q response || true + print >&2 + + if [[ "$response" != "y" ]]; then + print "Operation cancelled" >&2 + exit 0 + fi +fi + +# Create temporary files for the transformed CSS +raw_file=$(mktemp) +temp_file=$(mktemp) +trap "rm -f '$temp_file' '$urls_file' '$raw_file'" EXIT + +# Process each unique URL +for font_url in $unique_urls; do + response=$(curl -sS -w "\n%{http_code}" -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" \ + "$font_url") + + if [[ $? -eq 0 ]]; then + http_code=$(print "$response" | tail -n1) + content=$(print "$response" | sed '$d') + + if [[ "$http_code" = "200" ]]; then + print "$content" >> "$raw_file" + print >> "$raw_file" # Add newline between font definitions + else + print "Error: HTTP $http_code for $font_url" >&2 + fi + else + print "Error: Failed to fetch $font_url" >&2 + fi +done + +# Deduplicate font declarations and transform URLs +if [[ -s "$raw_file" ]]; then + # Extract unique @font-face blocks and transform URLs + perl -0777 -ne ' + while (/(\@font-face\s*\{[^}]+\})/gs) { + $block = $1; + $seen{$block}++ or print "$block\n\n"; + } + ' "$raw_file" | \ + sed "s/fonts\.gstatic\.com/${DISCORD_ACTIVITY_CLIENT_ID}.discordsays.com\/.proxy\/gstatic\/fonts/g" \ + > "$temp_file" + + if [[ -s "$temp_file" ]]; then + mv "$temp_file" "$output_file" + print "Generated $output_file" >&2 + else + print "Error: No valid font definitions found after deduplication" >&2 + exit 1 + fi +else + print "Error: No valid font definitions found" >&2 + exit 1 +fi From e11d8407c9bb62ab3d29cd5a29b54d08bbac9e88 Mon Sep 17 00:00:00 2001 From: Daniel Vu Date: Fri, 8 Nov 2024 19:52:05 -0500 Subject: [PATCH 5/8] Removes deprecated code --- Alien Roleplaying Game/discord/production.css | 192 ------------------ Alien Roleplaying Game/discord/staging.css | 192 ------------------ Alien Roleplaying Game/sheet.json | 29 ++- 3 files changed, 14 insertions(+), 399 deletions(-) delete mode 100644 Alien Roleplaying Game/discord/production.css delete mode 100644 Alien Roleplaying Game/discord/staging.css diff --git a/Alien Roleplaying Game/discord/production.css b/Alien Roleplaying Game/discord/production.css deleted file mode 100644 index bbbb505421..0000000000 --- a/Alien Roleplaying Game/discord/production.css +++ /dev/null @@ -1,192 +0,0 @@ -/* latin-ext */ -@font-face { - font-family: 'Courier Prime'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/courierprime/v9/u-450q2lgwslOqpF_6gQ8kELaw9pWt_-.woff2) format('woff2'); - unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Courier Prime'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/courierprime/v9/u-450q2lgwslOqpF_6gQ8kELawFpWg.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* latin */ -@font-face { - font-family: 'Graduate'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/graduate/v17/C8cg4cs3o2n15t_2YygW43w.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* fallback */ -@font-face { - font-family: 'Material Icons'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/materialicons/v142/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2'); -} -/* fallback */ -@font-face { - font-family: 'Material Symbols Outlined'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/materialsymbolsoutlined/v215/kJF1BvYX7BgnkSrUwT8OhrdQw4oELdPIeeII9v6oDMzByHX9rA6RzaxHMPdY43zj-jCxv3fzvRNU22ZXGJpEpjC_1v-p_4MrImHCIJIZrDCvHOej.woff2) format('woff2'); -} -/* cyrillic-ext */ -@font-face { - font-family: 'Montserrat'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw0aXpsog.woff2) format('woff2'); - unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; -} -/* cyrillic */ -@font-face { - font-family: 'Montserrat'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw9aXpsog.woff2) format('woff2'); - unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; -} -/* vietnamese */ -@font-face { - font-family: 'Montserrat'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw2aXpsog.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; -} -/* latin-ext */ -@font-face { - font-family: 'Montserrat'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw3aXpsog.woff2) format('woff2'); - unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Montserrat'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw5aXo.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* cyrillic-ext */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu72xKOzY.woff2) format('woff2'); - unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; -} -/* cyrillic */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu5mxKOzY.woff2) format('woff2'); - unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; -} -/* greek-ext */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu7mxKOzY.woff2) format('woff2'); - unicode-range: U+1F00-1FFF; -} -/* greek */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu4WxKOzY.woff2) format('woff2'); - unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; -} -/* vietnamese */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu7WxKOzY.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; -} -/* latin-ext */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu7GxKOzY.woff2) format('woff2'); - unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu4mxK.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* latin */ -@font-face { - font-family: 'Share Tech Mono'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199271093882589195.discordsays.com/.proxy/gstatic/fonts/s/sharetechmono/v15/J7aHnp1uDWRBEqV98dVQztYldFcLowEF.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} - -.material-icons { - font-family: 'Material Icons'; - font-weight: normal; - font-style: normal; - font-size: 24px; - line-height: 1; - letter-spacing: normal; - text-transform: none; - display: inline-block; - white-space: nowrap; - word-wrap: normal; - direction: ltr; - -webkit-font-feature-settings: 'liga'; - -webkit-font-smoothing: antialiased; -} - -.material-symbols-outlined { - font-family: 'Material Symbols Outlined'; - font-weight: normal; - font-style: normal; - font-size: 24px; - line-height: 1; - letter-spacing: normal; - text-transform: none; - display: inline-block; - white-space: nowrap; - word-wrap: normal; - direction: ltr; - -webkit-font-feature-settings: 'liga'; - -webkit-font-smoothing: antialiased; -} diff --git a/Alien Roleplaying Game/discord/staging.css b/Alien Roleplaying Game/discord/staging.css deleted file mode 100644 index 1e3bb37d1c..0000000000 --- a/Alien Roleplaying Game/discord/staging.css +++ /dev/null @@ -1,192 +0,0 @@ -/* latin-ext */ -@font-face { - font-family: 'Courier Prime'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/courierprime/v9/u-450q2lgwslOqpF_6gQ8kELaw9pWt_-.woff2) format('woff2'); - unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Courier Prime'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/courierprime/v9/u-450q2lgwslOqpF_6gQ8kELawFpWg.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* latin */ -@font-face { - font-family: 'Graduate'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/graduate/v17/C8cg4cs3o2n15t_2YygW43w.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* fallback */ -@font-face { - font-family: 'Material Icons'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/materialicons/v142/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2'); -} -/* fallback */ -@font-face { - font-family: 'Material Symbols Outlined'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/materialsymbolsoutlined/v215/kJF1BvYX7BgnkSrUwT8OhrdQw4oELdPIeeII9v6oDMzByHX9rA6RzaxHMPdY43zj-jCxv3fzvRNU22ZXGJpEpjC_1v-p_4MrImHCIJIZrDCvHOej.woff2) format('woff2'); -} -/* cyrillic-ext */ -@font-face { - font-family: 'Montserrat'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw0aXpsog.woff2) format('woff2'); - unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; -} -/* cyrillic */ -@font-face { - font-family: 'Montserrat'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw9aXpsog.woff2) format('woff2'); - unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; -} -/* vietnamese */ -@font-face { - font-family: 'Montserrat'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw2aXpsog.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; -} -/* latin-ext */ -@font-face { - font-family: 'Montserrat'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw3aXpsog.woff2) format('woff2'); - unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Montserrat'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw5aXo.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* cyrillic-ext */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu72xKOzY.woff2) format('woff2'); - unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; -} -/* cyrillic */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu5mxKOzY.woff2) format('woff2'); - unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; -} -/* greek-ext */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu7mxKOzY.woff2) format('woff2'); - unicode-range: U+1F00-1FFF; -} -/* greek */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu4WxKOzY.woff2) format('woff2'); - unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; -} -/* vietnamese */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu7WxKOzY.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; -} -/* latin-ext */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu7GxKOzY.woff2) format('woff2'); - unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/roboto/v32/KFOmCnqEu92Fr1Mu4mxK.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* latin */ -@font-face { - font-family: 'Share Tech Mono'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url(https://1199270539278164008.discordsays.com/.proxy/gstatic/fonts/s/sharetechmono/v15/J7aHnp1uDWRBEqV98dVQztYldFcLowEF.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} - -.material-icons { - font-family: 'Material Icons'; - font-weight: normal; - font-style: normal; - font-size: 24px; - line-height: 1; - letter-spacing: normal; - text-transform: none; - display: inline-block; - white-space: nowrap; - word-wrap: normal; - direction: ltr; - -webkit-font-feature-settings: 'liga'; - -webkit-font-smoothing: antialiased; -} - -.material-symbols-outlined { - font-family: 'Material Symbols Outlined'; - font-weight: normal; - font-style: normal; - font-size: 24px; - line-height: 1; - letter-spacing: normal; - text-transform: none; - display: inline-block; - white-space: nowrap; - word-wrap: normal; - direction: ltr; - -webkit-font-feature-settings: 'liga'; - -webkit-font-smoothing: antialiased; -} diff --git a/Alien Roleplaying Game/sheet.json b/Alien Roleplaying Game/sheet.json index 0fcc3dadf6..6bc7220849 100644 --- a/Alien Roleplaying Game/sheet.json +++ b/Alien Roleplaying Game/sheet.json @@ -14,7 +14,7 @@ "displayname": "Enable API rolls", "displaytranslationkey": "config-enable-apirolls", "description": "When enabled, rolls will be using the API script for Alien RPG, allowing for in-chat pushing of rolls. The script needs to be added to the game, obviously.", - "descriptiontranslationkey": "config-enable-apirolls-desc" + "descriptiontranslationkey": "config-enable-apirolls-desc" }, { "attribute": "config_advencumbrance", @@ -24,7 +24,7 @@ "displayname": "Enable weights and calculated encumbrance", "displaytranslationkey": "config-enable-encumbrance" , "description": "Adds fields Wt (weight), # (amount) and Enc (encumbrance) to the Gear list, as well as a Weight option for weapons. Every 4 items of Food or Water in the Consumables section will count as 1 item.", - "descriptiontranslationkey": "config-enable-encumbrance-desc" + "descriptiontranslationkey": "config-enable-encumbrance-desc" }, { "attribute": "config_gearrepeatingonly", @@ -33,7 +33,7 @@ "displayname": "Only use repeating section for Gear", "displaytranslationkey": "config-gearrepeatingonly", "description": "This will remove the static 1 - 8 rows in the Gear list, and only rely on the addition of dynamic rows. Enabling this will not delete or remove the data in the static rows. NB, the static list rows still count towards the encumbrance calculation!", - "descriptiontranslationkey": "config-gearrepeatingonly-desc" + "descriptiontranslationkey": "config-gearrepeatingonly-desc" }, { "attribute": "config_healthcalculation", @@ -43,7 +43,7 @@ "displayname": "Use automatically calculated Health", "displaytranslationkey": "config-healthcalculation", "description":"The health is calculated automatically using the Strength attribute and the Tough talent (checkbox on sheet). Only the number of health bar boxes up to the calculated health is shown.", - "descriptiontranslationkey": "config-healthcalculation-desc" + "descriptiontranslationkey": "config-healthcalculation-desc" }, { "attribute": "config_squareinput", @@ -53,7 +53,7 @@ "displayname": "Use squarer input boxes", "displaytranslationkey": "config-squareinput", "description": "Use squares with rounded corners instead of the circular input fields. Changing this has no effect on the data in the fields, it is only decorative", - "descriptiontranslationkey": "config-squareinput-desc" + "descriptiontranslationkey": "config-squareinput-desc" }, { "attribute": "config_optionalspinners", @@ -63,7 +63,7 @@ "displayname": "Use spinners in number input fields", "displaytranslationkey": "config-optionalspinners", "description": "When enabled up and down arrows (spinner) will appear when hovering over number fields, to make small increases or decreases easier (attributes excempted).", - "descriptiontranslationkey": "config-optionalspinners-desc" + "descriptiontranslationkey": "config-optionalspinners-desc" }, { "attribute": "config_spacebackground", @@ -73,7 +73,7 @@ "displayname": "Use space background", "displaytranslationkey": "config-spacebackground", "description": "If enabled will set the background to space with stars, disabled just black colour", - "descriptiontranslationkey": "config-spacebackground-desc" + "descriptiontranslationkey": "config-spacebackground-desc" }, { "attribute": "config_initiativedice", @@ -81,7 +81,7 @@ "displayname": "Dice to roll for initiative", "displaytranslationkey": "config-initiativedice", "description": "When rolling for initiative as an alternative to drawing cards, you can select which size of dice to use", - "descriptiontranslationkey": "config-initiativedice-desc", + "descriptiontranslationkey": "config-initiativedice-desc", "options": [ "2d6|2d6", "1d10|1d10", @@ -94,7 +94,7 @@ "dice-1d12", "dice-1d20" ], - "default": "1d10" + "default": "1d10" }, { "attribute": "config_panicdesc", @@ -104,7 +104,7 @@ "displayname": "Include panic descriptions in rolls", "displaytranslationkey": "config-panicdesc", "description": "When enabled, this will include the description of the panic effect of the specific roll", - "descriptiontranslationkey": "config-panicdesc-desc" + "descriptiontranslationkey": "config-panicdesc-desc" }, { "attribute": "config_modifierquery", @@ -114,7 +114,7 @@ "displayname": "Use modifier query popup for rolls", "displaytranslationkey": "modifierquery-desc", "description": "When enabled, this will activate the popup asking for modifiers for each roll.", - "descriptiontranslationkey": "modifierquery-info" + "descriptiontranslationkey": "modifierquery-info" }, { "attribute": "config_permanentmods", @@ -124,8 +124,7 @@ "displayname": "Permanent modifiers enabled", "displaytranslationkey": "config-perm-modifier-label", "description": "Provides an option to add a modifier to all rolls for each skill, and represents bonuses from gear or talents.", - "descriptiontranslationkey": "config-perm-modifier-desc" + "descriptiontranslationkey": "config-perm-modifier-desc" } - ], - "discord": {"fonts": true } -} \ No newline at end of file + ] +} From 550e5532970b0bef65fb45c637e6519b09dfca50 Mon Sep 17 00:00:00 2001 From: Daniel Vu Date: Wed, 13 Nov 2024 08:09:44 -0500 Subject: [PATCH 6/8] Fixes unwanted font weights being used for Alien sheet in Discord --- .github/workflows/discord-fonts.yml | 19 ++-- process-fonts.sh | 131 ++++++++++++---------------- 2 files changed, 65 insertions(+), 85 deletions(-) diff --git a/.github/workflows/discord-fonts.yml b/.github/workflows/discord-fonts.yml index c00ffdd4b1..8e7d208cac 100644 --- a/.github/workflows/discord-fonts.yml +++ b/.github/workflows/discord-fonts.yml @@ -31,21 +31,16 @@ jobs: chmod +x ./process-fonts.sh CLIENT_ID=${{ github.ref_name == 'master' && '1199271093882589195' || '1199270539278164008' }} DISCORD_ACTIVITY_CLIENT_ID=$CLIENT_ID \ - ./process-fonts.sh --no-prompt fonts.css + ./process-fonts.sh --no-prompt --output-dir ${{ runner.temp }}/sheet-fonts - name: Upload to GCS run: | - DEST_NAME="${{ github.ref_name == 'master' && 'production' || 'staging' }}.css" + ENV_PATH="${{ github.ref_name == 'master' && 'production' || 'staging' }}" - # Create temp directory and copy fonts.css to it - TEMP_DIR="${{ runner.temp }}/fonts" - mkdir -p "$TEMP_DIR" - cp fonts.css "$TEMP_DIR/$DEST_NAME" - - # Sync to GCS + # Sync the entire fonts directory gcloud storage rsync \ --project=roll20-actual \ - "$TEMP_DIR" \ - gs://roll20-cdn/discord/fonts \ - --cache-control='no-cache' \ - --recursive + ${{ runner.temp }}/sheet-fonts \ + "gs://roll20-cdn/discord/fonts/$ENV_PATH" \ + --recursive \ + --cache-control="no-cache" \ No newline at end of file diff --git a/process-fonts.sh b/process-fonts.sh index 2dbc053c93..0ecbaf7ce7 100755 --- a/process-fonts.sh +++ b/process-fonts.sh @@ -12,7 +12,7 @@ fi # Process arguments test_mode=0 no_prompt=0 -output_file="fonts.css" +output_dir="/tmp/discord-fonts" while [[ $# -gt 0 ]]; do case $1 in @@ -24,13 +24,22 @@ while [[ $# -gt 0 ]]; do no_prompt=1 shift ;; + --output-dir) + output_dir="$2" + shift 2 + ;; *) - output_file="$1" shift ;; esac done +# Clean/create output directory +if [[ -d "$output_dir" ]]; then + rm -rf "$output_dir" +fi +mkdir -p "$output_dir" + print "Starting directory search..." >&2 # Get directories @@ -52,10 +61,7 @@ fi print "\nFound directories:" >&2 print -l " ${dirs[@]}" >&2 -# First collect all URLs -urls_file=$(mktemp) -trap "rm -f '$urls_file'" EXIT - +# Extract URLs function extract_font_urls() { perl -ne ' next if /^\s*\/\*/; # Skip comment lines @@ -65,7 +71,7 @@ extract_font_urls() { ' "$1" } -# Process each directory to collect URLs +# Process each directory for dir in ${dirs[@]}; do print "Checking directory: $dir" >&2 @@ -76,6 +82,10 @@ for dir in ${dirs[@]}; do print "Found CSS files in $dir:" >&2 print -l " ${css_files[@]}" >&2 + # Collect URLs for this directory + urls_file=$(mktemp) + trap "rm -f '$urls_file'" EXIT + for css_file in ${css_files[@]}; do print "Processing: $css_file" >&2 @@ -87,79 +97,54 @@ for dir in ${dirs[@]}; do print "$found_urls" >> "$urls_file" fi done - else - print "No CSS files found in $dir" >&2 - fi -done -# Get unique URLs and show summary -unique_urls=($(sort -u "$urls_file")) -total_urls=${#unique_urls} + # If we found URLs in this directory + unique_urls=($(sort -u "$urls_file")) + if [[ ${#unique_urls} -gt 0 ]]; then + print "\nFound ${#unique_urls} unique font URLs in $dir" >&2 -if [[ $total_urls -eq 0 ]]; then - print "No Google Font URLs found" >&2 - exit 1 -fi + if [[ $no_prompt -eq 0 ]]; then + print "Proceed with fetching and transforming URLs for $dir? [y/N] " >&2 + read -q response || true + print >&2 -print "\nFound $total_urls unique Google Font URLs:" >&2 -print -l " ${unique_urls[@]}" >&2 + if [[ "$response" != "y" ]]; then + print "Skipping $dir" >&2 + continue + fi + fi -if [[ $no_prompt -eq 0 ]]; then - print "\nProceed with fetching and transforming these URLs? [y/N] " >&2 - read -q response || true - print >&2 + raw_file=$(mktemp) + trap "rm -f '$raw_file'" EXIT - if [[ "$response" != "y" ]]; then - print "Operation cancelled" >&2 - exit 0 - fi -fi + # Process URLs for this directory + for font_url in $unique_urls; do + response=$(curl -sS -w "\n%{http_code}" -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" \ + "$font_url") -# Create temporary files for the transformed CSS -raw_file=$(mktemp) -temp_file=$(mktemp) -trap "rm -f '$temp_file' '$urls_file' '$raw_file'" EXIT + if [[ $? -eq 0 ]]; then + http_code=$(print "$response" | tail -n1) + content=$(print "$response" | sed '$d') -# Process each unique URL -for font_url in $unique_urls; do - response=$(curl -sS -w "\n%{http_code}" -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" \ - "$font_url") + if [[ "$http_code" = "200" ]]; then + print "$content" | \ + sed "s/fonts\.gstatic\.com/${DISCORD_ACTIVITY_CLIENT_ID}.discordsays.com\/.proxy\/gstatic\/fonts/g" \ + >> "$raw_file" + print >> "$raw_file" + else + print "Error: HTTP $http_code for $font_url" >&2 + fi + else + print "Error: Failed to fetch $font_url" >&2 + fi + done - if [[ $? -eq 0 ]]; then - http_code=$(print "$response" | tail -n1) - content=$(print "$response" | sed '$d') - - if [[ "$http_code" = "200" ]]; then - print "$content" >> "$raw_file" - print >> "$raw_file" # Add newline between font definitions - else - print "Error: HTTP $http_code for $font_url" >&2 + if [[ -s "$raw_file" ]]; then + # Create directory for this sheet + mkdir -p "$output_dir/$dir" + mv "$raw_file" "$output_dir/$dir/fonts.css" + print "Generated fonts.css for $dir" >&2 + fi fi - else - print "Error: Failed to fetch $font_url" >&2 fi -done - -# Deduplicate font declarations and transform URLs -if [[ -s "$raw_file" ]]; then - # Extract unique @font-face blocks and transform URLs - perl -0777 -ne ' - while (/(\@font-face\s*\{[^}]+\})/gs) { - $block = $1; - $seen{$block}++ or print "$block\n\n"; - } - ' "$raw_file" | \ - sed "s/fonts\.gstatic\.com/${DISCORD_ACTIVITY_CLIENT_ID}.discordsays.com\/.proxy\/gstatic\/fonts/g" \ - > "$temp_file" - - if [[ -s "$temp_file" ]]; then - mv "$temp_file" "$output_file" - print "Generated $output_file" >&2 - else - print "Error: No valid font definitions found after deduplication" >&2 - exit 1 - fi -else - print "Error: No valid font definitions found" >&2 - exit 1 -fi +done \ No newline at end of file From 2a6f5eef77972127f42fcb6d7a6db4b03aa14a78 Mon Sep 17 00:00:00 2001 From: Daniel Vu Date: Wed, 13 Nov 2024 12:29:04 -0500 Subject: [PATCH 7/8] Ensures that fonts.css always exists --- process-fonts.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/process-fonts.sh b/process-fonts.sh index 0ecbaf7ce7..552009c47c 100755 --- a/process-fonts.sh +++ b/process-fonts.sh @@ -74,6 +74,7 @@ extract_font_urls() { # Process each directory for dir in ${dirs[@]}; do print "Checking directory: $dir" >&2 + mkdir -p "$output_dir/$dir" # Find CSS files directly in this directory css_files=($dir/*.css(.N)) @@ -110,6 +111,7 @@ for dir in ${dirs[@]}; do if [[ "$response" != "y" ]]; then print "Skipping $dir" >&2 + touch "$output_dir/$dir/fonts.css" continue fi fi @@ -140,11 +142,18 @@ for dir in ${dirs[@]}; do done if [[ -s "$raw_file" ]]; then - # Create directory for this sheet - mkdir -p "$output_dir/$dir" mv "$raw_file" "$output_dir/$dir/fonts.css" print "Generated fonts.css for $dir" >&2 + else + touch "$output_dir/$dir/fonts.css" + print "Generated empty fonts.css for $dir (no valid content)" >&2 fi + else + touch "$output_dir/$dir/fonts.css" + print "Generated empty fonts.css for $dir (no URLs found)" >&2 fi + else + touch "$output_dir/$dir/fonts.css" + print "Generated empty fonts.css for $dir (no CSS files)" >&2 fi done \ No newline at end of file From 2f2330486679e2aabe0cde295fa52b2ed5c009ea Mon Sep 17 00:00:00 2001 From: Daniel Vu Date: Thu, 14 Nov 2024 12:26:42 -0500 Subject: [PATCH 8/8] Reduces PR diff --- Alien Roleplaying Game/sheet.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Alien Roleplaying Game/sheet.json b/Alien Roleplaying Game/sheet.json index 6bc7220849..d8258a15dc 100644 --- a/Alien Roleplaying Game/sheet.json +++ b/Alien Roleplaying Game/sheet.json @@ -14,7 +14,7 @@ "displayname": "Enable API rolls", "displaytranslationkey": "config-enable-apirolls", "description": "When enabled, rolls will be using the API script for Alien RPG, allowing for in-chat pushing of rolls. The script needs to be added to the game, obviously.", - "descriptiontranslationkey": "config-enable-apirolls-desc" + "descriptiontranslationkey": "config-enable-apirolls-desc" }, { "attribute": "config_advencumbrance", @@ -24,7 +24,7 @@ "displayname": "Enable weights and calculated encumbrance", "displaytranslationkey": "config-enable-encumbrance" , "description": "Adds fields Wt (weight), # (amount) and Enc (encumbrance) to the Gear list, as well as a Weight option for weapons. Every 4 items of Food or Water in the Consumables section will count as 1 item.", - "descriptiontranslationkey": "config-enable-encumbrance-desc" + "descriptiontranslationkey": "config-enable-encumbrance-desc" }, { "attribute": "config_gearrepeatingonly", @@ -33,7 +33,7 @@ "displayname": "Only use repeating section for Gear", "displaytranslationkey": "config-gearrepeatingonly", "description": "This will remove the static 1 - 8 rows in the Gear list, and only rely on the addition of dynamic rows. Enabling this will not delete or remove the data in the static rows. NB, the static list rows still count towards the encumbrance calculation!", - "descriptiontranslationkey": "config-gearrepeatingonly-desc" + "descriptiontranslationkey": "config-gearrepeatingonly-desc" }, { "attribute": "config_healthcalculation", @@ -43,7 +43,7 @@ "displayname": "Use automatically calculated Health", "displaytranslationkey": "config-healthcalculation", "description":"The health is calculated automatically using the Strength attribute and the Tough talent (checkbox on sheet). Only the number of health bar boxes up to the calculated health is shown.", - "descriptiontranslationkey": "config-healthcalculation-desc" + "descriptiontranslationkey": "config-healthcalculation-desc" }, { "attribute": "config_squareinput", @@ -53,7 +53,7 @@ "displayname": "Use squarer input boxes", "displaytranslationkey": "config-squareinput", "description": "Use squares with rounded corners instead of the circular input fields. Changing this has no effect on the data in the fields, it is only decorative", - "descriptiontranslationkey": "config-squareinput-desc" + "descriptiontranslationkey": "config-squareinput-desc" }, { "attribute": "config_optionalspinners", @@ -63,7 +63,7 @@ "displayname": "Use spinners in number input fields", "displaytranslationkey": "config-optionalspinners", "description": "When enabled up and down arrows (spinner) will appear when hovering over number fields, to make small increases or decreases easier (attributes excempted).", - "descriptiontranslationkey": "config-optionalspinners-desc" + "descriptiontranslationkey": "config-optionalspinners-desc" }, { "attribute": "config_spacebackground", @@ -73,7 +73,7 @@ "displayname": "Use space background", "displaytranslationkey": "config-spacebackground", "description": "If enabled will set the background to space with stars, disabled just black colour", - "descriptiontranslationkey": "config-spacebackground-desc" + "descriptiontranslationkey": "config-spacebackground-desc" }, { "attribute": "config_initiativedice", @@ -81,7 +81,7 @@ "displayname": "Dice to roll for initiative", "displaytranslationkey": "config-initiativedice", "description": "When rolling for initiative as an alternative to drawing cards, you can select which size of dice to use", - "descriptiontranslationkey": "config-initiativedice-desc", + "descriptiontranslationkey": "config-initiativedice-desc", "options": [ "2d6|2d6", "1d10|1d10", @@ -94,7 +94,7 @@ "dice-1d12", "dice-1d20" ], - "default": "1d10" + "default": "1d10" }, { "attribute": "config_panicdesc", @@ -104,7 +104,7 @@ "displayname": "Include panic descriptions in rolls", "displaytranslationkey": "config-panicdesc", "description": "When enabled, this will include the description of the panic effect of the specific roll", - "descriptiontranslationkey": "config-panicdesc-desc" + "descriptiontranslationkey": "config-panicdesc-desc" }, { "attribute": "config_modifierquery", @@ -114,7 +114,7 @@ "displayname": "Use modifier query popup for rolls", "displaytranslationkey": "modifierquery-desc", "description": "When enabled, this will activate the popup asking for modifiers for each roll.", - "descriptiontranslationkey": "modifierquery-info" + "descriptiontranslationkey": "modifierquery-info" }, { "attribute": "config_permanentmods", @@ -124,7 +124,7 @@ "displayname": "Permanent modifiers enabled", "displaytranslationkey": "config-perm-modifier-label", "description": "Provides an option to add a modifier to all rolls for each skill, and represents bonuses from gear or talents.", - "descriptiontranslationkey": "config-perm-modifier-desc" + "descriptiontranslationkey": "config-perm-modifier-desc" } - ] -} + ] +} \ No newline at end of file