Skip to content

Commit a1ef0bb

Browse files
authored
Merge pull request #15 from shirokun20/feat/multi-source-migration-phase-4
Feat/multi source migration phase 4
2 parents dc97672 + 1258322 commit a1ef0bb

File tree

16 files changed

+295
-152
lines changed

16 files changed

+295
-152
lines changed

.github/workflows/build.yml

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -147,78 +147,85 @@ jobs:
147147
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
148148
TELEGRAM_CHANNEL_ID: ${{ secrets.TELEGRAM_CHANNEL_ID }}
149149
run: |
150+
set -e
150151
# Check if APK files exist
151152
if [ ! -d "apk-output" ] || [ -z "$(ls -A apk-output/*.apk 2>/dev/null)" ]; then
152153
echo "❌ No APK files found in apk-output/"
153154
exit 1
154155
fi
155156
156-
# Get version from pubspec.yaml for caption
157+
# Get version from pubspec.yaml
157158
VERSION=$(grep '^version: ' pubspec.yaml | cut -d ' ' -f 2 | cut -d '+' -f 1)
159+
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-8)
160+
161+
echo "📦 Version: $VERSION"
162+
echo "🔗 Commit: $SHORT_SHA"
158163
159-
# Priority: ARM64 > ARM > x86_64
160-
# Only upload ARM64 and ARM to save bandwidth and telegram storage
161-
# x86_64 is mainly for emulators/testing
164+
# Absolute path for reliability
165+
OUTPUT_DIR="$(pwd)/apk-output"
162166
UPLOADED_COUNT=0
163167
164168
# Upload ARM64 (highest priority - 95% of users)
165-
for apk in apk-output/*arm64-v8a*.apk; do
169+
for apk in "$OUTPUT_DIR"/*arm64-v8a*.apk; do
166170
if [ -f "$apk" ]; then
171+
filename=$(basename "$apk")
167172
size=$(stat -c%s "$apk" 2>/dev/null || stat -f%z "$apk" 2>/dev/null || echo "0")
168173
size_mb=$((size / 1024 / 1024))
169174
170175
if [ $size_mb -gt 50 ]; then
171-
echo "⚠️ Skipping $apk - too large (${size_mb}MB > 50MB limit)"
176+
echo "⚠️ Skipping $filename - too large (${size_mb}MB > 50MB limit)"
172177
continue
173178
fi
174179
175-
echo "📤 Uploading ARM64: $apk (${size_mb}MB)..."
176-
response=$(curl -s --max-time 600 --connect-timeout 60 --retry 3 --retry-delay 10 \
180+
echo "📤 Uploading ARM64: $filename (${size_mb}MB)..."
181+
182+
# Use -S to show errors but keep it quiet otherwise
183+
response=$(curl -S --max-time 600 --connect-timeout 60 --retry 3 --retry-delay 10 \
177184
-F chat_id="$TELEGRAM_CHANNEL_ID" \
178185
-F document=@"$apk" \
179-
-F caption="📱 Kuro-N v${VERSION} - ARM64 | ✅ Recommended for modern devices (Android 5.0+) | 💾 ${size_mb}MB | 🔗 ${GITHUB_SHA::8}" \
186+
-F caption="📱 Kuro-N v${VERSION} - ARM64 | ✅ Recommended for modern devices | 💾 ${size_mb}MB | 🔗 $SHORT_SHA" \
180187
"https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendDocument")
181188
182-
if echo "$response" | grep -q '"ok":true'; then
183-
echo "✅ Successfully uploaded ARM64 APK (${size_mb}MB)"
184-
UPLOADED_COUNT=$((UPLOADED_COUNT + 1))
185-
else
186-
echo "❌ Failed to upload: $response"
189+
if echo "$response" | grep -q '"ok":true'; then
190+
echo "✅ Successfully uploaded ARM64: $filename"
191+
UPLOADED_COUNT=$((UPLOADED_COUNT + 1))
192+
else
193+
echo "❌ Failed to upload $filename: $response"
187194
exit 1
188195
fi
189196
fi
190197
done
191198
192199
# Upload ARM (compatibility for older devices)
193-
for apk in apk-output/*armeabi-v7a*.apk; do
200+
for apk in "$OUTPUT_DIR"/*armeabi-v7a*.apk; do
194201
if [ -f "$apk" ]; then
202+
filename=$(basename "$apk")
195203
size=$(stat -c%s "$apk" 2>/dev/null || stat -f%z "$apk" 2>/dev/null || echo "0")
196204
size_mb=$((size / 1024 / 1024))
197205
198206
if [ $size_mb -gt 50 ]; then
199-
echo "⚠️ Skipping $apk - too large (${size_mb}MB > 50MB limit)"
207+
echo "⚠️ Skipping $filename - too large (${size_mb}MB > 50MB limit)"
200208
continue
201209
fi
202210
203-
echo "📤 Uploading ARM: $apk (${size_mb}MB)..."
204-
response=$(curl -s --max-time 600 --connect-timeout 60 --retry 3 --retry-delay 10 \
211+
echo "📤 Uploading ARM: $filename (${size_mb}MB)..."
212+
213+
response=$(curl -S --max-time 600 --connect-timeout 60 --retry 3 --retry-delay 10 \
205214
-F chat_id="$TELEGRAM_CHANNEL_ID" \
206215
-F document=@"$apk" \
207-
-F caption="📱 Kuro-N v${VERSION} - ARMv7 | 📦 For older devices | 💾 ${size_mb}MB | 🔗 ${GITHUB_SHA::8}" \
216+
-F caption="📱 Kuro-N v${VERSION} - ARMv7 | 📦 For older devices | 💾 ${size_mb}MB | 🔗 $SHORT_SHA" \
208217
"https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendDocument")
209218
210-
if echo "$response" | grep -q '"ok":true'; then
211-
echo "✅ Successfully uploaded ARM APK (${size_mb}MB)"
212-
UPLOADED_COUNT=$((UPLOADED_COUNT + 1))
213-
else
214-
echo "❌ Failed to upload: $response"
219+
if echo "$response" | grep -q '"ok":true'; then
220+
echo "✅ Successfully uploaded ARM: $filename"
221+
UPLOADED_COUNT=$((UPLOADED_COUNT + 1))
222+
else
223+
echo "❌ Failed to upload $filename: $response"
215224
exit 1
216225
fi
217226
fi
218227
done
219228
220-
# Note: x86_64 not uploaded to save space (mainly for emulators)
221-
echo ""
222229
echo "🎉 Upload complete! Total uploaded: $UPLOADED_COUNT APKs"
223230
224231
# Extract Version from pubspec.yaml

lib/core/config/api_config.dart

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,41 @@
1-
/// API Configuration
2-
///
3-
/// Centralized configuration for API endpoints and settings.
4-
library;
5-
1+
import 'package:nhasixapp/core/config/remote_config_service.dart';
2+
import 'package:nhasixapp/core/di/service_locator.dart';
3+
import 'package:nhasixapp/core/config/config_models.dart' as models;
4+
65
/// Configuration class for nhentai API
76
class ApiConfig {
87
ApiConfig._();
9-
8+
9+
static models.SourceConfig? get _nhentaiConfig =>
10+
getIt<RemoteConfigService>().getConfig('nhentai');
11+
1012
// ============ nhentai API ============
1113

1214
/// Base URL for nhentai API
13-
static const String nhentaiApiBase = 'https://nhentai.net/api';
14-
15+
static String get nhentaiApiBase => _nhentaiConfig?.api?.apiBase ?? 'https://nhentai.net/api';
16+
1517
/// nhentai website base URL (for fallback scraping)
16-
static const String nhentaiWebBase = 'https://nhentai.net';
17-
18+
static String get nhentaiWebBase => _nhentaiConfig?.baseUrl ?? 'https://nhentai.net';
19+
1820
/// API request timeout in milliseconds
19-
static const int apiTimeout = 30000;
20-
21+
static int get apiTimeout => _nhentaiConfig?.api?.timeout ?? 30000;
22+
2123
/// Enable automatic fallback to HTML scraper if API fails
22-
static const bool enableApiFallback = true;
23-
24+
static bool get enableApiFallback => _nhentaiConfig?.features?.related ?? true;
25+
2426
/// Maximum retry attempts for API requests
25-
static const int maxRetryAttempts = 3;
26-
27+
static int get maxRetryAttempts => _nhentaiConfig?.network?.retry?.maxAttempts ?? 3;
28+
2729
/// Delay between retries in milliseconds
28-
static const int retryDelayMs = 1000;
30+
static int get retryDelayMs => _nhentaiConfig?.network?.retry?.delayMs ?? 1000;
2931

3032
// ============ Rate Limiting ============
31-
33+
3234
/// Minimum delay between API requests in milliseconds
33-
static const int minRequestDelayMs = 200;
34-
35+
static int get minRequestDelayMs => _nhentaiConfig?.network?.rateLimit?.minDelayMs ?? 200;
36+
3537
/// Maximum requests per minute
36-
static const int maxRequestsPerMinute = 60;
38+
static int get maxRequestsPerMinute => _nhentaiConfig?.network?.rateLimit?.requestsPerMinute ?? 60;
3739

3840
// ============ Endpoints ============
3941

lib/core/config/config_models.dart

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -520,9 +520,18 @@ class AppConfig {
520520
@JsonSerializable()
521521
class AppLimits {
522522
final int defaultPageSize;
523+
final int maxBatchSize;
523524
final int maxConcurrentDownloads;
524-
525-
AppLimits({this.defaultPageSize = 20, this.maxConcurrentDownloads = 3});
525+
final int searchHistoryLimit;
526+
final int imagePreloadBuffer;
527+
528+
AppLimits({
529+
this.defaultPageSize = 20,
530+
this.maxBatchSize = 1000,
531+
this.maxConcurrentDownloads = 3,
532+
this.searchHistoryLimit = 50,
533+
this.imagePreloadBuffer = 5,
534+
});
526535

527536
factory AppLimits.fromJson(Map<String, dynamic> json) =>
528537
_$AppLimitsFromJson(json);
@@ -532,9 +541,26 @@ class AppLimits {
532541
@JsonSerializable()
533542
class AppDurations {
534543
final int splashDelayMs;
535-
final int snackbarDurationMs;
536-
537-
AppDurations({this.splashDelayMs = 2000, this.snackbarDurationMs = 3000});
544+
final int snackbarShortMs;
545+
final int snackbarLongMs;
546+
final int pageTransitionMs;
547+
final int searchDebounceMs;
548+
final int networkTimeoutMs;
549+
final int cacheExpirationHours;
550+
final int readerAutoHideDelaySeconds;
551+
final int progressUpdateIntervalMs;
552+
553+
AppDurations({
554+
this.splashDelayMs = 1000,
555+
this.snackbarShortMs = 2000,
556+
this.snackbarLongMs = 4000,
557+
this.pageTransitionMs = 300,
558+
this.searchDebounceMs = 300,
559+
this.networkTimeoutMs = 30000,
560+
this.cacheExpirationHours = 24,
561+
this.readerAutoHideDelaySeconds = 3,
562+
this.progressUpdateIntervalMs = 100,
563+
});
538564

539565
factory AppDurations.fromJson(Map<String, dynamic> json) =>
540566
_$AppDurationsFromJson(json);
@@ -544,9 +570,22 @@ class AppDurations {
544570
@JsonSerializable()
545571
class AppUiConfig {
546572
final int gridColumnsPortrait;
573+
final int gridColumnsLandscape;
574+
final double minCardWidth;
547575
final double cardAspectRatio;
548-
549-
AppUiConfig({this.gridColumnsPortrait = 2, this.cardAspectRatio = 0.7});
576+
final double cardBorderRadius;
577+
final double defaultPadding;
578+
final int titleMaxLength;
579+
580+
AppUiConfig({
581+
this.gridColumnsPortrait = 2,
582+
this.gridColumnsLandscape = 3,
583+
this.minCardWidth = 150.0,
584+
this.cardAspectRatio = 0.65,
585+
this.cardBorderRadius = 12.0,
586+
this.defaultPadding = 16.0,
587+
this.titleMaxLength = 40,
588+
});
550589

551590
factory AppUiConfig.fromJson(Map<String, dynamic> json) =>
552591
_$AppUiConfigFromJson(json);
@@ -556,8 +595,14 @@ class AppUiConfig {
556595
@JsonSerializable()
557596
class AppStorage {
558597
final String backupFolderName;
598+
final int maxImageSizeKb;
599+
final int pdfPartsSizePages;
559600

560-
AppStorage({this.backupFolderName = 'nhasix_backup'});
601+
AppStorage({
602+
this.backupFolderName = 'nhasix',
603+
this.maxImageSizeKb = 200,
604+
this.pdfPartsSizePages = 100,
605+
});
561606

562607
factory AppStorage.fromJson(Map<String, dynamic> json) =>
563608
_$AppStorageFromJson(json);

lib/core/config/config_models.g.dart

Lines changed: 43 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/core/config/remote_config_service.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:dio/dio.dart';
44
import 'package:flutter/services.dart';
55
import 'package:logger/logger.dart';
66
import 'package:nhasixapp/core/config/config_models.dart';
7+
import 'package:nhasixapp/core/constants/app_constants.dart' as constants;
78
import 'package:shared_preferences/shared_preferences.dart';
89
import 'package:flutter/foundation.dart'; // Add this import
910

@@ -127,7 +128,7 @@ class RemoteConfigService {
127128
_versionUrl,
128129
options: Options(
129130
responseType: ResponseType.json,
130-
receiveTimeout: const Duration(seconds: 10),
131+
receiveTimeout: constants.AppDurations.networkTimeout,
131132
),
132133
);
133134

0 commit comments

Comments
 (0)