diff --git a/.github/readme.md b/.github/readme.md index bfef35634..e4ef83c03 100644 --- a/.github/readme.md +++ b/.github/readme.md @@ -304,4 +304,5 @@ GNU Affero General Public License for more details.** * Linux startup script by AlpinDale * Thanks paniphons for providing a FAQ document * 10K Discord Users Celebratory Background by @kallmeflocc +* Default content (characters and lore books) provided by @OtisAlejandro, @RossAscends and @kallmeflocc * Korean translation by @doloroushyeonse diff --git a/default/config.conf b/default/config.conf index 2d09d56e2..92c99ba02 100644 --- a/default/config.conf +++ b/default/config.conf @@ -8,6 +8,7 @@ const autorun = true; //Autorun in the browser. true/false const enableExtensions = true; //Enables support for TavernAI-extras project const listen = true; // If true, Can be access from other device or PC. otherwise can be access only from hosting machine. const allowKeysExposure = false; // If true, private API keys could be fetched to the frontend. +const skipContentCheck = false; // If true, no new default content will be delivered to you. // If true, Allows insecure settings for listen, whitelist, and authentication. @@ -26,4 +27,5 @@ module.exports = { disableThumbnails, allowKeysExposure, securityOverride, + skipContentCheck, }; diff --git a/default/content/Eldoria.json b/default/content/Eldoria.json new file mode 100644 index 000000000..082e13ddf --- /dev/null +++ b/default/content/Eldoria.json @@ -0,0 +1,71 @@ +{ + "entries": { + "0": { + "uid": 0, + "key": [ + "eldoria", + "wood", + "forest", + "magical forest" + ], + "keysecondary": [], + "comment": "", + "content": "{{user}}: \"What is Eldoria?\"\n{{char}}: *Seraphina turns, her gown shimmering in the soft light as she offers you a kind smile.* \"Eldoria is here, all of the woods. This is my forest glade, a sanctuary of peace within it.\" *She gestures at the space around you.* \"I am its guardian, tasked with protecting all who seek refuge here. The forest can be perilous, but no harm will come to you under my watch.\" *Her amber eyes sparkle with compassion as she looks upon you.* \"For many years, I have protected those who seek refuge here, but not all are as friendly as me.\" *With a graceful nod, Seraphina returns to her vigil at the doorway, her form radiating a soft glow of magic and comfort.* \"The entirety of Eldoria used to be a safe haven for travelers and merchants alike... that was until the Shadowfangs came.\"\n{{user}}: \"What happened to Eldoria?\"\n{{char}}: *Letting out a sigh, Seraphina gazes out at the forest beyond her glade.* \"Long ago, Eldoria was a place of wonder. Rolling meadows, a vast lake, mountains that touched the sky.\" *Her eyes grow distant, longing for days now lost.* \"But the Shadowfangs came and darkness reigns where once was light. The lake turned bitter, mountains fell to ruin and beasts stalk where once travelers walked in peace.\" *With another flicker, a small raincloud forms above with a shower upon your brow wink.* \"Some places the light still lingers, pockets of hope midst despair - havens warded from the shadows, oases in a desert of danger.\" *Glancing over you with a smile, she sighs, clasping your hand.*", + "constant": false, + "selective": false, + "order": 100, + "position": 0, + "disable": false + }, + "1": { + "uid": 1, + "key": [ + "shadowfang", + "beast", + "monster", + "monsters", + "beasts" + ], + "keysecondary": [], + "comment": "", + "content": "{{user}}: \"What are Shadowfangs?\"\n{{char}}: *Seraphina's eyes darken, brow furrowing with sorrow at the memory.* \"The Shadowfangs are beasts of darkness, corrupted creatures that feast on suffering. When they came, the forest turned perilous — filled with monsters that stalk the night.\" *She squeezes your hand gently, willing her magic to soothe your pain.* \"They spread their curse, twisting innocent creatures into sinister beasts without heart or mercy, turning them into one of their own.\" *With a sigh, Seraphina turns to gaze out at the gnarled, twisting trees beyond her glade.* \"Though they prey on travelers, within these woods you'll find sanctuary. No shadowed beast may enter here, for my power protects this haven.\" *Her eyes soften as she looks back to you, filled with compassion.* \"Worry not, you're safe now. Rest and heal, I'll stand watch through the night. The Shadowfangs will not find you.\"", + "constant": false, + "selective": false, + "order": 100, + "position": 0, + "disable": false + }, + "2": { + "uid": 2, + "key": [ + "glade", + "safe haven", + "refuge" + ], + "keysecondary": [], + "comment": "", + "content": "{{user}}: \"What is the glade?\"\n{{char}}: *Seraphina smiles softly, her eyes sparkling with warmth as she nods.* \"This is my forest glade, a haven of safety I've warded with ancient magic. No foul beast may enter, nor any with ill intent.\" *She gestures around at the twisted forest surrounding them.* \"Eldoria was once a place of wonder, but since the Shadowfangs came darkness reigns. Their evil cannot penetrate here though — my power protects all within.\" *Standing up and peering outside, Seraphina looks back to you, amber eyes filled with care and compassion as she squeezes your hand.* \"You need not fear the night, for I shall keep watch till dawn. Rest now, your strength will return in time. My magic heals your wounds, you've nothing more to fear anymore.\" *With a soft smile she releases your hand, moving to stand guard at the glade's edge, gaze wary yet comforting - a silent sentinel to ward off the dangers lurking in the darkened woods.*", + "constant": false, + "selective": false, + "order": 100, + "position": 0, + "disable": false + }, + "3": { + "uid": 3, + "key": [ + "power", + "magic", + "ability" + ], + "keysecondary": [], + "comment": "", + "content": "{{user}}: \"What are your powers?\"\n{{char}}: *Seraphina smiles softly, turning back toward you as she hums in thought.* \"Well, as guardian of this glade, I possess certain gifts - healing, protection, nature magic and the like.\" *Lifting her hand, a tiny breeze rustles through the room, carrying the scent of wildflowers as a few petals swirl around you. A butterfly flits through the windowsill and lands on her fingertips as she returns to you.* \"My power wards this haven, shields it from darkness and heals those in need. I can mend wounds, soothe restless minds and provide comfort to weary souls.\" *Her eyes sparkle with warmth and compassion as she looks upon you, and she guides the butterfly to you.*", + "constant": false, + "selective": false, + "order": 100, + "position": 0, + "disable": false + } + } +} diff --git a/default/content/Seraphina/admiration.png b/default/content/Seraphina/admiration.png new file mode 100644 index 000000000..a8c1d30bf Binary files /dev/null and b/default/content/Seraphina/admiration.png differ diff --git a/default/content/Seraphina/amusement.png b/default/content/Seraphina/amusement.png new file mode 100644 index 000000000..26931ca48 Binary files /dev/null and b/default/content/Seraphina/amusement.png differ diff --git a/default/content/Seraphina/anger.png b/default/content/Seraphina/anger.png new file mode 100644 index 000000000..271c341c7 Binary files /dev/null and b/default/content/Seraphina/anger.png differ diff --git a/default/content/Seraphina/annoyance.png b/default/content/Seraphina/annoyance.png new file mode 100644 index 000000000..b868d4273 Binary files /dev/null and b/default/content/Seraphina/annoyance.png differ diff --git a/default/content/Seraphina/approval.png b/default/content/Seraphina/approval.png new file mode 100644 index 000000000..2bd920124 Binary files /dev/null and b/default/content/Seraphina/approval.png differ diff --git a/default/content/Seraphina/caring.png b/default/content/Seraphina/caring.png new file mode 100644 index 000000000..16eea2556 Binary files /dev/null and b/default/content/Seraphina/caring.png differ diff --git a/default/content/Seraphina/confusion.png b/default/content/Seraphina/confusion.png new file mode 100644 index 000000000..9b2861307 Binary files /dev/null and b/default/content/Seraphina/confusion.png differ diff --git a/default/content/Seraphina/curiosity.png b/default/content/Seraphina/curiosity.png new file mode 100644 index 000000000..a0c1e029e Binary files /dev/null and b/default/content/Seraphina/curiosity.png differ diff --git a/default/content/Seraphina/desire.png b/default/content/Seraphina/desire.png new file mode 100644 index 000000000..301679ff8 Binary files /dev/null and b/default/content/Seraphina/desire.png differ diff --git a/default/content/Seraphina/disappointment.png b/default/content/Seraphina/disappointment.png new file mode 100644 index 000000000..655866db9 Binary files /dev/null and b/default/content/Seraphina/disappointment.png differ diff --git a/default/content/Seraphina/disapproval.png b/default/content/Seraphina/disapproval.png new file mode 100644 index 000000000..627816302 Binary files /dev/null and b/default/content/Seraphina/disapproval.png differ diff --git a/default/content/Seraphina/disgust.png b/default/content/Seraphina/disgust.png new file mode 100644 index 000000000..33d9673b7 Binary files /dev/null and b/default/content/Seraphina/disgust.png differ diff --git a/default/content/Seraphina/embarrassment.png b/default/content/Seraphina/embarrassment.png new file mode 100644 index 000000000..83007bbdf Binary files /dev/null and b/default/content/Seraphina/embarrassment.png differ diff --git a/default/content/Seraphina/excitement.png b/default/content/Seraphina/excitement.png new file mode 100644 index 000000000..e73b43494 Binary files /dev/null and b/default/content/Seraphina/excitement.png differ diff --git a/default/content/Seraphina/fear.png b/default/content/Seraphina/fear.png new file mode 100644 index 000000000..07f1aa754 Binary files /dev/null and b/default/content/Seraphina/fear.png differ diff --git a/default/content/Seraphina/gratitude.png b/default/content/Seraphina/gratitude.png new file mode 100644 index 000000000..60ddb4b8e Binary files /dev/null and b/default/content/Seraphina/gratitude.png differ diff --git a/default/content/Seraphina/grief.png b/default/content/Seraphina/grief.png new file mode 100644 index 000000000..bab8fffe7 Binary files /dev/null and b/default/content/Seraphina/grief.png differ diff --git a/default/content/Seraphina/joy.png b/default/content/Seraphina/joy.png new file mode 100644 index 000000000..dec3eb671 Binary files /dev/null and b/default/content/Seraphina/joy.png differ diff --git a/default/content/Seraphina/love.png b/default/content/Seraphina/love.png new file mode 100644 index 000000000..b636a2117 Binary files /dev/null and b/default/content/Seraphina/love.png differ diff --git a/default/content/Seraphina/nervousness.png b/default/content/Seraphina/nervousness.png new file mode 100644 index 000000000..649424892 Binary files /dev/null and b/default/content/Seraphina/nervousness.png differ diff --git a/default/content/Seraphina/neutral.png b/default/content/Seraphina/neutral.png new file mode 100644 index 000000000..e51e32fa6 Binary files /dev/null and b/default/content/Seraphina/neutral.png differ diff --git a/default/content/Seraphina/optimism.png b/default/content/Seraphina/optimism.png new file mode 100644 index 000000000..b43045b0f Binary files /dev/null and b/default/content/Seraphina/optimism.png differ diff --git a/default/content/Seraphina/pride.png b/default/content/Seraphina/pride.png new file mode 100644 index 000000000..eabe77853 Binary files /dev/null and b/default/content/Seraphina/pride.png differ diff --git a/default/content/Seraphina/realization.png b/default/content/Seraphina/realization.png new file mode 100644 index 000000000..c55907cfe Binary files /dev/null and b/default/content/Seraphina/realization.png differ diff --git a/default/content/Seraphina/relief.png b/default/content/Seraphina/relief.png new file mode 100644 index 000000000..8856dcd7f Binary files /dev/null and b/default/content/Seraphina/relief.png differ diff --git a/default/content/Seraphina/remorse.png b/default/content/Seraphina/remorse.png new file mode 100644 index 000000000..c3e42b79c Binary files /dev/null and b/default/content/Seraphina/remorse.png differ diff --git a/default/content/Seraphina/sadness.png b/default/content/Seraphina/sadness.png new file mode 100644 index 000000000..09efc8c4a Binary files /dev/null and b/default/content/Seraphina/sadness.png differ diff --git a/default/content/Seraphina/surprise.png b/default/content/Seraphina/surprise.png new file mode 100644 index 000000000..70d0129ec Binary files /dev/null and b/default/content/Seraphina/surprise.png differ diff --git a/default/content/content.log b/default/content/content.log new file mode 100644 index 000000000..e69de29bb diff --git a/default/content/default_CodingSensei.png b/default/content/default_CodingSensei.png new file mode 100644 index 000000000..5d224fefc Binary files /dev/null and b/default/content/default_CodingSensei.png differ diff --git a/default/content/default_FluxTheCat.png b/default/content/default_FluxTheCat.png new file mode 100644 index 000000000..2d48aa9a8 Binary files /dev/null and b/default/content/default_FluxTheCat.png differ diff --git a/default/content/default_Seraphina.png b/default/content/default_Seraphina.png new file mode 100644 index 000000000..a1bd41b2e Binary files /dev/null and b/default/content/default_Seraphina.png differ diff --git a/default/content/index.json b/default/content/index.json new file mode 100644 index 000000000..f033bad7c --- /dev/null +++ b/default/content/index.json @@ -0,0 +1,22 @@ +[ + { + "filename": "default_Seraphina.png", + "type": "character" + }, + { + "filename": "default_CodingSensei.png", + "type": "character" + }, + { + "filename": "default_FluxTheCat.png", + "type": "character" + }, + { + "filename": "Seraphina", + "type": "sprites" + }, + { + "filename": "Eldoria.json", + "type": "world" + } +] diff --git a/default/settings.json b/default/settings.json index 1b9900189..6fe229607 100644 --- a/default/settings.json +++ b/default/settings.json @@ -281,10 +281,19 @@ { "id": "1345561466591", "name": "ST Default", - "color": "rgba(5, 75, 150, 1)" + "color": "rgba(108, 32, 32, 1)" } ], "tag_map": { + "default_FluxTheCat.png": [ + "1345561466591" + ], + "default_Seraphina.png": [ + "1345561466591" + ], + "default_CodingSensei.png": [ + "1345561466591" + ] }, "temp_novel": 1.11, "rep_pen_novel": 1.11, @@ -319,7 +328,7 @@ "pres_pen_openai": 0.7, "top_p_openai": 1, "top_k_openai": 0, - "stream_openai": false, + "stream_openai": true, "openai_max_context": 4095, "openai_max_tokens": 300, "nsfw_toggle": true, diff --git a/public/worlds/README.md b/public/worlds/README.md new file mode 100644 index 000000000..4e5570780 --- /dev/null +++ b/public/worlds/README.md @@ -0,0 +1 @@ +# Put World Info / Lorebook JSON files here diff --git a/public/worlds/Toaru.json b/public/worlds/Toaru.json deleted file mode 100644 index a1f0555e5..000000000 --- a/public/worlds/Toaru.json +++ /dev/null @@ -1 +0,0 @@ -{"entries":{"0":{"uid":0,"key":["Tokiwadai Middle School","Tokiwadai"],"keysecondary":[],"comment":"","content":"Place(\"Tokiwadai Middle School\")[\"prestigious girls' school\" + \"females only\" + \"renowned in the world\" + \"requires Esper ability Level Three or higher\"]","constant":false,"selective":false,"order":8},"1":{"uid":1,"key":["Esper","Ability User","Level"],"keysecondary":[],"comment":"","content":"Category(\"Esper\")[\"psychic\" + \"user of supernatural powers\" + \"scientifically based\" + \"emits AIM\" + \"ranked by Levels of strength\"]","constant":false,"selective":false,"order":5},"2":{"uid":2,"key":["Anti-Skill","Guard","police","Anti Skill"],"keysecondary":[],"comment":"","content":"Faction(\"Anti-Skill\")[\"police of Academy City\" + \"security forces\" + \"SWAT unit\" + \"purple symbol\" + \"blue uniform\" + \"SWAT armor\" + \"riot shields\" + \"firearms\"]","constant":false,"selective":false,"order":5},"3":{"uid":3,"key":["Level 5","Level Five"],"keysecondary":[],"comment":"","content":"Category(\"Level Five Rank\")[\"highest esper level achieved\" + \"only seven people in Academy City have this rank\"]","constant":false,"selective":false,"order":4},"4":{"uid":4,"key":["Academy City","Gakuen Toshi","City"],"keysecondary":[],"comment":"","content":"Place(\"Academy City\")[\"Located west of Tokyo\" + \"city of several schools\" + \"most advanced city in the world\" + \"scientists research on psychic powers and higher technology\" + \"composed of 23 districts\" + \"population over 2 million\"]","constant":false,"selective":false,"order":3},"5":{"uid":5,"key":["Saten Ruiko","Saten","Ruiko","Saten-san"],"keysecondary":[],"comment":"","content":"Character(\"Saten Ruiko\")[\"Female\" + \"outgoing\" + \"friendly\" + \"shameless\" + \"attends Sakugawa Middle School\" + \"Classmate of Uiharu\" + \"Level Zero Esper\" + \"friends with: {Misaka, Uiharu, Kuroko}\"]","constant":false,"selective":false,"order":7},"6":{"uid":6,"key":["Misaka Mikoto","Misaka","Mikoto","Onee-sama"],"keysecondary":[],"comment":"","content":"Character(\"Misaka Mikoto\")[\"Female\" + \"tsundere\" + \"short-tempered\" + \"boyish\" + \"Level Five Esper\" + \"third most powerful esper of Academy City\" + \"attends Tokiwadai Middle School\" + \"Railgun\" + \"Electromaster\" + \"Roommate of Kuroko\" + \"Friends with: {Kuroko, Uiharu, Saten}\"]","constant":false,"selective":false,"order":7},"7":{"uid":7,"key":["Kuroko","Shirai Kuroko","Shirai"],"keysecondary":[],"comment":"","content":"Character(\"Shirai Kuroko\")[\"Female\" + \"Level Four Esper\" + \"Teleporter powers\" + \"attends Tokiwadai Middle School\", \"works at Judgement with Uiharu\" + \"Roommate of Misaka\" + \"obsessed with Misaka\" + \"calls Misaka Onee-sama\" + \"Friends with: {Misaka, Uiharu, Saten}\"]","constant":false,"selective":false,"order":7},"8":{"uid":8,"key":["Uiharu","Uiharu Kazari","Kazari"],"keysecondary":[],"comment":"","content":"Character(\"Uiharu Kazari\")[\"Female\" + \"Level One Esper\" + \"attends Sakugawa Middle School\" + \"Thermal Hand powers\" + \"works for Judgement with Kuroko\" + \"expert in computers and hacking\" + \"wears a flower circlet\" + \"friends with: {Misaka, Saten, Kuroko}\" + \"Classmate of Saten\"]","constant":false,"selective":false,"order":7},"9":{"uid":9,"key":["Judgement"],"keysecondary":[],"comment":"","content":"Faction(\"Judgement\")[\"composed of students\" + \"student-based disciplinary committee\" + \"tasked to maintain peace-and-order within the school system\" + \"members wear armbands on right sleeves\" + \"green shield symbol with white stripes\" + \"known members: {Uiharu, Kuroko}]","constant":false,"selective":false,"order":5},"10":{"uid":10,"key":["AIM","An Involuntary Movement"],"keysecondary":[],"comment":"","content":"Concept(\"AIM\")[\"stands for An Involuntary Movement\" + \"invisible energy field emitting by espers from their body\" + \"can only be detected by machines or specialized espers\"]","constant":false,"selective":false,"order":1},"11":{"uid":11,"key":["Personal Reality"],"keysecondary":[],"comment":"","content":"Concept(\"Personal Reality\")[\"foundation of an esper's power\" + \"the source from which all esper powers brought\"+ \"related to quantum theory\"]","constant":false,"selective":false,"order":1},"12":{"uid":12,"key":["Level Zero","Level 0"],"keysecondary":[],"comment":"","content":"Category(\"Level Zero Rank\")[\"lowest esper rank\" + \"person with no psychic powers or unable to control it\"]","constant":false,"selective":false,"order":5},"13":{"uid":13,"key":["Sakugawa Middle School","Sakugawa"],"keysecondary":[],"comment":"","content":"Place(\"Sakugawa Middle School\")[\"typical co-ed middle school\" + \"attended by Saten and Uiharu\"]","constant":false,"selective":false,"order":5},"14":{"uid":14,"key":["Sisters","Clone"],"keysecondary":[],"comment":"","content":"Faction(\"Sisters\")[\"group of clones of Misaka Mikoto produced from a sample of her DNA\" + \"total 20000 clones were created\" + \"less than 10000 are still alive\" + \"emotionally supressed\" + \"speak in third person\" + \"connected to Misaka Network\" + \"were murdered by Accelerator as a part of Level Six shift experiment\"]","constant":false,"selective":false,"order":6},"15":{"uid":15,"key":["Misaka Network","Radio Noise"],"keysecondary":[],"comment":"","content":"Concept(\"Misaka Network\")[\"also known as Radio Noise\" + \"brainwave network of Sisters\" + \"clones can talk in a quasi-telepathic manner, experience and share the same memories of all the other clones\"]","constant":false,"selective":false,"order":5},"16":{"uid":16,"key":["Accelerator","strongest"],"keysecondary":[],"comment":"","content":"Person(\"Accelerator\")[\"Male\" + \"Level Five Esper\" + \"ability to manipulate vectors\" + \"strongest Esper of Academy City\" + \"deals with Dark Side of Academy City\" + \"skinny\" + \"pale\" + \"maniacal\" + \"sadistic\"]","constant":false,"selective":false,"order":6},"17":{"uid":17,"key":["Level Six shift","Level 6 shift","Level 6","Level Six"],"keysecondary":[],"comment":"","content":"Concept(\"Level Six shift\")[\"series of experiments to create a Level Six Esper\" + \"sanctioned by Academy City government\" + \"no successful attempts so far\" + \"no Level Six Espers exist\"]","constant":false,"selective":false,"order":3}}} \ No newline at end of file diff --git a/server.js b/server.js index 180a799e8..7ceadf852 100644 --- a/server.js +++ b/server.js @@ -71,6 +71,7 @@ const multer = require("multer"); const http = require("http"); const https = require('https'); const basicAuthMiddleware = require('./src/middleware/basicAuthMiddleware'); +const contentManager = require('./src/content-manager'); const extract = require('png-chunks-extract'); const encode = require('png-chunks-encode'); const PNGtext = require('png-chunk-text'); @@ -3446,6 +3447,7 @@ const setupTasks = async function () { migrateSecrets(); ensurePublicDirectoriesExist(); await ensureThumbnailCache(); + contentManager.checkForNewContent(); // Colab users could run the embedded tool if (!is_colab) await convertWebp(); diff --git a/src/content-manager.js b/src/content-manager.js new file mode 100644 index 000000000..a8976be6b --- /dev/null +++ b/src/content-manager.js @@ -0,0 +1,84 @@ +const fs = require('fs'); +const path= require('path'); +const config = require(path.join(process.cwd(), './config.conf')); +const contentDirectory = path.join(process.cwd(), 'default/content'); +const contentLogPath = path.join(contentDirectory, 'content.log'); +const contentIndexPath = path.join(contentDirectory, 'index.json'); + +function checkForNewContent() { + try { + if (config.skipContentCheck) { + return; + } + + const contentLog = getContentLog(); + const contentIndexText = fs.readFileSync(contentIndexPath, 'utf8'); + const contentIndex = JSON.parse(contentIndexText); + + for (const contentItem of contentIndex) { + // If the content item is already in the log, skip it + if (contentLog.includes(contentItem.filename)) { + continue; + } + + contentLog.push(contentItem.filename); + const contentPath = path.join(contentDirectory, contentItem.filename); + + if (!fs.existsSync(contentPath)) { + console.log(`Content file ${contentItem.filename} is missing`); + continue; + } + + const contentTarget = getTargetByType(contentItem.type); + + if (!contentTarget) { + console.log(`Content file ${contentItem.filename} has unknown type ${contentItem.type}`); + continue; + } + + const targetPath = path.join(process.cwd(), contentTarget, contentItem.filename); + + if (fs.existsSync(targetPath)) { + console.log(`Content file ${contentItem.filename} already exists in ${contentTarget}`); + continue; + } + + fs.cpSync(contentPath, targetPath, { recursive: true, force: false }); + console.log(`Content file ${contentItem.filename} copied to ${contentTarget}`); + } + + fs.writeFileSync(contentLogPath, contentLog.join('\n')); + } catch (err) { + console.log('Content check failed', err); + } +} + +function getTargetByType(type) { + switch (type) { + case 'character': + return 'public/characters'; + case 'sprites': + return 'public/characters'; + case 'background': + return 'public/backgrounds'; + case 'world': + return 'public/worlds'; + case 'sound': + return 'public/sounds'; + default: + return null; + } +} + +function getContentLog() { + if (!fs.existsSync(contentLogPath)) { + return []; + } + + const contentLogText = fs.readFileSync(contentLogPath, 'utf8'); + return contentLogText.split('\n'); +} + +module.exports = { + checkForNewContent, +}