mirror of
https://github.com/wgh136/pixes.git
synced 2025-09-27 04:57:23 +00:00
novel
This commit is contained in:
@@ -121,14 +121,14 @@ class UserDetails {
|
||||
pawooUrl = json['profile']['pawoo_url'];
|
||||
}
|
||||
|
||||
class IllustAuthor {
|
||||
class Author {
|
||||
final int id;
|
||||
final String name;
|
||||
final String account;
|
||||
final String avatar;
|
||||
bool isFollowed;
|
||||
|
||||
IllustAuthor(this.id, this.name, this.account, this.avatar, this.isFollowed);
|
||||
Author(this.id, this.name, this.account, this.avatar, this.isFollowed);
|
||||
}
|
||||
|
||||
class Tag {
|
||||
@@ -170,7 +170,7 @@ class Illust {
|
||||
final List<IllustImage> images;
|
||||
final String caption;
|
||||
final int restrict;
|
||||
final IllustAuthor author;
|
||||
final Author author;
|
||||
final List<Tag> tags;
|
||||
final DateTime createDate;
|
||||
final int pageCount;
|
||||
@@ -210,7 +210,7 @@ class Illust {
|
||||
}()),
|
||||
caption = json['caption'],
|
||||
restrict = json['restrict'],
|
||||
author = IllustAuthor(
|
||||
author = Author(
|
||||
json['user']['id'],
|
||||
json['user']['name'],
|
||||
json['user']['account'],
|
||||
@@ -380,7 +380,8 @@ class UserPreview {
|
||||
avatar = json['user']['profile_image_urls']['medium'],
|
||||
isFollowed = json['user']['is_followed'],
|
||||
isBlocking = json['user']['is_access_blocking_user'] ?? false,
|
||||
artworks = (json['illusts'] as List).map((e) => Illust.fromJson(e)).toList();
|
||||
artworks =
|
||||
(json['illusts'] as List).map((e) => Illust.fromJson(e)).toList();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -420,6 +421,107 @@ class Comment {
|
||||
uid = json['user']['id'].toString(),
|
||||
name = json['user']['name'],
|
||||
avatar = json['user']['profile_image_urls']['medium'],
|
||||
hasReplies = json['has_replies'],
|
||||
hasReplies = json['has_replies'] ?? false,
|
||||
stampUrl = json['stamp']?['stamp_url'];
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
"id": 20741342,
|
||||
"title": "中身が一般人のやつがれくん",
|
||||
"caption": "なんか思いついたので書いてみた。<br />よくある芥川成り代わり。<br />3年くらい前の書きかけのやつをサルベージ。<br />じっくりは書いてないので抜け抜け。<br /><br />デイリー1位ありがとうございます✨<br /><br />※※※※※※※※<br />※※※※※※※※<br /><br />以下読了後推奨の蛇足<br /><br />「芥川くん」<br />「なんですかボス」<br />「君は将来的にどんな地位につきたいとかある?」<br />「僕はしがない一構成員ゆえ」<br />「ほら幹部とか隊長とか人事部とかさ。君あれこれオールマイティにできるから希望を聞いておこうと思って」<br />「ございます」<br />「なにかな?」<br />「僕は将来的にポートマフィア直営のいちじく農家になりたいと思います」<br />「なんて?」<br />「さらに、ゆくゆくはいちじく農家兼、いちじくの素晴らしさを世に知らしめるポートマフィア直営いちじくレストランを開きたいと」<br />「なんて???」",
|
||||
"restrict": 0,
|
||||
"x_restrict": 0,
|
||||
"is_original": false,
|
||||
"image_urls": {
|
||||
"square_medium": "https://i.pximg.net/c/128x128/novel-cover-master/img/2023/09/27/16/14/45/ci20741342_db401e9b27afbf96f772d30759e1d104_square1200.jpg",
|
||||
"medium": "https://i.pximg.net/c/176x352/novel-cover-master/img/2023/09/27/16/14/45/ci20741342_db401e9b27afbf96f772d30759e1d104_master1200.jpg",
|
||||
"large": "https://i.pximg.net/c/240x480_80/novel-cover-master/img/2023/09/27/16/14/45/ci20741342_db401e9b27afbf96f772d30759e1d104_master1200.jpg"
|
||||
},
|
||||
"create_date": "2023-09-27T16:14:45+09:00",
|
||||
"tags": [
|
||||
{
|
||||
"name": "文スト夢",
|
||||
"translated_name": "Bungo Stray Dogs original/self-insert",
|
||||
"added_by_uploaded_user": true
|
||||
},
|
||||
{
|
||||
"name": "成り代わり",
|
||||
"translated_name": "取代即有角色",
|
||||
"added_by_uploaded_user": true
|
||||
},
|
||||
],
|
||||
"page_count": 6,
|
||||
"text_length": 12550,
|
||||
"user": {
|
||||
"id": 9275134,
|
||||
"name": "もろろ",
|
||||
"account": "sleepinglife",
|
||||
"profile_image_urls": {
|
||||
"medium": "https://s.pximg.net/common/images/no_profile.png"
|
||||
},
|
||||
"is_followed": false
|
||||
},
|
||||
"series": {
|
||||
"id": 11897059,
|
||||
"title": "文スト夢"
|
||||
},
|
||||
"is_bookmarked": false,
|
||||
"total_bookmarks": 8099,
|
||||
"total_view": 76112,
|
||||
"visible": true,
|
||||
"total_comments": 146,
|
||||
"is_muted": false,
|
||||
"is_mypixiv_only": false,
|
||||
"is_x_restricted": false,
|
||||
"novel_ai_type": 1
|
||||
}
|
||||
*/
|
||||
class Novel {
|
||||
final int id;
|
||||
final String title;
|
||||
final String caption;
|
||||
final bool isOriginal;
|
||||
final String image;
|
||||
final DateTime createDate;
|
||||
final List<Tag> tags;
|
||||
final int pages;
|
||||
final int length;
|
||||
final Author author;
|
||||
final int? seriesId;
|
||||
final String? seriesTitle;
|
||||
bool isBookmarked;
|
||||
final int totalBookmarks;
|
||||
final int totalViews;
|
||||
final int commentsCount;
|
||||
final bool isAi;
|
||||
|
||||
Novel.fromJson(Map<String, dynamic> json)
|
||||
: id = json["id"],
|
||||
title = json["title"],
|
||||
caption = json["caption"],
|
||||
isOriginal = json["is_original"],
|
||||
image = json["image_urls"]["large"] ??
|
||||
json["image_urls"]["medium"] ??
|
||||
json["image_urls"]["square_medium"] ??
|
||||
"",
|
||||
createDate = DateTime.parse(json["create_date"]),
|
||||
tags = (json['tags'] as List)
|
||||
.map((e) => Tag(e['name'], e['translated_name']))
|
||||
.toList(),
|
||||
pages = json["page_count"],
|
||||
length = json["text_length"],
|
||||
author = Author(
|
||||
json['user']['id'],
|
||||
json['user']['name'],
|
||||
json['user']['account'],
|
||||
json['user']['profile_image_urls']['medium'],
|
||||
json['user']['is_followed'] ?? false),
|
||||
seriesId = json["series"]?["id"],
|
||||
seriesTitle = json["series"]?["title"],
|
||||
isBookmarked = json["is_bookmarked"],
|
||||
totalBookmarks = json["total_bookmarks"],
|
||||
totalViews = json["total_view"],
|
||||
commentsCount = json["total_comments"],
|
||||
isAi = json["novel_ai_type"] == 2;
|
||||
}
|
||||
|
@@ -14,6 +14,8 @@ import 'models.dart';
|
||||
export 'models.dart';
|
||||
export 'res.dart';
|
||||
|
||||
part 'novel.dart';
|
||||
|
||||
class Network {
|
||||
static const hashSalt =
|
||||
"28c1fdd170a5204386cb1313c7077b34f83e4aaf4aa829ce78c231e05b0bae2c";
|
||||
@@ -159,6 +161,38 @@ class Network {
|
||||
}
|
||||
}
|
||||
|
||||
Future<Res<String>> apiGetPlain(String path,
|
||||
{Map<String, dynamic>? query}) async {
|
||||
try {
|
||||
if (!path.startsWith("http")) {
|
||||
path = "$baseUrl$path";
|
||||
}
|
||||
final res = await dio.get<String>(path,
|
||||
queryParameters: query,
|
||||
options:
|
||||
Options(headers: headers, validateStatus: (status) => true));
|
||||
if (res.statusCode == 200) {
|
||||
return Res(res.data!);
|
||||
} else if (res.statusCode == 400) {
|
||||
if (res.data.toString().contains("Access Token")) {
|
||||
var refresh = await refreshToken();
|
||||
if (refresh.success) {
|
||||
return apiGetPlain(path, query: query);
|
||||
} else {
|
||||
return Res.error(refresh.errorMessage);
|
||||
}
|
||||
} else {
|
||||
return Res.error("Invalid Status Code: ${res.statusCode}");
|
||||
}
|
||||
} else {
|
||||
return Res.error("Invalid Status Code: ${res.statusCode}");
|
||||
}
|
||||
} catch (e, s) {
|
||||
Log.error("Network", "$e\n$s");
|
||||
return Res.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Res<Map<String, dynamic>>> apiPost(String path,
|
||||
{Map<String, dynamic>? query, Map<String, dynamic>? data}) async {
|
||||
try {
|
||||
|
152
lib/network/novel.dart
Normal file
152
lib/network/novel.dart
Normal file
@@ -0,0 +1,152 @@
|
||||
part of "network.dart";
|
||||
|
||||
extension NovelExt on Network {
|
||||
Future<Res<List<Novel>>> getRecommendNovels() {
|
||||
return getNovelsWithNextUrl("/v1/novel/recommended");
|
||||
}
|
||||
|
||||
Future<Res<List<Novel>>> getNovelsWithNextUrl(String nextUrl) async {
|
||||
var res = await apiGet(nextUrl);
|
||||
if (res.error) {
|
||||
return Res.fromErrorRes(res);
|
||||
}
|
||||
return Res(
|
||||
(res.data["novels"] as List).map((e) => Novel.fromJson(e)).toList(),
|
||||
subData: res.data["next_url"]);
|
||||
}
|
||||
|
||||
Future<Res<List<Novel>>> searchNovels(String keyword, SearchOptions options) {
|
||||
var url = "/v1/search/novel?"
|
||||
"include_translated_tag_results=true&"
|
||||
"merge_plain_keyword_results=true&"
|
||||
"word=${Uri.encodeComponent(keyword)}&"
|
||||
"sort=${options.sort.toParam()}&"
|
||||
"search_target=${options.matchType.toParam()}&"
|
||||
"search_ai_type=0";
|
||||
return getNovelsWithNextUrl(url);
|
||||
}
|
||||
|
||||
/// mode: day, day_male, day_female, week_rookie, week, week_ai
|
||||
Future<Res<List<Novel>>> getNovelRanking(String mode, DateTime? date) {
|
||||
var url = "/v1/novel/ranking?mode=$mode";
|
||||
if (date != null) {
|
||||
url += "&date=${date.year}-${date.month}-${date.day}";
|
||||
}
|
||||
return getNovelsWithNextUrl(url);
|
||||
}
|
||||
|
||||
Future<Res<List<Novel>>> getBookmarkedNovels(String uid) {
|
||||
return getNovelsWithNextUrl(
|
||||
"/v1/user/bookmarks/novel?user_id=$uid&restrict=public");
|
||||
}
|
||||
|
||||
Future<Res<bool>> favoriteNovel(String id) async {
|
||||
var res = await apiPost("/v2/novel/bookmark/add", data: {
|
||||
"novel_id": id,
|
||||
"restrict": "public",
|
||||
});
|
||||
if (res.error) {
|
||||
return Res.fromErrorRes(res);
|
||||
}
|
||||
return const Res(true);
|
||||
}
|
||||
|
||||
Future<Res<bool>> deleteFavoriteNovel(String id) async {
|
||||
var res = await apiPost("/v1/novel/bookmark/delete", data: {
|
||||
"novel_id": id,
|
||||
});
|
||||
if (res.error) {
|
||||
return Res.fromErrorRes(res);
|
||||
}
|
||||
return const Res(true);
|
||||
}
|
||||
|
||||
Future<Res<String>> getNovelContent(String id) async {
|
||||
var res = await apiGetPlain(
|
||||
"/webview/v2/novel?id=$id&font=default&font_size=16.0px&line_height=1.75&color=%23101010&background_color=%23EFEFEF&margin_top=56px&margin_bottom=48px&theme=light&use_block=true&viewer_version=20221031_ai");
|
||||
if (res.error) {
|
||||
return Res.fromErrorRes(res);
|
||||
}
|
||||
try {
|
||||
var html = res.data;
|
||||
int start = html.indexOf("novel:");
|
||||
while (html[start] != '{') {
|
||||
start++;
|
||||
}
|
||||
int leftCount = 0;
|
||||
int end = start;
|
||||
for (end = start; end < html.length; end++) {
|
||||
if (html[end] == '{') {
|
||||
leftCount++;
|
||||
} else if (html[end] == '}') {
|
||||
leftCount--;
|
||||
}
|
||||
if (leftCount == 0) {
|
||||
end++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
var json = jsonDecode(html.substring(start, end));
|
||||
return Res(json['text']);
|
||||
} catch (e, s) {
|
||||
Log.error(
|
||||
"Data Convert", "Failed to analyze html novel content: \n$e\n$s");
|
||||
return Res.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Res<List<Novel>>> relatedNovels(String id) async {
|
||||
var res = await apiPost("/v1/novel/related", data: {
|
||||
"novel_id": id,
|
||||
});
|
||||
if (res.error) {
|
||||
return Res.fromErrorRes(res);
|
||||
}
|
||||
return Res(
|
||||
(res.data["novels"] as List).map((e) => Novel.fromJson(e)).toList());
|
||||
}
|
||||
|
||||
Future<Res<List<Novel>>> getUserNovels(String uid) {
|
||||
return getNovelsWithNextUrl("/v1/user/novels?user_id=$uid");
|
||||
}
|
||||
|
||||
Future<Res<List<Novel>>> getNovelSeries(String id, [String? nextUrl]) async {
|
||||
var res = await apiGet(nextUrl ?? "/v2/novel/series?series_id=$id");
|
||||
if (res.error) {
|
||||
return Res.fromErrorRes(res);
|
||||
}
|
||||
return Res(
|
||||
(res.data["novels"] as List).map((e) => Novel.fromJson(e)).toList(),
|
||||
subData: res.data["next_url"]);
|
||||
}
|
||||
|
||||
Future<Res<List<Comment>>> getNovelComments(String id,
|
||||
[String? nextUrl]) async {
|
||||
var res = await apiGet(nextUrl ?? "/v1/novel/comments?novel_id=$id");
|
||||
if (res.error) {
|
||||
return Res.fromErrorRes(res);
|
||||
}
|
||||
return Res(
|
||||
(res.data["comments"] as List).map((e) => Comment.fromJson(e)).toList(),
|
||||
subData: res.data["next_url"]);
|
||||
}
|
||||
|
||||
Future<Res<bool>> commentNovel(String id, String content) async {
|
||||
var res = await apiPost("/v1/novel/comment/add", data: {
|
||||
"novel_id": id,
|
||||
"content": content,
|
||||
});
|
||||
if (res.error) {
|
||||
return Res.fromErrorRes(res);
|
||||
}
|
||||
return const Res(true);
|
||||
}
|
||||
|
||||
Future<Res<Novel>> getNovelDetail(String id) async {
|
||||
var res = await apiGet("/v2/novel/detail?novel_id=$id");
|
||||
if (res.error) {
|
||||
return Res.fromErrorRes(res);
|
||||
}
|
||||
return Res(Novel.fromJson(res.data["novel"]));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user