mirror of
https://github.com/steelbrain/ffmpeg-over-ip.git
synced 2024-10-12 01:34:56 +03:00
🆕 Add basic logger and configs
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,2 +1,7 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
/lib
|
||||
|
||||
# Testing configs
|
||||
ffmpeg-over-ip.client.jsonc
|
||||
ffmpeg-over-ip.server.jsonc
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"ignoreUnknown": true
|
||||
"ignoreUnknown": true,
|
||||
"ignore": ["lib/"]
|
||||
},
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
|
||||
@@ -4,12 +4,15 @@
|
||||
"description": "TODO",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"build:server": "esbuild src/server.ts --platform=node --bundle --outdir=lib",
|
||||
"watch:server": "esbuild src/server.ts --platform=node --bundle --outdir=lib --watch"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.5.3",
|
||||
"@types/node": "20",
|
||||
"esbuild": "^0.20.0",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
||||
|
||||
7
src/config.ts
Normal file
7
src/config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { CONFIG_FILE_ENV, CONFIG_FILE_NAMES, Runtime } from './constants'
|
||||
|
||||
export function loadConfig(runtime: Runtime): Config {
|
||||
const configFile = process.env[CONFIG_FILE_ENV] || CONFIG_FILE_NAMES[runtime]
|
||||
const config = require(`./${configFile}`)
|
||||
return config
|
||||
}
|
||||
50
src/constants.ts
Normal file
50
src/constants.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import os from 'node:os'
|
||||
import path from 'node:path'
|
||||
|
||||
export enum Runtime {
|
||||
Server = 'server',
|
||||
Client = 'client',
|
||||
}
|
||||
|
||||
export const CONFIG_FILE_ENV = 'FFMPEG_OVER_IP_CONFIG_FILE'
|
||||
|
||||
const CONFIG_FILE_NAMES_SERVER_FULL = ['ffmpeg-over-ip.server.json', 'ffmpeg-over-ip.server.jsonc']
|
||||
const CONFIG_FILE_NAMES_SERVER_SHORT = ['config.server.json', 'config.server.jsonc']
|
||||
|
||||
const CONFIG_FILE_NAMES_CLIENT_FULL = ['ffmpeg-over-ip.client.json', 'ffmpeg-over-ip.client.jsonc']
|
||||
const CONFIG_FILE_NAMES_CLIENT_SHORT = ['config.client.json', 'config.client.jsonc']
|
||||
|
||||
const CONFIG_FILE_SEARCH_PATHS = [
|
||||
['/etc/ffmpeg-over-ip', CONFIG_FILE_NAMES_SERVER_SHORT, CONFIG_FILE_NAMES_CLIENT_SHORT],
|
||||
['/etc', CONFIG_FILE_NAMES_SERVER_FULL, CONFIG_FILE_NAMES_CLIENT_FULL],
|
||||
[
|
||||
path.join(os.homedir(), '.config', 'ffmpeg-over-ip'),
|
||||
CONFIG_FILE_NAMES_SERVER_SHORT,
|
||||
CONFIG_FILE_NAMES_CLIENT_SHORT,
|
||||
],
|
||||
[
|
||||
path.join(os.homedir(), '.config'),
|
||||
CONFIG_FILE_NAMES_SERVER_FULL,
|
||||
CONFIG_FILE_NAMES_CLIENT_FULL,
|
||||
],
|
||||
[process.cwd(), CONFIG_FILE_NAMES_SERVER_FULL, CONFIG_FILE_NAMES_CLIENT_FULL],
|
||||
]
|
||||
|
||||
if (process.argv.length > 1) {
|
||||
const execDirectory = path.dirname(`${process.argv[1]}`)
|
||||
CONFIG_FILE_SEARCH_PATHS.push([
|
||||
execDirectory,
|
||||
CONFIG_FILE_NAMES_SERVER_FULL,
|
||||
CONFIG_FILE_NAMES_CLIENT_FULL,
|
||||
])
|
||||
}
|
||||
|
||||
export const CONFIG_FILE_SEARCH_PATHS_SERVER = CONFIG_FILE_SEARCH_PATHS.map(([path, server]) => [
|
||||
path,
|
||||
server,
|
||||
])
|
||||
|
||||
export const CONFIG_FILE_SEARCH_PATHS_CLIENT = CONFIG_FILE_SEARCH_PATHS.map(([path, , client]) => [
|
||||
path,
|
||||
client,
|
||||
])
|
||||
29
src/logger.ts
Normal file
29
src/logger.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import fs from 'node:fs'
|
||||
|
||||
export default function createLogger(logFile: string | false) {
|
||||
function logToOutput(prefix: string, message: string) {
|
||||
if (logFile === false) {
|
||||
return
|
||||
}
|
||||
if (logFile === 'stdout') {
|
||||
console.log(prefix, message)
|
||||
return
|
||||
}
|
||||
if (logFile === 'error') {
|
||||
console.error(prefix, message)
|
||||
return
|
||||
}
|
||||
fs.appendFile(logFile, `${prefix} ${message}\n`, err => {
|
||||
console.error(`Error writing to logfile at ${logFile}`, { err })
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
log: (message: string) => {
|
||||
logToOutput('[INFO]', message)
|
||||
},
|
||||
error: (message: string) => {
|
||||
logToOutput('[ERROR]', message)
|
||||
},
|
||||
}
|
||||
}
|
||||
13
src/server.ts
Normal file
13
src/server.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { CONFIG_FILE_SEARCH_PATHS_SERVER } from './constants'
|
||||
|
||||
async function main() {
|
||||
if (process.argv.includes('--internal-print-search-paths')) {
|
||||
console.log(CONFIG_FILE_SEARCH_PATHS_SERVER)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
console.error('Error during initialization', { err })
|
||||
process.exit(1)
|
||||
})
|
||||
14
template.ffmpeg-over-ip.client.jsonc
Normal file
14
template.ffmpeg-over-ip.client.jsonc
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
// This is a "jsonc" file and therefore supports comments in addition to standard JSON syntax
|
||||
|
||||
"log": "stdout", // type: "stdout" | "stderr" | any string (file path) | false
|
||||
// Other possibilities:
|
||||
"log": "$TMP/ffmpeg-over-ip.server.log",
|
||||
// ^ $TMP is a special variable here, only supported in "log" config where it uses the operating system
|
||||
// temp folder
|
||||
"log": false,
|
||||
// ^ This turns off logging completely
|
||||
"log": "stdout",
|
||||
"log": "stderr",
|
||||
"log": "/var/log/messages.log"
|
||||
}
|
||||
14
template.ffmpeg-over-ip.server.jsonc
Normal file
14
template.ffmpeg-over-ip.server.jsonc
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
// This is a "jsonc" file and therefore supports comments in addition to standard JSON syntax
|
||||
|
||||
"log": "stdout", // type: "stdout" | "stderr" | any string (file path) | false
|
||||
// Other possibilities:
|
||||
"log": "$TMP/ffmpeg-over-ip.server.log",
|
||||
// ^ $TMP is a special variable here, only supported in "log" config where it uses the operating system
|
||||
// temp folder
|
||||
"log": false,
|
||||
// ^ This turns off logging completely
|
||||
"log": "stdout",
|
||||
"log": "stderr",
|
||||
"log": "/var/log/messages.log"
|
||||
}
|
||||
156
yarn.lock
156
yarn.lock
@@ -56,7 +56,163 @@
|
||||
resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-1.5.3.tgz#1a424f26b709bc17fc592de18e8f48a6d2a44c86"
|
||||
integrity sha512-fMvbSouZEASU7mZH8SIJSANDm5OqsjgtVXlbUqxwed6BP7uuHRSs396Aqwh2+VoW8fwTpp6ybIUoC9FrzB0kyA==
|
||||
|
||||
"@esbuild/aix-ppc64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.20.0.tgz#509621cca4e67caf0d18561a0c56f8b70237472f"
|
||||
integrity sha512-fGFDEctNh0CcSwsiRPxiaqX0P5rq+AqE0SRhYGZ4PX46Lg1FNR6oCxJghf8YgY0WQEgQuh3lErUFE4KxLeRmmw==
|
||||
|
||||
"@esbuild/android-arm64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.20.0.tgz#109a6fdc4a2783fc26193d2687827045d8fef5ab"
|
||||
integrity sha512-aVpnM4lURNkp0D3qPoAzSG92VXStYmoVPOgXveAUoQBWRSuQzt51yvSju29J6AHPmwY1BjH49uR29oyfH1ra8Q==
|
||||
|
||||
"@esbuild/android-arm@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.20.0.tgz#1397a2c54c476c4799f9b9073550ede496c94ba5"
|
||||
integrity sha512-3bMAfInvByLHfJwYPJRlpTeaQA75n8C/QKpEaiS4HrFWFiJlNI0vzq/zCjBrhAYcPyVPG7Eo9dMrcQXuqmNk5g==
|
||||
|
||||
"@esbuild/android-x64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.20.0.tgz#2b615abefb50dc0a70ac313971102f4ce2fdb3ca"
|
||||
integrity sha512-uK7wAnlRvjkCPzh8jJ+QejFyrP8ObKuR5cBIsQZ+qbMunwR8sbd8krmMbxTLSrDhiPZaJYKQAU5Y3iMDcZPhyQ==
|
||||
|
||||
"@esbuild/darwin-arm64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.20.0.tgz#5c122ed799eb0c35b9d571097f77254964c276a2"
|
||||
integrity sha512-AjEcivGAlPs3UAcJedMa9qYg9eSfU6FnGHJjT8s346HSKkrcWlYezGE8VaO2xKfvvlZkgAhyvl06OJOxiMgOYQ==
|
||||
|
||||
"@esbuild/darwin-x64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.20.0.tgz#9561d277002ba8caf1524f209de2b22e93d170c1"
|
||||
integrity sha512-bsgTPoyYDnPv8ER0HqnJggXK6RyFy4PH4rtsId0V7Efa90u2+EifxytE9pZnsDgExgkARy24WUQGv9irVbTvIw==
|
||||
|
||||
"@esbuild/freebsd-arm64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.0.tgz#84178986a3138e8500d17cc380044868176dd821"
|
||||
integrity sha512-kQ7jYdlKS335mpGbMW5tEe3IrQFIok9r84EM3PXB8qBFJPSc6dpWfrtsC/y1pyrz82xfUIn5ZrnSHQQsd6jebQ==
|
||||
|
||||
"@esbuild/freebsd-x64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.20.0.tgz#3f9ce53344af2f08d178551cd475629147324a83"
|
||||
integrity sha512-uG8B0WSepMRsBNVXAQcHf9+Ko/Tr+XqmK7Ptel9HVmnykupXdS4J7ovSQUIi0tQGIndhbqWLaIL/qO/cWhXKyQ==
|
||||
|
||||
"@esbuild/linux-arm64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.20.0.tgz#24efa685515689df4ecbc13031fa0a9dda910a11"
|
||||
integrity sha512-uTtyYAP5veqi2z9b6Gr0NUoNv9F/rOzI8tOD5jKcCvRUn7T60Bb+42NDBCWNhMjkQzI0qqwXkQGo1SY41G52nw==
|
||||
|
||||
"@esbuild/linux-arm@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.20.0.tgz#6b586a488e02e9b073a75a957f2952b3b6e87b4c"
|
||||
integrity sha512-2ezuhdiZw8vuHf1HKSf4TIk80naTbP9At7sOqZmdVwvvMyuoDiZB49YZKLsLOfKIr77+I40dWpHVeY5JHpIEIg==
|
||||
|
||||
"@esbuild/linux-ia32@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.20.0.tgz#84ce7864f762708dcebc1b123898a397dea13624"
|
||||
integrity sha512-c88wwtfs8tTffPaoJ+SQn3y+lKtgTzyjkD8NgsyCtCmtoIC8RDL7PrJU05an/e9VuAke6eJqGkoMhJK1RY6z4w==
|
||||
|
||||
"@esbuild/linux-loong64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.20.0.tgz#1922f571f4cae1958e3ad29439c563f7d4fd9037"
|
||||
integrity sha512-lR2rr/128/6svngnVta6JN4gxSXle/yZEZL3o4XZ6esOqhyR4wsKyfu6qXAL04S4S5CgGfG+GYZnjFd4YiG3Aw==
|
||||
|
||||
"@esbuild/linux-mips64el@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.20.0.tgz#7ca1bd9df3f874d18dbf46af009aebdb881188fe"
|
||||
integrity sha512-9Sycc+1uUsDnJCelDf6ZNqgZQoK1mJvFtqf2MUz4ujTxGhvCWw+4chYfDLPepMEvVL9PDwn6HrXad5yOrNzIsQ==
|
||||
|
||||
"@esbuild/linux-ppc64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.20.0.tgz#8f95baf05f9486343bceeb683703875d698708a4"
|
||||
integrity sha512-CoWSaaAXOZd+CjbUTdXIJE/t7Oz+4g90A3VBCHLbfuc5yUQU/nFDLOzQsN0cdxgXd97lYW/psIIBdjzQIwTBGw==
|
||||
|
||||
"@esbuild/linux-riscv64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.20.0.tgz#ca63b921d5fe315e28610deb0c195e79b1a262ca"
|
||||
integrity sha512-mlb1hg/eYRJUpv8h/x+4ShgoNLL8wgZ64SUr26KwglTYnwAWjkhR2GpoKftDbPOCnodA9t4Y/b68H4J9XmmPzA==
|
||||
|
||||
"@esbuild/linux-s390x@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.20.0.tgz#cb3d069f47dc202f785c997175f2307531371ef8"
|
||||
integrity sha512-fgf9ubb53xSnOBqyvWEY6ukBNRl1mVX1srPNu06B6mNsNK20JfH6xV6jECzrQ69/VMiTLvHMicQR/PgTOgqJUQ==
|
||||
|
||||
"@esbuild/linux-x64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.20.0.tgz#ac617e0dc14e9758d3d7efd70288c14122557dc7"
|
||||
integrity sha512-H9Eu6MGse++204XZcYsse1yFHmRXEWgadk2N58O/xd50P9EvFMLJTQLg+lB4E1cF2xhLZU5luSWtGTb0l9UeSg==
|
||||
|
||||
"@esbuild/netbsd-x64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.20.0.tgz#6cc778567f1513da6e08060e0aeb41f82eb0f53c"
|
||||
integrity sha512-lCT675rTN1v8Fo+RGrE5KjSnfY0x9Og4RN7t7lVrN3vMSjy34/+3na0q7RIfWDAj0e0rCh0OL+P88lu3Rt21MQ==
|
||||
|
||||
"@esbuild/openbsd-x64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.20.0.tgz#76848bcf76b4372574fb4d06cd0ed1fb29ec0fbe"
|
||||
integrity sha512-HKoUGXz/TOVXKQ+67NhxyHv+aDSZf44QpWLa3I1lLvAwGq8x1k0T+e2HHSRvxWhfJrFxaaqre1+YyzQ99KixoA==
|
||||
|
||||
"@esbuild/sunos-x64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.20.0.tgz#ea4cd0639bf294ad51bc08ffbb2dac297e9b4706"
|
||||
integrity sha512-GDwAqgHQm1mVoPppGsoq4WJwT3vhnz/2N62CzhvApFD1eJyTroob30FPpOZabN+FgCjhG+AgcZyOPIkR8dfD7g==
|
||||
|
||||
"@esbuild/win32-arm64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.20.0.tgz#a5c171e4a7f7e4e8be0e9947a65812c1535a7cf0"
|
||||
integrity sha512-0vYsP8aC4TvMlOQYozoksiaxjlvUcQrac+muDqj1Fxy6jh9l9CZJzj7zmh8JGfiV49cYLTorFLxg7593pGldwQ==
|
||||
|
||||
"@esbuild/win32-ia32@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.20.0.tgz#f8ac5650c412d33ea62d7551e0caf82da52b7f85"
|
||||
integrity sha512-p98u4rIgfh4gdpV00IqknBD5pC84LCub+4a3MO+zjqvU5MVXOc3hqR2UgT2jI2nh3h8s9EQxmOsVI3tyzv1iFg==
|
||||
|
||||
"@esbuild/win32-x64@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.20.0.tgz#2efddf82828aac85e64cef62482af61c29561bee"
|
||||
integrity sha512-NgJnesu1RtWihtTtXGFMU5YSE6JyyHPMxCwBZK7a6/8d31GuSo9l0Ss7w1Jw5QnKUawG6UEehs883kcXf5fYwg==
|
||||
|
||||
"@types/node@20":
|
||||
version "20.11.17"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.17.tgz#cdd642d0e62ef3a861f88ddbc2b61e32578a9292"
|
||||
integrity sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw==
|
||||
dependencies:
|
||||
undici-types "~5.26.4"
|
||||
|
||||
esbuild@^0.20.0:
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.20.0.tgz#a7170b63447286cd2ff1f01579f09970e6965da4"
|
||||
integrity sha512-6iwE3Y2RVYCME1jLpBqq7LQWK3MW6vjV2bZy6gt/WrqkY+WE74Spyc0ThAOYpMtITvnjX09CrC6ym7A/m9mebA==
|
||||
optionalDependencies:
|
||||
"@esbuild/aix-ppc64" "0.20.0"
|
||||
"@esbuild/android-arm" "0.20.0"
|
||||
"@esbuild/android-arm64" "0.20.0"
|
||||
"@esbuild/android-x64" "0.20.0"
|
||||
"@esbuild/darwin-arm64" "0.20.0"
|
||||
"@esbuild/darwin-x64" "0.20.0"
|
||||
"@esbuild/freebsd-arm64" "0.20.0"
|
||||
"@esbuild/freebsd-x64" "0.20.0"
|
||||
"@esbuild/linux-arm" "0.20.0"
|
||||
"@esbuild/linux-arm64" "0.20.0"
|
||||
"@esbuild/linux-ia32" "0.20.0"
|
||||
"@esbuild/linux-loong64" "0.20.0"
|
||||
"@esbuild/linux-mips64el" "0.20.0"
|
||||
"@esbuild/linux-ppc64" "0.20.0"
|
||||
"@esbuild/linux-riscv64" "0.20.0"
|
||||
"@esbuild/linux-s390x" "0.20.0"
|
||||
"@esbuild/linux-x64" "0.20.0"
|
||||
"@esbuild/netbsd-x64" "0.20.0"
|
||||
"@esbuild/openbsd-x64" "0.20.0"
|
||||
"@esbuild/sunos-x64" "0.20.0"
|
||||
"@esbuild/win32-arm64" "0.20.0"
|
||||
"@esbuild/win32-ia32" "0.20.0"
|
||||
"@esbuild/win32-x64" "0.20.0"
|
||||
|
||||
typescript@^5.3.3:
|
||||
version "5.3.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37"
|
||||
integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==
|
||||
|
||||
undici-types@~5.26.4:
|
||||
version "5.26.5"
|
||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
|
||||
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
|
||||
|
||||
Reference in New Issue
Block a user