1817 lines
48 KiB
JavaScript
Executable File
1817 lines
48 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
||
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
const { promisify } = require('util');
|
||
|
||
const readFile = promisify(fs.readFile);
|
||
const writeFile = promisify(fs.writeFile);
|
||
const readdir = promisify(fs.readdir);
|
||
const stat = promisify(fs.stat);
|
||
|
||
// Configuration
|
||
const config = {
|
||
postsDirectory: './src/data/post',
|
||
assetsDirectory: './src/assets/images',
|
||
backupDirectory: './blog-posts-backup',
|
||
logFile: './fix-blog-posts.log'
|
||
};
|
||
|
||
// Logging utility
|
||
class Logger {
|
||
constructor(logFile) {
|
||
this.logFile = logFile;
|
||
this.logs = [];
|
||
}
|
||
|
||
log(level, message, file = null) {
|
||
const timestamp = new Date().toISOString();
|
||
const logEntry = {
|
||
timestamp,
|
||
level,
|
||
message,
|
||
file
|
||
};
|
||
|
||
this.logs.push(logEntry);
|
||
|
||
const logString = file
|
||
? `[${timestamp}] ${level.toUpperCase()}: ${message} (${file})`
|
||
: `[${timestamp}] ${level.toUpperCase()}: ${message}`;
|
||
|
||
console.log(logString);
|
||
}
|
||
|
||
async saveLogs() {
|
||
const logContent = this.logs.map(entry =>
|
||
entry.file
|
||
? `[${entry.timestamp}] ${entry.level.toUpperCase()}: ${entry.message} (${entry.file})`
|
||
: `[${entry.timestamp}] ${entry.level.toUpperCase()}: ${entry.message}`
|
||
).join('\n');
|
||
|
||
await writeFile(this.logFile, logContent);
|
||
console.log(`\nLogs saved to ${this.logFile}`);
|
||
}
|
||
}
|
||
|
||
// HTML entities mapping
|
||
const htmlEntities = {
|
||
// Common HTML entities
|
||
'&': '&',
|
||
'<': '<',
|
||
'>': '>',
|
||
'"': '"',
|
||
''': "'",
|
||
' ': ' ',
|
||
|
||
// Extended HTML entities
|
||
'©': '©',
|
||
'®': '®',
|
||
'™': '™',
|
||
'…': '…',
|
||
'—': '—',
|
||
'–': '–',
|
||
'“': '"',
|
||
'”': '"',
|
||
'‘': '\u2018',
|
||
'’': '\u2019',
|
||
'•': '•',
|
||
'·': '·',
|
||
'§': '§',
|
||
'¶': '¶',
|
||
'†': '†',
|
||
'‡': '‡',
|
||
'‰': '‰',
|
||
'‹': '‹',
|
||
'›': '›',
|
||
'€': '€',
|
||
'£': '£',
|
||
'¥': '¥',
|
||
'¢': '¢',
|
||
'¤': '¤',
|
||
|
||
// Common Unicode entities
|
||
'🎯': '🎯',
|
||
'📡': '📡',
|
||
'📱': '📱',
|
||
'📺': '📺',
|
||
'📻': '📻',
|
||
'📞': '📞',
|
||
'📟': '📟',
|
||
'📢': '📢',
|
||
'📣': '📣',
|
||
'📤': '📤',
|
||
'📥': '📥',
|
||
'📦': '📦',
|
||
'📧': '📧',
|
||
'📨': '📨',
|
||
'📩': '📩',
|
||
'📪': '📪',
|
||
'📫': '📫',
|
||
'📬': '📬',
|
||
'📭': '📭',
|
||
'📮': '📮',
|
||
'📯': '📯',
|
||
'📰': '📰',
|
||
'📲': '📲',
|
||
'📳': '📳',
|
||
'📴': '📴',
|
||
'📵': '📵',
|
||
'📶': '📶',
|
||
'📷': '📷',
|
||
'📸': '📸',
|
||
'📹': '📹',
|
||
'📼': '📼',
|
||
'📽': '📽',
|
||
'📿': '📿',
|
||
'🔀': '🔀',
|
||
'🔁': '🔁',
|
||
'🔂': '🔂',
|
||
'🔃': '🔃',
|
||
'🔄': '🔄',
|
||
'🔅': '🔅',
|
||
'🔆': '🔆',
|
||
'🔇': '🔇',
|
||
'🔈': '🔈',
|
||
'🔉': '🔉',
|
||
'🔊': '🔊',
|
||
'🔋': '🔋',
|
||
'🔌': '🔌',
|
||
'🔍': '🔍',
|
||
'🔎': '🔎',
|
||
'🔏': '🔏',
|
||
'🔐': '🔐',
|
||
'🔑': '🔑',
|
||
'🔒': '🔒',
|
||
'🔓': '🔓',
|
||
'🔔': '🔔',
|
||
'🔕': '🔕',
|
||
'🔖': '🔖',
|
||
'🔗': '🔗',
|
||
'🔘': '🔘',
|
||
'🔙': '🔙',
|
||
'🔚': '🔚',
|
||
'🔛': '🔛',
|
||
'🔜': '🔜',
|
||
'🔝': '🔝',
|
||
'🔞': '🔞',
|
||
'🔟': '🔟',
|
||
'🔠': '🔠',
|
||
'🔡': '🔡',
|
||
'🔢': '🔢',
|
||
'🔣': '🔣',
|
||
'🔤': '🔤',
|
||
'🔥': '🔥',
|
||
'🔦': '🔦',
|
||
'🔧': '🔧',
|
||
'🔨': '🔨',
|
||
'🔩': '🔩',
|
||
'🔪': '🔪',
|
||
'🔫': '🔫',
|
||
'🔬': '🔬',
|
||
'🔭': '🔭',
|
||
'🔮': '🔮',
|
||
'🔯': '🔯',
|
||
'🔰': '🔰',
|
||
'🔱': '🔱',
|
||
'🔲': '🔲',
|
||
'🔳': '🔳',
|
||
'🔴': '🔴',
|
||
'🔵': '🔵',
|
||
'🔶': '🔶',
|
||
'🔷': '🔷',
|
||
'🔸': '🔸',
|
||
'🔹': '🔹',
|
||
'🔺': '🔺',
|
||
'🔻': '🔻',
|
||
'🔼': '🔼',
|
||
'🔽': '🔽',
|
||
'🚀': '🚀',
|
||
'🚁': '🚁',
|
||
'🚂': '🚂',
|
||
'🚃': '🚃',
|
||
'🚄': '🚄',
|
||
'🚅': '🚅',
|
||
'🚆': '🚆',
|
||
'🚇': '🚇',
|
||
'🚈': '🚈',
|
||
'🚉': '🚉',
|
||
'🚠': '🚠',
|
||
'🚡': '🚡',
|
||
'🚢': '🚢',
|
||
'🚣': '🚣',
|
||
'🚤': '🚤',
|
||
'🚥': '🚥',
|
||
'🚦': '🚦',
|
||
'🚧': '🚧',
|
||
'🚨': '🚨',
|
||
'🚩': '🚩',
|
||
'🚪': '🚪',
|
||
'🚫': '🚫',
|
||
'🚬': '🚬',
|
||
'🚭': '🚭',
|
||
'🚮': '🚮',
|
||
'🚯': '🚯',
|
||
'🚰': '🚰',
|
||
'🚱': '🚱',
|
||
'🚲': '🚲',
|
||
'🚳': '🚳',
|
||
'🚴': '🚴',
|
||
'🚵': '🚵',
|
||
'🚶': '🚶',
|
||
'🚷': '🚷',
|
||
'🚸': '🚸',
|
||
'🚹': '🚹',
|
||
'🚺': '🚺',
|
||
'🚻': '🚻',
|
||
'🚼': '🚼',
|
||
'🚽': '🚽',
|
||
'🚾': '🚾',
|
||
'🚿': '🚿',
|
||
'🛀': '🛀',
|
||
'🛁': '🛁',
|
||
'🛂': '🛂',
|
||
'🛃': '🛃',
|
||
'🛄': '🛄',
|
||
'🛅': '🛅',
|
||
'🌍': '🌍',
|
||
'🌎': '🌎',
|
||
'🌏': '🌏',
|
||
'🌐': '🌐',
|
||
'🌑': '🌑',
|
||
'🌒': '🌒',
|
||
'🌓': '🌓',
|
||
'🌔': '🌔',
|
||
'🌕': '🌕',
|
||
'🌖': '🌖',
|
||
'🌗': '🌗',
|
||
'🌘': '🌘',
|
||
'🌙': '🌙',
|
||
'🌚': '🌚',
|
||
'🌛': '🌛',
|
||
'🌜': '🌜',
|
||
'🌝': '🌝',
|
||
'🌞': '🌞',
|
||
'🌟': '🌟',
|
||
'🌠': '🌠',
|
||
'🌡': '🌡',
|
||
'🌤': '🌤',
|
||
'🌥': '🌥',
|
||
'🌦': '🌦',
|
||
'🌧': '🌧',
|
||
'🌨': '🌨',
|
||
'🌩': '🌩',
|
||
'🌪': '🌪',
|
||
'🌫': '🌫',
|
||
'🌬': '🌬',
|
||
'🌭': '🌭',
|
||
'🌮': '🌮',
|
||
'🌯': '🌯',
|
||
'🌰': '🌰',
|
||
'🌱': '🌱',
|
||
'🌲': '🌲',
|
||
'🌳': '🌳',
|
||
'🌴': '🌴',
|
||
'🌵': '🌵',
|
||
'🌶': '🌶',
|
||
'🌷': '🌷',
|
||
'🌸': '🌸',
|
||
'🌹': '🌹',
|
||
'🌺': '🌺',
|
||
'🌻': '🌻',
|
||
'🌼': '🌼',
|
||
'🌽': '🌽',
|
||
'🌾': '🌾',
|
||
'🌿': '🌿',
|
||
'🍀': '🍀',
|
||
'🍁': '🍁',
|
||
'🍂': '🍂',
|
||
'🍃': '🍃',
|
||
'🍄': '🍄',
|
||
'🍅': '🍅',
|
||
'🍆': '🍆',
|
||
'🍇': '🍇',
|
||
'🍈': '🍈',
|
||
'🍉': '🍉',
|
||
'🍊': '🍊',
|
||
'🍋': '🍋',
|
||
'🍌': '🍌',
|
||
'🍍': '🍍',
|
||
'🍎': '🍎',
|
||
'🍏': '🍏',
|
||
'🍐': '🍐',
|
||
'🍑': '🍑',
|
||
'🍒': '🍒',
|
||
'🍓': '🍓',
|
||
'🍔': '🍔',
|
||
'🍕': '🍕',
|
||
'🍖': '🍖',
|
||
'🍗': '🍗',
|
||
'🍘': '🍘',
|
||
'🍙': '🍙',
|
||
'🍚': '🍚',
|
||
'🍛': '🍛',
|
||
'🍜': '🍜',
|
||
'🍝': '🍝',
|
||
'🍞': '🍞',
|
||
'🍟': '🍟',
|
||
'🍠': '🍠',
|
||
'🍡': '🍡',
|
||
'🍢': '🍢',
|
||
'🍣': '🍣',
|
||
'🍤': '🍤',
|
||
'🍥': '🍥',
|
||
'🍦': '🍦',
|
||
'🍧': '🍧',
|
||
'🍨': '🍨',
|
||
'🍩': '🍩',
|
||
'🍪': '🍪',
|
||
'🍫': '🍫',
|
||
'🍬': '🍬',
|
||
'🍭': '🍭',
|
||
'🍮': '🍮',
|
||
'🍯': '🍯',
|
||
'🍰': '🍰',
|
||
'🍱': '🍱',
|
||
'🍲': '🍲',
|
||
'🍳': '🍳',
|
||
'🍴': '🍴',
|
||
'🍵': '🍵',
|
||
'🍶': '🍶',
|
||
'🍷': '🍷',
|
||
'🍸': '🍸',
|
||
'🍹': '🍹',
|
||
'🍺': '🍺',
|
||
'🍻': '🍻',
|
||
'🍼': '🍼',
|
||
'🍽': '🍽',
|
||
'🍾': '🍾',
|
||
'🍿': '🍿',
|
||
'🎀': '🎀',
|
||
'🎁': '🎁',
|
||
'🎂': '🎂',
|
||
'🎃': '🎃',
|
||
'🎄': '🎄',
|
||
'🎅': '🎅',
|
||
'🎆': '🎆',
|
||
'🎇': '🎇',
|
||
'🎈': '🎈',
|
||
'🎉': '🎉',
|
||
'🎊': '🎊',
|
||
'🎋': '🎋',
|
||
'🎌': '🎌',
|
||
'🎍': '🎍',
|
||
'🎎': '🎎',
|
||
'🎏': '🎏',
|
||
'🎐': '🎐',
|
||
'🎑': '🎑',
|
||
'🎒': '🎒',
|
||
'🎓': '🎓',
|
||
'🎖': '🎖',
|
||
'🎗': '🎗',
|
||
'🎙': '🎙',
|
||
'🎚': '🎚',
|
||
'🎛': '🎛',
|
||
'🎞': '🎞',
|
||
'🎟': '🎟',
|
||
'🎠': '🎠',
|
||
'🎡': '🎡',
|
||
'🎢': '🎢',
|
||
'🎣': '🎣',
|
||
'🎤': '🎤',
|
||
'🎥': '🎥',
|
||
'🎦': '🎦',
|
||
'🎧': '🎧',
|
||
'🎨': '🎨',
|
||
'🎩': '🎩',
|
||
'🎪': '🎪',
|
||
'🎫': '🎫',
|
||
'🎬': '🎬',
|
||
'🎭': '🎭',
|
||
'🎮': '🎮',
|
||
'🎰': '🎰',
|
||
'🎱': '🎱',
|
||
'🎲': '🎲',
|
||
'🎳': '🎳',
|
||
'🎴': '🎴',
|
||
'🎵': '🎵',
|
||
'🎶': '🎶',
|
||
'🎷': '🎷',
|
||
'🎸': '🎸',
|
||
'🎹': '🎹',
|
||
'🎺': '🎺',
|
||
'🎻': '🎻',
|
||
'🎼': '🎼',
|
||
'🎽': '🎽',
|
||
'🎾': '🎾',
|
||
'🎿': '🎿',
|
||
'🏀': '🏀',
|
||
'🏁': '🏁',
|
||
'🏂': '🏂',
|
||
'🏃': '🏃',
|
||
'🏄': '🏄',
|
||
'🏅': '🏅',
|
||
'🏆': '🏆',
|
||
'🏇': '🏇',
|
||
'🏈': '🏈',
|
||
'🏉': '🏉',
|
||
'🏊': '🏊',
|
||
'🏋': '🏋',
|
||
'🏌': '🏌',
|
||
'🏍': '🏍',
|
||
'🏎': '🏎',
|
||
'🏏': '🏏',
|
||
'🏐': '🏐',
|
||
'🏑': '🏑',
|
||
'🏒': '🏒',
|
||
'🏓': '🏓',
|
||
'🏔': '🏔',
|
||
'🏕': '🏕',
|
||
'🏖': '🏖',
|
||
'🏗': '🏗',
|
||
'🏘': '🏘',
|
||
'🏙': '🏙',
|
||
'🏚': '🏚',
|
||
'🏛': '🏛',
|
||
'🏜': '🏜',
|
||
'🏝': '🏝',
|
||
'🏞': '🏞',
|
||
'🏟': '🏟',
|
||
'🏠': '🏠',
|
||
'🏡': '🏡',
|
||
'🏢': '🏢',
|
||
'🏣': '🏣',
|
||
'🏤': '🏤',
|
||
'🏥': '🏥',
|
||
'🏦': '🏦',
|
||
'🏧': '🏧',
|
||
'🏨': '🏨',
|
||
'🏩': '🏩',
|
||
'🏪': '🏪',
|
||
'🏫': '🏫',
|
||
'🏬': '🏬',
|
||
'🏭': '🏭',
|
||
'🏮': '🏮',
|
||
'🏯': '🏯',
|
||
'🏰': '🏰',
|
||
'🏳': '🏳',
|
||
'🏴': '🏴',
|
||
'🏵': '🏵',
|
||
'🏷': '🏷',
|
||
'🏸': '🏸',
|
||
'🏹': '🏹',
|
||
'🏺': '🏺',
|
||
'🏻': '🏻',
|
||
'🏼': '🏼',
|
||
'🏽': '🏽',
|
||
'🏾': '🏾',
|
||
'🏿': '🏿',
|
||
'🐀': '🐀',
|
||
'🐁': '🐁',
|
||
'🐂': '🐂',
|
||
'🐃': '🐃',
|
||
'🐄': '🐄',
|
||
'🐅': '🐅',
|
||
'🐆': '🐆',
|
||
'🐇': '🐇',
|
||
'🐈': '🐈',
|
||
'🐉': '🐉',
|
||
'🐊': '🐊',
|
||
'🐋': '🐋',
|
||
'🐌': '🐌',
|
||
'🐍': '🐍',
|
||
'🐎': '🐎',
|
||
'🐏': '🐏',
|
||
'🐐': '🐐',
|
||
'🐑': '🐑',
|
||
'🐒': '🐒',
|
||
'🐓': '🐓',
|
||
'🐔': '🐔',
|
||
'🐕': '🐕',
|
||
'🐖': '🐖',
|
||
'🐗': '🐗',
|
||
'🐘': '🐘',
|
||
'🐙': '🐙',
|
||
'🐚': '🐚',
|
||
'🐛': '🐛',
|
||
'🐜': '🐜',
|
||
'🐝': '🐝',
|
||
'🐞': '🐞',
|
||
'🐟': '🐟',
|
||
'🐠': '🐠',
|
||
'🐡': '🐡',
|
||
'🐢': '🐢',
|
||
'🐣': '🐣',
|
||
'🐤': '🐤',
|
||
'🐥': '🐥',
|
||
'🐦': '🐦',
|
||
'🐧': '🐧',
|
||
'🐨': '🐨',
|
||
'🐩': '🐩',
|
||
'🐪': '🐪',
|
||
'🐫': '🐫',
|
||
'🐬': '🐬',
|
||
'🐭': '🐭',
|
||
'🐮': '🐮',
|
||
'🐯': '🐯',
|
||
'🐰': '🐰',
|
||
'🐱': '🐱',
|
||
'🐲': '🐲',
|
||
'🐳': '🐳',
|
||
'🐴': '🐴',
|
||
'🐵': '🐵',
|
||
'🐶': '🐶',
|
||
'🐷': '🐷',
|
||
'🐸': '🐸',
|
||
'🐹': '🐹',
|
||
'🐺': '🐺',
|
||
'🐻': '🐻',
|
||
'🐼': '🐼',
|
||
'🐽': '🐽',
|
||
'🐾': '🐾',
|
||
'🐿': '🐿',
|
||
'👀': '👀',
|
||
'👁': '👁',
|
||
'👂': '👂',
|
||
'👃': '👃',
|
||
'👄': '👄',
|
||
'👅': '👅',
|
||
'👆': '👆',
|
||
'👇': '👇',
|
||
'👈': '👈',
|
||
'👉': '👉',
|
||
'👊': '👊',
|
||
'👋': '👋',
|
||
'👌': '👌',
|
||
'👍': '👍',
|
||
'👎': '👎',
|
||
'👏': '👏',
|
||
'👐': '👐',
|
||
'👑': '👑',
|
||
'👒': '👒',
|
||
'👓': '👓',
|
||
'👔': '👔',
|
||
'👕': '👕',
|
||
'👖': '👖',
|
||
'👗': '👗',
|
||
'👘': '👘',
|
||
'👙': '👙',
|
||
'👚': '👚',
|
||
'👛': '👛',
|
||
'👜': '👜',
|
||
'👝': '👝',
|
||
'👞': '👞',
|
||
'👟': '👟',
|
||
'👠': '👠',
|
||
'👡': '👡',
|
||
'👢': '👢',
|
||
'👣': '👣',
|
||
'👤': '👤',
|
||
'👥': '👥',
|
||
'👦': '👦',
|
||
'👧': '👧',
|
||
'👨': '👨',
|
||
'👩': '👩',
|
||
'👪': '👪',
|
||
'👫': '👫',
|
||
'👬': '👬',
|
||
'👭': '👭',
|
||
'👮': '👮',
|
||
'👯': '👯',
|
||
'👰': '👰',
|
||
'👱': '👱',
|
||
'👲': '👲',
|
||
'👳': '👳',
|
||
'👴': '👴',
|
||
'👵': '👵',
|
||
'👶': '👶',
|
||
'👷': '👷',
|
||
'👸': '👸',
|
||
'👹': '👹',
|
||
'👺': '👺',
|
||
'👻': '👻',
|
||
'👼': '👼',
|
||
'👽': '👽',
|
||
'👾': '👾',
|
||
'👿': '👿',
|
||
'💀': '💀',
|
||
'💁': '💁',
|
||
'💂': '💂',
|
||
'💃': '💃',
|
||
'💄': '💄',
|
||
'💅': '💅',
|
||
'💆': '💆',
|
||
'💇': '💇',
|
||
'💈': '💈',
|
||
'💉': '💉',
|
||
'💊': '💊',
|
||
'💋': '💋',
|
||
'💌': '💌',
|
||
'💍': '💍',
|
||
'💎': '💎',
|
||
'💏': '💏',
|
||
'💐': '💐',
|
||
'💑': '💑',
|
||
'💒': '💒',
|
||
'💓': '💓',
|
||
'💔': '💔',
|
||
'💕': '💕',
|
||
'💖': '💖',
|
||
'💗': '💗',
|
||
'💘': '💘',
|
||
'💙': '💙',
|
||
'💚': '💚',
|
||
'💛': '💛',
|
||
'💜': '💜',
|
||
'💝': '💝',
|
||
'💞': '💞',
|
||
'💟': '💟',
|
||
'💠': '💠',
|
||
'💡': '💡',
|
||
'💢': '💢',
|
||
'💣': '💣',
|
||
'💤': '💤',
|
||
'💥': '💥',
|
||
'💦': '💦',
|
||
'💧': '💧',
|
||
'💨': '💨',
|
||
'💩': '💩',
|
||
'💪': '💪',
|
||
'💫': '💫',
|
||
'💬': '💬',
|
||
'💭': '💭',
|
||
'💮': '💮',
|
||
'💯': '💯',
|
||
'💰': '💰',
|
||
'💱': '💱',
|
||
'💲': '💲',
|
||
'💳': '💳',
|
||
'💴': '💴',
|
||
'💵': '💵',
|
||
'💶': '💶',
|
||
'💷': '💷',
|
||
'💸': '💸',
|
||
'💹': '💹',
|
||
'💺': '💺',
|
||
'💻': '💻',
|
||
'💼': '💼',
|
||
'💽': '💽',
|
||
'💾': '💾',
|
||
'💿': '💿',
|
||
'📀': '📀',
|
||
'📁': '📁',
|
||
'📂': '📂',
|
||
'📃': '📃',
|
||
'📄': '📄',
|
||
'📅': '📅',
|
||
'📆': '📆',
|
||
'📇': '📇',
|
||
'📈': '📈',
|
||
'📉': '📉',
|
||
'📊': '📊',
|
||
'📋': '📋',
|
||
'📌': '📌',
|
||
'📍': '📍',
|
||
'📎': '📎',
|
||
'📏': '📏',
|
||
'📐': '📐',
|
||
'📑': '📑',
|
||
'📒': '📒',
|
||
'📓': '📓',
|
||
'📔': '📔',
|
||
'📕': '📕',
|
||
'📖': '📖',
|
||
'📗': '📗',
|
||
'📘': '📘',
|
||
'📙': '📙',
|
||
'📚': '📚',
|
||
'📛': '📛',
|
||
'📜': '📜',
|
||
'📝': '📝',
|
||
'📞': '📞',
|
||
'📟': '📟',
|
||
'📠': '📠',
|
||
'📡': '📡',
|
||
'📢': '📢',
|
||
'📣': '📣',
|
||
'📤': '📤',
|
||
'📥': '📥',
|
||
'📦': '📦',
|
||
'📧': '📧',
|
||
'📨': '📨',
|
||
'📩': '📩',
|
||
'📪': '📪',
|
||
'📫': '📫',
|
||
'📬': '📬',
|
||
'📭': '📭',
|
||
'📮': '📮',
|
||
'📯': '📯',
|
||
'📰': '📰',
|
||
'📱': '📱',
|
||
'📲': '📲',
|
||
'📳': '📳',
|
||
'📴': '📴',
|
||
'📵': '📵',
|
||
'📶': '📶',
|
||
'📷': '📷',
|
||
'📸': '📸',
|
||
'📹': '📹',
|
||
'📺': '📺',
|
||
'📻': '📻',
|
||
'📼': '📼',
|
||
'📽': '📽',
|
||
'📿': '📿',
|
||
'🔀': '🔀',
|
||
'🔁': '🔁',
|
||
'🔂': '🔂',
|
||
'🔃': '🔃',
|
||
'🔄': '🔄',
|
||
'🔅': '🔅',
|
||
'🔆': '🔆',
|
||
'🔇': '🔇',
|
||
'🔈': '🔈',
|
||
'🔉': '🔉',
|
||
'🔊': '🔊',
|
||
'🔋': '🔋',
|
||
'🔌': '🔌',
|
||
'🔍': '🔍',
|
||
'🔎': '🔎',
|
||
'🔏': '🔏',
|
||
'🔐': '🔐',
|
||
'🔑': '🔑',
|
||
'🔒': '🔒',
|
||
'🔓': '🔓',
|
||
'🔔': '🔔',
|
||
'🔕': '🔕',
|
||
'🔖': '🔖',
|
||
'🔗': '🔗',
|
||
'🔘': '🔘',
|
||
'🔙': '🔙',
|
||
'🔚': '🔚',
|
||
'🔛': '🔛',
|
||
'🔜': '🔜',
|
||
'🔝': '🔝',
|
||
'🔞': '🔞',
|
||
'🔟': '🔟',
|
||
'🔠': '🔠',
|
||
'🔡': '🔡',
|
||
'🔢': '🔢',
|
||
'🔣': '🔣',
|
||
'🔤': '🔤',
|
||
'🔥': '🔥',
|
||
'🔦': '🔦',
|
||
'🔧': '🔧',
|
||
'🔨': '🔨',
|
||
'🔩': '🔩',
|
||
'🔪': '🔪',
|
||
'🔫': '🔫',
|
||
'🔬': '🔬',
|
||
'🔭': '🔭',
|
||
'🔮': '🔮',
|
||
'🔯': '🔯',
|
||
'🔰': '🔰',
|
||
'🔱': '🔱',
|
||
'🔲': '🔲',
|
||
'🔳': '🔳',
|
||
'🔴': '🔴',
|
||
'🔵': '🔵',
|
||
'🔶': '🔶',
|
||
'🔷': '🔷',
|
||
'🔸': '🔸',
|
||
'🔹': '🔹',
|
||
'🔺': '🔺',
|
||
'🔻': '🔻',
|
||
'🔼': '🔼',
|
||
'🔽': '🔽',
|
||
'🕉': '🕉',
|
||
'🕊': '🕊',
|
||
'🕋': '🕋',
|
||
'🕌': '🕌',
|
||
'🕍': '🕍',
|
||
'🕎': '🕎',
|
||
'🕐': '🕐',
|
||
'🕑': '🕑',
|
||
'🕒': '🕒',
|
||
'🕓': '🕓',
|
||
'🕔': '🕔',
|
||
'🕕': '🕕',
|
||
'🕖': '🕖',
|
||
'🕗': '🕗',
|
||
'🕘': '🕘',
|
||
'🕙': '🕙',
|
||
'🕚': '🕚',
|
||
'🕛': '🕛',
|
||
'🕜': '🕜',
|
||
'🕝': '🕝',
|
||
'🕞': '🕞',
|
||
'🕟': '🕟',
|
||
'🕠': '🕠',
|
||
'🕡': '🕡',
|
||
'🕢': '🕢',
|
||
'🕣': '🕣',
|
||
'🕤': '🕤',
|
||
'🕥': '🕥',
|
||
'🕦': '🕦',
|
||
'🕧': '🕧',
|
||
'🕯': '🕯',
|
||
'🕰': '🕰',
|
||
'🕳': '🕳',
|
||
'🕴': '🕴',
|
||
'🕵': '🕵',
|
||
'🕶': '🕶',
|
||
'🕷': '🕷',
|
||
'🕸': '🕸',
|
||
'🕹': '🕹',
|
||
'🕺': '🕺',
|
||
'🖇': '🖇',
|
||
'🖊': '🖊',
|
||
'🖋': '🖋',
|
||
'🖌': '🖌',
|
||
'🖍': '🖍',
|
||
'🖐': '🖐',
|
||
'🖕': '🖕',
|
||
'🖖': '🖖',
|
||
'🖤': '🖤',
|
||
'🖥': '🖥',
|
||
'🖨': '🖨',
|
||
'🖱': '🖱',
|
||
'🖲': '🖲',
|
||
'🖼': '🖼',
|
||
'🗂': '🗂',
|
||
'🗃': '🗃',
|
||
'🗄': '🗄',
|
||
'🗑': '🗑',
|
||
'🗒': '🗒',
|
||
'🗓': '🗓',
|
||
'🗜': '🗜',
|
||
'🗝': '🗝',
|
||
'🗞': '🗞',
|
||
'🗡': '🗡',
|
||
'🗣': '🗣',
|
||
'🗨': '🗨',
|
||
'🗯': '🗯',
|
||
'🗳': '🗳',
|
||
'🗺': '🗺',
|
||
'🗻': '🗻',
|
||
'🗼': '🗼',
|
||
'🗽': '🗽',
|
||
'🗾': '🗾',
|
||
'🗿': '🗿',
|
||
'😀': '😀',
|
||
'😁': '😁',
|
||
'😂': '😂',
|
||
'😃': '😃',
|
||
'😄': '😄',
|
||
'😅': '😅',
|
||
'😆': '😆',
|
||
'😇': '😇',
|
||
'😈': '😈',
|
||
'😉': '😉',
|
||
'😊': '😊',
|
||
'😋': '😋',
|
||
'😌': '😌',
|
||
'😍': '😍',
|
||
'😎': '😎',
|
||
'😏': '😏',
|
||
'😐': '😐',
|
||
'😑': '😑',
|
||
'😒': '😒',
|
||
'😓': '😓',
|
||
'😔': '😔',
|
||
'😕': '😕',
|
||
'😖': '😖',
|
||
'😗': '😗',
|
||
'😘': '😘',
|
||
'😙': '😙',
|
||
'😚': '😚',
|
||
'😛': '😛',
|
||
'😜': '😜',
|
||
'😝': '😝',
|
||
'😞': '😞',
|
||
'😟': '😟',
|
||
'😠': '😠',
|
||
'😡': '😡',
|
||
'😢': '😢',
|
||
'😣': '😣',
|
||
'😤': '😤',
|
||
'😥': '😥',
|
||
'😦': '😦',
|
||
'😧': '😧',
|
||
'😨': '😨',
|
||
'😩': '😩',
|
||
'😪': '😪',
|
||
'😫': '😫',
|
||
'😬': '😬',
|
||
'😭': '😭',
|
||
'😮': '😮',
|
||
'😯': '😯',
|
||
'😰': '😰',
|
||
'😱': '😱',
|
||
'😲': '😲',
|
||
'😳': '😳',
|
||
'😴': '😴',
|
||
'😵': '😵',
|
||
'😶': '😶',
|
||
'😷': '😷',
|
||
'😸': '😸',
|
||
'😹': '😹',
|
||
'😺': '😺',
|
||
'😻': '😻',
|
||
'😼': '😼',
|
||
'😽': '😽',
|
||
'😾': '😾',
|
||
'😿': '😿',
|
||
'🙀': '🙀',
|
||
'🙁': '🙁',
|
||
'🙂': '🙂',
|
||
'🙃': '🙃',
|
||
'🙄': '🙄',
|
||
'🙅': '🙅',
|
||
'🙆': '🙆',
|
||
'🙇': '🙇',
|
||
'🙈': '🙈',
|
||
'🙉': '🙉',
|
||
'🙊': '🙊',
|
||
'🙋': '🙋',
|
||
'🙌': '🙌',
|
||
'🙍': '🙍',
|
||
'🙎': '🙎',
|
||
'🙏': '🙏',
|
||
'🚀': '🚀',
|
||
'🚁': '🚁',
|
||
'🚂': '🚂',
|
||
'🚃': '🚃',
|
||
'🚄': '🚄',
|
||
'🚅': '🚅',
|
||
'🚆': '🚆',
|
||
'🚇': '🚇',
|
||
'🚈': '🚈',
|
||
'🚉': '🚉',
|
||
'🚊': '🚊',
|
||
'🚋': '🚋',
|
||
'🚌': '🚌',
|
||
'🚍': '🚍',
|
||
'🚎': '🚎',
|
||
'🚏': '🚏',
|
||
'🚐': '🚐',
|
||
'🚑': '🚑',
|
||
'🚒': '🚒',
|
||
'🚓': '🚓',
|
||
'🚔': '🚔',
|
||
'🚕': '🚕',
|
||
'🚖': '🚖',
|
||
'🚗': '🚗',
|
||
'🚘': '🚘',
|
||
'🚙': '🚙',
|
||
'🚚': '🚚',
|
||
'🚛': '🚛',
|
||
'🚜': '🚜',
|
||
'🚝': '🚝',
|
||
'🚞': '🚞',
|
||
'🚟': '🚟',
|
||
'🚠': '🚠',
|
||
'🚡': '🚡',
|
||
'🚢': '🚢',
|
||
'🚣': '🚣',
|
||
'🚤': '🚤',
|
||
'🚥': '🚥',
|
||
'🚦': '🚦',
|
||
'🚧': '🚧',
|
||
'🚨': '🚨',
|
||
'🚩': '🚩',
|
||
'🚪': '🚪',
|
||
'🚫': '🚫',
|
||
'🚬': '🚬',
|
||
'🚭': '🚭',
|
||
'🚮': '🚮',
|
||
'🚯': '🚯',
|
||
'🚰': '🚰',
|
||
'🚱': '🚱',
|
||
'🚲': '🚲',
|
||
'🚳': '🚳',
|
||
'🚴': '🚴',
|
||
'🚵': '🚵',
|
||
'🚶': '🚶',
|
||
'🚷': '🚷',
|
||
'🚸': '🚸',
|
||
'🚹': '🚹',
|
||
'🚺': '🚺',
|
||
'🚻': '🚻',
|
||
'🚼': '🚼',
|
||
'🚽': '🚽',
|
||
'🚾': '🚾',
|
||
'🚿': '🚿',
|
||
'🛀': '🛀',
|
||
'🛁': '🛁',
|
||
'🛂': '🛂',
|
||
'🛃': '🛃',
|
||
'🛄': '🛄',
|
||
'🛅': '🛅',
|
||
'🛋': '🛋',
|
||
'🛌': '🛌',
|
||
'🛍': '🛍',
|
||
'🛎': '🛎',
|
||
'🛏': '🛏',
|
||
'🛐': '🛐',
|
||
'🛑': '🛑',
|
||
'🛒': '🛒',
|
||
'🛕': '🛕',
|
||
'🛠': '🛠',
|
||
'🛡': '🛡',
|
||
'🛢': '🛢',
|
||
'🛣': '🛣',
|
||
'🛤': '🛤',
|
||
'🛥': '🛥',
|
||
'🛩': '🛩',
|
||
'🛫': '🛫',
|
||
'🛬': '🛬',
|
||
'🛰': '🛰',
|
||
'🛳': '🛳',
|
||
'🛴': '🛴',
|
||
'🛵': '🛵',
|
||
'🛶': '🛶',
|
||
'🛷': '🛷',
|
||
'🛸': '🛸',
|
||
'🛹': '🛹',
|
||
'🛺': '🛺',
|
||
'🟠': '🟠',
|
||
'🟡': '🟡',
|
||
'🟢': '🟢',
|
||
'🟣': '🟣',
|
||
'🟤': '🟤',
|
||
'🟥': '🟥',
|
||
'🟦': '🟦',
|
||
'🟧': '🟧',
|
||
'🟨': '🟨',
|
||
'🟩': '🟩',
|
||
'🟪': '🟪',
|
||
'🟫': '🟫',
|
||
'🤍': '🤍',
|
||
'🤎': '🤎',
|
||
'🤏': '🤏',
|
||
'🤐': '🤐',
|
||
'🤑': '🤑',
|
||
'🤒': '🤒',
|
||
'🤓': '🤓',
|
||
'🤔': '🤔',
|
||
'🤕': '🤕',
|
||
'🤖': '🤖',
|
||
'🤗': '🤗',
|
||
'🤘': '🤘',
|
||
'🤙': '🤙',
|
||
'🤚': '🤚',
|
||
'🤛': '🤛',
|
||
'🤜': '🤜',
|
||
'🤝': '🤝',
|
||
'🤞': '🤞',
|
||
'🤟': '🤟',
|
||
'🤠': '🤠',
|
||
'🤡': '🤡',
|
||
'🤢': '🤢',
|
||
'🤣': '🤣',
|
||
'🤤': '🤤',
|
||
'🤥': '🤥',
|
||
'🤦': '🤦',
|
||
'🤧': '🤧',
|
||
'🤨': '🤨',
|
||
'🤩': '🤩',
|
||
'🤪': '🤪',
|
||
'🤫': '🤫',
|
||
'🤬': '🤬',
|
||
'🤭': '🤭',
|
||
'🤮': '🤮',
|
||
'🤯': '🤯',
|
||
'🤰': '🤰',
|
||
'🤱': '🤱',
|
||
'🤲': '🤲',
|
||
'🤳': '🤳',
|
||
'🤴': '🤴',
|
||
'🤵': '🤵',
|
||
'🤶': '🤶',
|
||
'🤷': '🤷',
|
||
'🤸': '🤸',
|
||
'🤹': '🤹',
|
||
'🤺': '🤺',
|
||
'🤼': '🤼',
|
||
'🤽': '🤽',
|
||
'🤾': '🤾',
|
||
'🥀': '🥀',
|
||
'🥁': '🥁',
|
||
'🥂': '🥂',
|
||
'🥃': '🥃',
|
||
'🥄': '🥄',
|
||
'🥅': '🥅',
|
||
'🥇': '🥇',
|
||
'🥈': '🥈',
|
||
'🥉': '🥉',
|
||
'🥊': '🥊',
|
||
'🥋': '🥋',
|
||
'🥌': '🥌',
|
||
'🥍': '🥍',
|
||
'🥎': '🥎',
|
||
'🥏': '🥏',
|
||
'🥐': '🥐',
|
||
'🥑': '🥑',
|
||
'🥒': '🥒',
|
||
'🥓': '🥓',
|
||
'🥔': '🥔',
|
||
'🥕': '🥕',
|
||
'🥖': '🥖',
|
||
'🥗': '🥗',
|
||
'🥘': '🥘',
|
||
'🥙': '🥙',
|
||
'🥚': '🥚',
|
||
'🥛': '🥛',
|
||
'🥜': '🥜',
|
||
'🥝': '🥝',
|
||
'🥞': '🥞',
|
||
'🥟': '🥟',
|
||
'🥠': '🥠',
|
||
'🥡': '🥡',
|
||
'🥢': '🥢',
|
||
'🥣': '🥣',
|
||
'🥤': '🥤',
|
||
'🥥': '🥥',
|
||
'🥦': '🥦',
|
||
'🥧': '🥧',
|
||
'🥨': '🥨',
|
||
'🥩': '🥩',
|
||
'🥪': '🥪',
|
||
'🥫': '🥫',
|
||
'🥬': '🥬',
|
||
'🥭': '🥭',
|
||
'🥮': '🥮',
|
||
'🥯': '🥯',
|
||
'🥰': '🥰',
|
||
'🥱': '🥱',
|
||
'🥲': '🥲',
|
||
'🥳': '🥳',
|
||
'🥴': '🥴',
|
||
'🥵': '🥵',
|
||
'🥶': '🥶',
|
||
'🥷': '🥷',
|
||
'🥸': '🥸',
|
||
'🥹': '🥹',
|
||
'🥺': '🥺',
|
||
'🥻': '🥻',
|
||
'🥼': '🥼',
|
||
'🥽': '🥽',
|
||
'🥾': '🥾',
|
||
'🥿': '🥿',
|
||
'🦀': '🦀',
|
||
'🦁': '🦁',
|
||
'🦂': '🦂',
|
||
'🦃': '🦃',
|
||
'🦄': '🦄',
|
||
'🦅': '🦅',
|
||
'🦆': '🦆',
|
||
'🦇': '🦇',
|
||
'🦈': '🦈',
|
||
'🦉': '🦉',
|
||
'🦊': '🦊',
|
||
'🦋': '🦋',
|
||
'🦌': '🦌',
|
||
'🦍': '🦍',
|
||
'🦎': '🦎',
|
||
'🦏': '🦏',
|
||
'🦐': '🦐',
|
||
'🦑': '🦑',
|
||
'🦒': '🦒',
|
||
'🦓': '🦓',
|
||
'🦔': '🦔',
|
||
'🦕': '🦕',
|
||
'🦖': '🦖',
|
||
'🦗': '🦗',
|
||
'🦘': '🦘',
|
||
'🦙': '🦙',
|
||
'🦚': '🦚',
|
||
'🦛': '🦛',
|
||
'🦜': '🦜',
|
||
'🦝': '🦝',
|
||
'🦞': '🦞',
|
||
'🦟': '🦟',
|
||
'🦠': '🦠',
|
||
'🦡': '🦡',
|
||
'🦢': '🦢',
|
||
'🦣': '🦣',
|
||
'🦤': '🦤',
|
||
'🦥': '🦥',
|
||
'🦦': '🦦',
|
||
'🦧': '🦧',
|
||
'🦨': '🦨',
|
||
'🦩': '🦩',
|
||
'🦪': '🦪',
|
||
'🦫': '🦫',
|
||
'🦬': '🦬',
|
||
'🦭': '🦭',
|
||
'🦮': '🦮',
|
||
'🦯': '🦯',
|
||
'🦰': '🦰',
|
||
'🦱': '🦱',
|
||
'🦲': '🦲',
|
||
'🦳': '🦳',
|
||
'🦴': '🦴',
|
||
'🦵': '🦵',
|
||
'🦶': '🦶',
|
||
'🦷': '🦷',
|
||
'🦸': '🦸',
|
||
'🦹': '🦹',
|
||
'🦺': '🦺',
|
||
'🦻': '🦻',
|
||
'🦼': '🦼',
|
||
'🦽': '🦽',
|
||
'🦾': '🦾',
|
||
'🦿': '🦿',
|
||
'🧀': '🧀',
|
||
'🧁': '🧁',
|
||
'🧂': '🧂',
|
||
'🧃': '🧃',
|
||
'🧄': '🧄',
|
||
'🧅': '🧅',
|
||
'🧆': '🧆',
|
||
'🧇': '🧇',
|
||
'🧈': '🧈',
|
||
'🧉': '🧉',
|
||
'🧊': '🧊',
|
||
'🧋': '🧋',
|
||
'🧌': '🧌',
|
||
'🧍': '🧍',
|
||
'🧎': '🧎',
|
||
'🧏': '🧏',
|
||
'🧐': '🧐',
|
||
'🧑': '🧑',
|
||
'🧒': '🧒',
|
||
'🧓': '🧓',
|
||
'🧔': '🧔',
|
||
'🧕': '🧕',
|
||
'🧖': '🧖',
|
||
'🧗': '🧗',
|
||
'🧘': '🧘',
|
||
'🧙': '🧙',
|
||
'🧚': '🧚',
|
||
'🧛': '🧛',
|
||
'🧜': '🧜',
|
||
'🧝': '🧝',
|
||
'🧞': '🧞',
|
||
'🧟': '🧟',
|
||
'🧠': '🧠',
|
||
'🧡': '🧡',
|
||
'🧢': '🧢',
|
||
'🧣': '🧣',
|
||
'🧤': '🧤',
|
||
'🧥': '🧥',
|
||
'🧦': '🧦',
|
||
'🧧': '🧧',
|
||
'🧨': '🧨',
|
||
'🧩': '🧩',
|
||
'🧪': '🧪',
|
||
'🧫': '🧫',
|
||
'🧬': '🧬',
|
||
'🧭': '🧭',
|
||
'🧮': '🧮',
|
||
'🧯': '🧯',
|
||
'🧰': '🧰',
|
||
'🧱': '🧱',
|
||
'🧲': '🧲',
|
||
'🧳': '🧳',
|
||
'🧴': '🧴',
|
||
'🧵': '🧵',
|
||
'🧶': '🧶',
|
||
'🧷': '🧷',
|
||
'🧸': '🧸',
|
||
'🧹': '🧹',
|
||
'🧺': '🧺',
|
||
'🧻': '🧻',
|
||
'🧼': '🧼',
|
||
'🧽': '🧽',
|
||
'🧾': '🧾',
|
||
'🧿': '🧿',
|
||
'🩰': '🩰',
|
||
'🩱': '🩱',
|
||
'🩲': '🩲',
|
||
'🩳': '🩳',
|
||
'🩴': '🩴',
|
||
'🩸': '🩸',
|
||
'🩹': '🩹',
|
||
'🩺': '🩺',
|
||
'🪀': '🪀',
|
||
'🪁': '🪁',
|
||
'🪂': '🪂',
|
||
'🪃': '🪃',
|
||
'🪄': '🪄',
|
||
'🪅': '🪅',
|
||
'🪆': '🪆',
|
||
'🪐': '🪐',
|
||
'🪑': '🪑',
|
||
'🪒': '🪒',
|
||
'🪓': '🪓',
|
||
'🪔': '🪔',
|
||
'🪕': '🪕',
|
||
'🪖': '🪖',
|
||
'🪗': '🪗',
|
||
'🪘': '🪘',
|
||
'🪙': '🪙',
|
||
'🪚': '🪚',
|
||
'🪛': '🪛',
|
||
'🪜': '🪜',
|
||
'🪝': '🪝',
|
||
'🪞': '🪞',
|
||
'🪟': '🪟',
|
||
'🪠': '🪠',
|
||
'🪡': '🪡',
|
||
'🪢': '🪢',
|
||
'🪣': '🪣',
|
||
'🪤': '🪤',
|
||
'🪥': '🪥',
|
||
'🪦': '🪦',
|
||
'🪧': '🪧',
|
||
'🪨': '🪨',
|
||
'🪰': '🪰',
|
||
'🪱': '🪱',
|
||
'🪲': '🪲',
|
||
'🪳': '🪳',
|
||
'🪴': '🪴',
|
||
'🪵': '🪵',
|
||
'🪶': '🪶',
|
||
'🫀': '🫀',
|
||
'🫁': '🫁',
|
||
'🫂': '🫂',
|
||
'🫐': '🫐',
|
||
'🫑': '🫑',
|
||
'🫒': '🫒',
|
||
'🫓': '🫓',
|
||
'🫔': '🫔',
|
||
'🫕': '🫕',
|
||
'🫖': '🫖',
|
||
'🫠': '🫠',
|
||
'🫡': '🫡',
|
||
'🫢': '🫢',
|
||
'🫣': '🫣',
|
||
'🫤': '🫤',
|
||
'🫥': '🫥',
|
||
'🫦': '🫦',
|
||
'🫧': '🫧',
|
||
'🫰': '🫰',
|
||
'🫱': '🫱',
|
||
'🫲': '🫲',
|
||
'🫳': '🫳',
|
||
'🫴': '🫴',
|
||
'🫵': '🫵',
|
||
'🫶': '🫶',
|
||
'‼': '‼',
|
||
'⁉': '⁉',
|
||
'™': '™',
|
||
'ℹ': 'ℹ',
|
||
'↔': '↔',
|
||
'↕': '↕',
|
||
'↖': '↖',
|
||
'↗': '↗',
|
||
'↘': '↘',
|
||
'↙': '↙',
|
||
'↩': '↩',
|
||
'↪': '↪',
|
||
'⌚': '⌚',
|
||
'⌛': '⌛',
|
||
'⌨': '⌨',
|
||
'⏏': '⏏',
|
||
'⏩': '⏩',
|
||
'⏪': '⏪',
|
||
'⏫': '⏫',
|
||
'⏬': '⏬',
|
||
'⏭': '⏭',
|
||
'⏮': '⏮',
|
||
'⏯': '⏯',
|
||
'⏰': '⏰',
|
||
'⏱': '⏱',
|
||
'⏲': '⏲',
|
||
'⏳': '⏳',
|
||
'⏸': '⏸',
|
||
'⏹': '⏹',
|
||
'⏺': '⏺',
|
||
'Ⓜ': 'Ⓜ',
|
||
'▪': '▪',
|
||
'▫': '▫',
|
||
'▶': '▶',
|
||
'◀': '◀',
|
||
'◻': '◻',
|
||
'◼': '◼',
|
||
'◽': '◽',
|
||
'◾': '◾',
|
||
'☀': '☀',
|
||
'☁': '☁',
|
||
'☂': '☂',
|
||
'☃': '☃',
|
||
'☄': '☄',
|
||
'☎': '☎',
|
||
'☑': '☑',
|
||
'☔': '☔',
|
||
'☕': '☕',
|
||
'☘': '☘',
|
||
'☝': '☝',
|
||
'☠': '☠',
|
||
'☢': '☢',
|
||
'☣': '☣',
|
||
'☦': '☦',
|
||
'☪': '☪',
|
||
'☮': '☮',
|
||
'☯': '☯',
|
||
'☸': '☸',
|
||
'☹': '☹',
|
||
'☺': '☺',
|
||
'♀': '♀',
|
||
'♂': '♂',
|
||
'♈': '♈',
|
||
'♉': '♉',
|
||
'♊': '♊',
|
||
'♋': '♋',
|
||
'♌': '♌',
|
||
'♍': '♍',
|
||
'♎': '♎',
|
||
'♏': '♏',
|
||
'♐': '♐',
|
||
'♑': '♑',
|
||
'♒': '♒',
|
||
'♓': '♓',
|
||
'♟': '♟',
|
||
'♠': '♠',
|
||
'♣': '♣',
|
||
'♥': '♥',
|
||
'♦': '♦',
|
||
'♨': '♨',
|
||
'♻': '♻',
|
||
'♾': '♾',
|
||
'♿': '♿',
|
||
'⚒': '⚒',
|
||
'⚓': '⚓',
|
||
'⚔': '⚔',
|
||
'⚕': '⚕',
|
||
'⚖': '⚖',
|
||
'⚗': '⚗',
|
||
'⚙': '⚙',
|
||
'⚛': '⚛',
|
||
'⚜': '⚜',
|
||
'⚠': '⚠',
|
||
'⚡': '⚡',
|
||
'⚪': '⚪',
|
||
'⚫': '⚫',
|
||
'⚰': '⚰',
|
||
'⚱': '⚱',
|
||
'⚽': '⚽',
|
||
'⚾': '⚾',
|
||
'⛄': '⛄',
|
||
'⛅': '⛅',
|
||
'⛈': '⛈',
|
||
'⛎': '⛎',
|
||
'⛏': '⛏',
|
||
'⛑': '⛑',
|
||
'⛓': '⛓',
|
||
'⛔': '⛔',
|
||
'⛩': '⛩',
|
||
'⛪': '⛪',
|
||
'⛰': '⛰',
|
||
'⛱': '⛱',
|
||
'⛲': '⛲',
|
||
'⛳': '⛳',
|
||
'⛴': '⛴',
|
||
'⛵': '⛵',
|
||
'⛷': '⛷',
|
||
'⛸': '⛸',
|
||
'⛹': '⛹',
|
||
'⛺': '⛺',
|
||
'⛽': '⛽',
|
||
'✂': '✂',
|
||
'✅': '✅',
|
||
'✈': '✈',
|
||
'✉': '✉',
|
||
'✊': '✊',
|
||
'✋': '✋',
|
||
'✌': '✌',
|
||
'✍': '✍',
|
||
'✏': '✏',
|
||
'✒': '✒',
|
||
'✔': '✔',
|
||
'✖': '✖',
|
||
'✝': '✝',
|
||
'✡': '✡',
|
||
'✨': '✨',
|
||
'✳': '✳',
|
||
'✴': '✴',
|
||
'❄': '❄',
|
||
'❇': '❇',
|
||
'❌': '❌',
|
||
'❎': '❎',
|
||
'❓': '❓',
|
||
'❔': '❔',
|
||
'❕': '❕',
|
||
'❗': '❗',
|
||
'❣': '❣',
|
||
'❤': '❤',
|
||
'➕': '➕',
|
||
'➖': '➖',
|
||
'➗': '➗',
|
||
'➡': '➡',
|
||
'➰': '➰',
|
||
'➿': '➿',
|
||
'⤴': '⤴',
|
||
'⤵': '⤵',
|
||
'⬅': '⬅',
|
||
'⬆': '⬆',
|
||
'⬇': '⬇',
|
||
'⬛': '⬛',
|
||
'⬜': '⬜',
|
||
'⭐': '⭐',
|
||
'⭕': '⭕',
|
||
'〰': '〰',
|
||
'〽': '〽',
|
||
'㊗': '㊗',
|
||
'㊙': '㊙',
|
||
'': '',
|
||
'️': '️'
|
||
};
|
||
|
||
// Function to convert HTML entities to Unicode
|
||
function decodeHtmlEntities(text) {
|
||
let result = text;
|
||
|
||
// First handle numeric entities (both decimal and hex)
|
||
result = result.replace(/&#x([0-9a-fA-F]+);/g, (match, hex) => {
|
||
const codePoint = parseInt(hex, 16);
|
||
return String.fromCodePoint(codePoint);
|
||
});
|
||
|
||
result = result.replace(/&#(\d+);/g, (match, decimal) => {
|
||
const codePoint = parseInt(decimal, 10);
|
||
return String.fromCodePoint(codePoint);
|
||
});
|
||
|
||
// Then handle named entities
|
||
for (const [entity, unicode] of Object.entries(htmlEntities)) {
|
||
result = result.replace(new RegExp(entity.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), unicode);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
// Function to convert WordPress caption shortcodes to Markdown
|
||
function convertWordPressCaption(content) {
|
||
// Pattern to match WordPress caption shortcode with markdown image inside
|
||
const captionPattern = /\[caption[^\]]*\](!\[[^\]]*\]\([^)]+\))([^[\]]*)\[\/caption\]/gi;
|
||
|
||
return content.replace(captionPattern, (match, imgMarkdown, caption) => {
|
||
const cleanCaption = caption.trim();
|
||
|
||
if (cleanCaption) {
|
||
return `${imgMarkdown}\n*${cleanCaption}*`;
|
||
} else {
|
||
return imgMarkdown;
|
||
}
|
||
});
|
||
}
|
||
|
||
// Function to convert WordPress image URLs to Astro asset paths
|
||
function convertWordPressUrlToAssetPath(url) {
|
||
// Pattern to match WordPress upload URLs
|
||
const wpUploadPattern = /https?:\/\/[^\/]+\/wp-content\/uploads\/(\d{4})\/(\d{2})\/(.+)/;
|
||
const match = url.match(wpUploadPattern);
|
||
|
||
if (match) {
|
||
const [, year, month, filename] = match;
|
||
return `~/assets/images/${year}/${month}/${filename}`;
|
||
}
|
||
|
||
// If it's already an asset path, return as is
|
||
if (url.startsWith('~/assets/images/')) {
|
||
return url;
|
||
}
|
||
|
||
// If it's a relative path, convert to asset path
|
||
if (url.startsWith('/assets/images/')) {
|
||
return `~${url}`;
|
||
}
|
||
|
||
// For other cases, return as is
|
||
return url;
|
||
}
|
||
|
||
// Function to find existing image files
|
||
async function findExistingImages(assetsDir) {
|
||
const imageMap = new Map();
|
||
|
||
async function scanDirectory(dir) {
|
||
try {
|
||
const entries = await readdir(dir);
|
||
|
||
for (const entry of entries) {
|
||
const fullPath = path.join(dir, entry);
|
||
const stats = await stat(fullPath);
|
||
|
||
if (stats.isDirectory()) {
|
||
await scanDirectory(fullPath);
|
||
} else if (stats.isFile() && /\.(jpg|jpeg|png|gif|svg|webp)$/i.test(entry)) {
|
||
const relativePath = path.relative(assetsDir, fullPath);
|
||
const assetPath = `~/assets/images/${relativePath.replace(/\\/g, '/')}`;
|
||
imageMap.set(entry.toLowerCase(), assetPath);
|
||
|
||
// Also map without extension for flexible matching
|
||
const nameWithoutExt = entry.replace(/\.[^.]+$/, '').toLowerCase();
|
||
if (!imageMap.has(nameWithoutExt)) {
|
||
imageMap.set(nameWithoutExt, assetPath);
|
||
}
|
||
}
|
||
}
|
||
} catch (error) {
|
||
// Directory might not exist, continue
|
||
}
|
||
}
|
||
|
||
await scanDirectory(assetsDir);
|
||
return imageMap;
|
||
}
|
||
|
||
// Function to process a single markdown file
|
||
async function processMarkdownFile(filePath, logger, imageMap) {
|
||
try {
|
||
const content = await readFile(filePath, 'utf-8');
|
||
const originalContent = content;
|
||
|
||
let processedContent = content;
|
||
let changes = [];
|
||
|
||
// 1. Convert HTML entities to Unicode
|
||
const entitiesConverted = decodeHtmlEntities(processedContent);
|
||
if (entitiesConverted !== processedContent) {
|
||
changes.push('HTML entities converted to Unicode');
|
||
processedContent = entitiesConverted;
|
||
}
|
||
|
||
// 2. Convert WordPress caption shortcodes
|
||
const captionsConverted = convertWordPressCaption(processedContent);
|
||
if (captionsConverted !== processedContent) {
|
||
changes.push('WordPress caption shortcodes converted to Markdown');
|
||
processedContent = captionsConverted;
|
||
}
|
||
|
||
// 3. Convert WordPress image URLs to Astro asset paths
|
||
const imageUrlPattern = /https?:\/\/[^\/]+\/wp-content\/uploads\/\d{4}\/\d{2}\/[^\s)]+\.(jpg|jpeg|png|gif|svg|webp)/gi;
|
||
const imageUrlsConverted = processedContent.replace(imageUrlPattern, (match) => {
|
||
changes.push(`WordPress image URL converted: ${match}`);
|
||
return convertWordPressUrlToAssetPath(match);
|
||
});
|
||
|
||
if (imageUrlsConverted !== processedContent) {
|
||
processedContent = imageUrlsConverted;
|
||
}
|
||
|
||
// 4. Fix any broken image references by matching with existing files
|
||
const imageRefPattern = /!\[([^\]]*)\]\(([^)]+)\)/g;
|
||
processedContent = processedContent.replace(imageRefPattern, (match, alt, src) => {
|
||
// If it's already a proper asset path, leave it alone
|
||
if (src.startsWith('~/assets/images/')) {
|
||
return match;
|
||
}
|
||
|
||
// Try to find the image in our map
|
||
const filename = path.basename(src).toLowerCase();
|
||
const nameWithoutExt = filename.replace(/\.[^.]+$/, '');
|
||
|
||
if (imageMap.has(filename)) {
|
||
changes.push(`Image reference fixed: ${src} -> ${imageMap.get(filename)}`);
|
||
return `})`;
|
||
} else if (imageMap.has(nameWithoutExt)) {
|
||
changes.push(`Image reference fixed: ${src} -> ${imageMap.get(nameWithoutExt)}`);
|
||
return `})`;
|
||
}
|
||
|
||
return match;
|
||
});
|
||
|
||
// Only write file if there were changes
|
||
if (processedContent !== originalContent) {
|
||
await writeFile(filePath, processedContent, 'utf-8');
|
||
logger.log('info', `Processed file with changes: ${changes.join(', ')}`, filePath);
|
||
return { processed: true, changes };
|
||
} else {
|
||
logger.log('info', 'No changes needed', filePath);
|
||
return { processed: false, changes: [] };
|
||
}
|
||
|
||
} catch (error) {
|
||
logger.log('error', `Error processing file: ${error.message}`, filePath);
|
||
return { processed: false, changes: [], error: error.message };
|
||
}
|
||
}
|
||
|
||
// Function to create backup of posts
|
||
async function createBackup(postsDir, backupDir) {
|
||
try {
|
||
// Create backup directory if it doesn't exist
|
||
if (!fs.existsSync(backupDir)) {
|
||
fs.mkdirSync(backupDir, { recursive: true });
|
||
}
|
||
|
||
const files = await readdir(postsDir);
|
||
let backupCount = 0;
|
||
|
||
for (const file of files) {
|
||
if (file.endsWith('.md') || file.endsWith('.mdx')) {
|
||
const sourcePath = path.join(postsDir, file);
|
||
const backupPath = path.join(backupDir, file);
|
||
|
||
const content = await readFile(sourcePath, 'utf-8');
|
||
await writeFile(backupPath, content, 'utf-8');
|
||
backupCount++;
|
||
}
|
||
}
|
||
|
||
return backupCount;
|
||
} catch (error) {
|
||
throw new Error(`Failed to create backup: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
// Main function
|
||
async function main() {
|
||
const logger = new Logger(config.logFile);
|
||
|
||
logger.log('info', 'Starting blog post processing...');
|
||
|
||
try {
|
||
// Create backup
|
||
logger.log('info', 'Creating backup of blog posts...');
|
||
const backupCount = await createBackup(config.postsDirectory, config.backupDirectory);
|
||
logger.log('info', `Backup created: ${backupCount} files backed up to ${config.backupDirectory}`);
|
||
|
||
// Scan for existing images
|
||
logger.log('info', 'Scanning for existing images...');
|
||
const imageMap = await findExistingImages(config.assetsDirectory);
|
||
logger.log('info', `Found ${imageMap.size} images in assets directory`);
|
||
|
||
// Process all markdown files
|
||
logger.log('info', 'Processing markdown files...');
|
||
const files = await readdir(config.postsDirectory);
|
||
const markdownFiles = files.filter(file => file.endsWith('.md') || file.endsWith('.mdx'));
|
||
|
||
let processedCount = 0;
|
||
let changedCount = 0;
|
||
let errorCount = 0;
|
||
const allChanges = [];
|
||
|
||
for (const file of markdownFiles) {
|
||
const filePath = path.join(config.postsDirectory, file);
|
||
const result = await processMarkdownFile(filePath, logger, imageMap);
|
||
|
||
processedCount++;
|
||
|
||
if (result.error) {
|
||
errorCount++;
|
||
} else if (result.processed) {
|
||
changedCount++;
|
||
allChanges.push({ file, changes: result.changes });
|
||
}
|
||
}
|
||
|
||
// Summary
|
||
logger.log('info', `Processing complete:`);
|
||
logger.log('info', ` - Total files processed: ${processedCount}`);
|
||
logger.log('info', ` - Files with changes: ${changedCount}`);
|
||
logger.log('info', ` - Files with errors: ${errorCount}`);
|
||
logger.log('info', ` - Files unchanged: ${processedCount - changedCount - errorCount}`);
|
||
|
||
if (allChanges.length > 0) {
|
||
logger.log('info', '\nSummary of changes:');
|
||
allChanges.forEach(({ file, changes }) => {
|
||
logger.log('info', ` ${file}:`);
|
||
changes.forEach(change => {
|
||
logger.log('info', ` - ${change}`);
|
||
});
|
||
});
|
||
}
|
||
|
||
// Save logs
|
||
await logger.saveLogs();
|
||
|
||
console.log('\n✅ Blog post processing completed successfully!');
|
||
console.log(`📄 Check ${config.logFile} for detailed logs`);
|
||
console.log(`💾 Backup created in ${config.backupDirectory}`);
|
||
|
||
} catch (error) {
|
||
logger.log('error', `Fatal error: ${error.message}`);
|
||
await logger.saveLogs();
|
||
console.error('❌ Processing failed:', error.message);
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
// Run the script
|
||
if (require.main === module) {
|
||
main().catch(console.error);
|
||
}
|
||
|
||
module.exports = {
|
||
decodeHtmlEntities,
|
||
convertWordPressCaption,
|
||
convertWordPressUrlToAssetPath,
|
||
findExistingImages,
|
||
processMarkdownFile,
|
||
createBackup
|
||
}; |