Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ We welcome contributions! Please read our [Contributing Guidelines](CONTRIBUTING

For any inquiries, feel free to reach out through one of the following channels:

- **Email**: [inknest@mail.p2devs.engineer](mailto:inknest@mail.p2devs.engineer)
- **Email**: [inknest@capacity.rocks](mailto:inknest@capacity.rocks)
- **Discord**: Join our community on [Discord](https://discord.gg/WYwJefvWNT) for real-time support and discussion.
- **GitHub Discussions**: Visit our [GitHub Discussions board](https://github.com/p2devs/InkNest/discussions) to engage with our community, ask questions, and find answers to common issues.

Expand Down
62 changes: 62 additions & 0 deletions __tests__/novelChapterParser.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const cheerio = require('cheerio');

const {
parseWTRLabChapter,
} = require('../src/Redux/Actions/parsers/novelChapterParser');

describe('parseWTRLabChapter', () => {
let logSpy;

beforeEach(() => {
logSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
});

afterEach(() => {
logSpy.mockRestore();
});

it('parses array-based reader payloads into readable paragraphs', () => {
const $ = cheerio.load('<html><body></body></html>');

const result = parseWTRLabChapter(
$,
{},
{
data: {
data: {
body: ['First paragraph', 'Second paragraph'],
},
},
},
{title: 'Chapter 1'},
);

expect(result.title).toBe('Chapter 1');
expect(result.paragraphs).toEqual([
'First paragraph',
'Second paragraph',
]);
expect(result.text).toBe('First paragraph\n\nSecond paragraph');
});

it('supports object entries inside array-based reader payloads', () => {
const $ = cheerio.load('<html><body></body></html>');

const result = parseWTRLabChapter(
$,
{},
{
data: {
data: {
body: [{text: 'Alpha'}, {content: 'Beta'}],
},
},
},
{title: 'Chapter 2'},
);

expect(result.title).toBe('Chapter 2');
expect(result.paragraphs).toEqual(['Alpha', 'Beta']);
expect(result.text).toBe('Alpha\n\nBeta');
});
});
34 changes: 34 additions & 0 deletions docs/blog/2026-03-28-release-v1.4.9.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
slug: release-v1.4.9
title: InkNest v1.4.9 Release
authors: [p2devs]
tags: [release]
---

# 📢 InkNest v1.4.9 Release Announcement

Hey everyone! 🎉 We're thrilled to announce **InkNest v1.4.9** is officially here!

This is a massive update introducing a highly anticipated new feature: the **Novel Reading Module**, along with multi-source tracking, offline support, and various quality-of-life improvements.

<!-- truncate -->

## ✨ What's New

#### 📚 All-New Novel Reading Module
- **Novel Reading Experience** — Dive into your favorite novels with a dedicated, brand-new reading module.
- **Offline Reading Foundation** — We've laid the groundwork for offline support. *(Note: Full offline downloading for novels is currently in development and not yet available for users).*
- **Multi-Source Integration** — Access content from multiple sources effortlessly. *(Note: WTR-Lab integration is included, but the source is currently disabled due to Cloudflare protection).*

#### 🔔 Source Status Tracking & Notifications
- **Source Status Tracking** — Stay updated on the status of your favorite content sources and get notifications when there are changes or issues.

## 🐛 Bug Fixes & Improvements
- **Search UI Refinements** — Updated the background color and centered the header title for a cleaner looking Search interface.
- **Code Optimization** — Refactored both the Search and NovelDetails components for improved performance and readability.
- **Bug Fixes** — Removed unnecessary error handling on synchronous notification persistence.
- **Contact Info** — Updated our official contact email to `inknest@capacity.rocks`.

**Update now** to explore the brand new Novel Reading Module and all the other improvements! 📚✨

As always, if you encounter any issues, please report them in our issues channel. Happy reading! 🦋
6 changes: 3 additions & 3 deletions docs/src/pages/faq.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ const faqData = [

• **GitHub Issues** - Create a detailed bug report on our [Issues page](https://github.com/p2devs/InkNest/issues)
• **Discord** - Report issues in our [Discord server](https://discord.gg/WYwJefvWNT)
• **Email** - Contact us at [inknest@mail.p2devs.engineer](mailto:inknest@mail.p2devs.engineer)
• **Email** - Contact us at [inknest@capacity.rocks](mailto:inknest@capacity.rocks)
• **TestFlight** - iOS users can send feedback directly through TestFlight

*Please include device info, app version, and steps to reproduce the issue!*`,
Expand Down Expand Up @@ -157,7 +157,7 @@ const faqData = [
q: 'How can I contact the InkNest team?',
a: `Reach out through any of these channels:

• **Email** - [inknest@mail.p2devs.engineer](mailto:inknest@mail.p2devs.engineer)
• **Email** - [inknest@capacity.rocks](mailto:inknest@capacity.rocks)
• **Discord** - Join our [Discord server](https://discord.gg/WYwJefvWNT) for real-time chat
• **GitHub Discussions** - [Ask questions](https://github.com/p2devs/InkNest/discussions) and share ideas
• **GitHub Issues** - For bug reports and feature requests
Expand Down Expand Up @@ -289,7 +289,7 @@ export default function FAQ() {
💡 GitHub Discussions
</a>
<a
href="mailto:inknest@mail.p2devs.engineer"
href="mailto:inknest@capacity.rocks"
className={styles.helpButton}>
📧 Email Us
</a>
Expand Down
4 changes: 2 additions & 2 deletions docs/src/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@ function ContactSection() {
<div className={styles.contactGrid}>
<div className={styles.contactCard}>
<h4>📧 Email</h4>
<a href="mailto:inknest@mail.p2devs.engineer">
inknest@mail.p2devs.engineer
<a href="mailto:inknest@capacity.rocks">
inknest@capacity.rocks
</a>
</div>
<div className={styles.contactCard}>
Expand Down
32 changes: 8 additions & 24 deletions ios/InkNest.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,20 @@ target 'InkNest' do
:mac_catalyst_enabled => false,
# :ccache_enabled => true
)

# Patch fmt base.h for Apple Clang 21+ (Xcode 26) consteval compatibility.
# Apple Clang 21 (__apple_build_version__ >= 21000000) has stricter consteval
# enforcement that breaks fmt 11.x. fmt only excludes < 14000029 (Clang < 14).
fmt_base_h = File.join(installer.sandbox.root, 'fmt/include/fmt/base.h')
if File.exist?(fmt_base_h)
content = File.read(fmt_base_h)
old_check = '#elif defined(__apple_build_version__) && __apple_build_version__ < 14000029L'
new_check = '#elif defined(__apple_build_version__) && (__apple_build_version__ < 14000029L || __apple_build_version__ >= 21000000L)'
if content.include?(old_check) && !content.include?(new_check)
File.chmod(0644, fmt_base_h)
File.write(fmt_base_h, content.gsub(old_check, new_check))
puts '[Fix] Patched fmt/base.h for Apple Clang 21+ consteval compatibility'
end
end
end
end
4 changes: 2 additions & 2 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4152,6 +4152,6 @@ SPEC CHECKSUMS:
UnrarKit: 62f535c7a34ec52d2514b9b148f33dcfa9a9dc39
Yoga: 1259c7a8cbaccf7b4c3ddf8ee36ca11be9dee407

PODFILE CHECKSUM: 508b472b779be51eb204147483558e3ddf0e43ea
PODFILE CHECKSUM: b45710cb91af671d189404d2388ad71bac78490a

COCOAPODS: 1.15.2
COCOAPODS: 1.16.2
14 changes: 7 additions & 7 deletions src/Components/Func/HomeFunc.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,12 @@ export const fetchComicsData = async (link, dispatch, baseUrl) => {
.replaceAll(',', '');
}
}
dispatch(checkDownTime(response));
dispatch(checkDownTime(response, baseUrl));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Downtime never clears 🐞 Bug ⛯ Reliability

Several success paths pass an Axios response object (or a non-error object) into checkDownTime,
but checkDownTime only reads error.response.status, so DownTime(false) and
recordSourceSuccess() are skipped and downtime/source-status can remain stuck after failures.
Agent Prompt
## Issue description
`checkDownTime()` is used with both Axios error objects and Axios success response objects. After the change, it only inspects `error.response.status`, so when callers pass a success `response` (with `response.status`) or other truthy placeholders, downtime/source-status is not cleared.

## Issue Context
Call sites in `HomeFunc` and `GlobalActions` dispatch `checkDownTime(response, sourceKey)` / `checkDownTime({filters}, source)` on success, but `checkDownTime` only clears downtime when the first argument is falsy.

## Fix Focus Areas
- src/Redux/Actions/utils/errorHandlers.js[38-95]
- src/Components/Func/HomeFunc.js[80-86]
- src/Components/Func/HomeFunc.js[167-179]
- src/Redux/Actions/GlobalActions.js[280-288]

## Suggested direction
Either:
- Update all success-path callers to dispatch `checkDownTime(null, sourceKey)` (and stop passing response/placeholder objects), OR
- Make `checkDownTime(result, sourceKey)` handle both shapes by deriving `statusCode` from `result.response?.status ?? result.status` and treating 2xx/3xx as success (dispatch `DownTime(false)` + `recordSourceSuccess(sourceKey)`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

return {data: comicsData, lastPage};
} catch (error) {
// console.log(link, 'link');
console.log('Error fetching or parsing data Home:', error);
if (dispatch) dispatch(checkDownTime(error));
if (dispatch) dispatch(checkDownTime(error, baseUrl));
return [];
}
};
Expand Down Expand Up @@ -155,27 +155,27 @@ export const FetchAnimeData = async (link, dispatch, baseUrl) => {
// console.log(AnimaData, 'videos');
}

dispatch(checkDownTime(response));
dispatch(checkDownTime(response, baseUrl));
return AnimaData;
} catch (error) {
console.log('Error fetching or parsing data Anime Home page: ', error);
if (dispatch) dispatch(checkDownTime(error));
if (dispatch) dispatch(checkDownTime(error, baseUrl));
return [];
}
};

export const checkServerDown = async (url, dispatch) => {
export const checkServerDown = async (url, dispatch, sourceKey = null) => {
dispatch(fetchDataStart());
try {
const response = await APICaller.get(url);
//set DownTime to false
console.log(response.status, 'response');
dispatch(checkDownTime(response));
dispatch(checkDownTime(response, sourceKey));
return false;
} catch (error) {
//set DownTime to true
console.log('Error checking server down:', error.message);
dispatch(checkDownTime(error));
dispatch(checkDownTime(error, sourceKey));
return true;
}
};
Expand Down
4 changes: 2 additions & 2 deletions src/Components/UIComp/DownTime.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ const DownTime = () => {
title="Retry"
onPress={() => {
if (animeActive) {
checkServerDown(AnimeHostName[baseUrl], dispatch)
checkServerDown(AnimeHostName[baseUrl], dispatch, baseUrl)
} else {
checkServerDown(ComicHostName[baseUrl], dispatch)
checkServerDown(ComicHostName[baseUrl], dispatch, baseUrl)
}
}}
textSize={20}
Expand Down
Loading