mirror of
https://github.com/kodjodevf/mangayomi-extensions.git
synced 2026-02-15 19:30:29 +00:00
Reorganize folders
This commit is contained in:
BIN
dart/manga/src/en/mangahere/icon.png
Normal file
BIN
dart/manga/src/en/mangahere/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.7 KiB |
341
dart/manga/src/en/mangahere/mangahere.dart
Normal file
341
dart/manga/src/en/mangahere/mangahere.dart
Normal file
@@ -0,0 +1,341 @@
|
||||
import 'package:mangayomi/bridge_lib.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class MangaHere extends MProvider {
|
||||
MangaHere({required this.source});
|
||||
|
||||
MSource source;
|
||||
|
||||
final Client client = Client(source);
|
||||
|
||||
@override
|
||||
Future<MPages> getPopular(int page) async {
|
||||
final res = (await client.get(
|
||||
Uri.parse("${source.baseUrl}/directory/$page.htm"),
|
||||
headers: getHeader(source.baseUrl)))
|
||||
.body;
|
||||
|
||||
List<MManga> mangaList = [];
|
||||
final names =
|
||||
xpath(res, '//*[ contains(@class, "manga-list-1-list")]/li/a/@title');
|
||||
final images = xpath(res,
|
||||
'//*[ contains(@class, "manga-list-1-list")]/li/a/img[@class="manga-list-1-cover"]/@src');
|
||||
final urls =
|
||||
xpath(res, '//*[ contains(@class, "manga-list-1-list")]/li/a/@href');
|
||||
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
MManga manga = MManga();
|
||||
manga.name = names[i];
|
||||
manga.imageUrl = images[i];
|
||||
manga.link = urls[i];
|
||||
mangaList.add(manga);
|
||||
}
|
||||
|
||||
return MPages(mangaList, true);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MPages> getLatestUpdates(int page) async {
|
||||
final res = (await client.get(
|
||||
Uri.parse("${source.baseUrl}/directory/$page.htm?latest"),
|
||||
headers: getHeader(source.baseUrl)))
|
||||
.body;
|
||||
|
||||
List<MManga> mangaList = [];
|
||||
final names =
|
||||
xpath(res, '//*[ contains(@class, "manga-list-1-list")]/li/a/@title');
|
||||
final images = xpath(res,
|
||||
'//*[ contains(@class, "manga-list-1-list")]/li/a/img[@class="manga-list-1-cover"]/@src');
|
||||
final urls =
|
||||
xpath(res, '//*[ contains(@class, "manga-list-1-list")]/li/a/@href');
|
||||
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
MManga manga = MManga();
|
||||
manga.name = names[i];
|
||||
manga.imageUrl = images[i];
|
||||
manga.link = urls[i];
|
||||
mangaList.add(manga);
|
||||
}
|
||||
|
||||
return MPages(mangaList, true);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MPages> search(String query, int page, FilterList filterList) async {
|
||||
final filters = filterList.filters;
|
||||
String url = "${source.baseUrl}/search";
|
||||
|
||||
for (var filter in filters) {
|
||||
if (filter.type == "TypeList") {
|
||||
final type = filter.values[filter.state].value;
|
||||
url += "${ll(url)}type=$type";
|
||||
} else if (filter.type == "CompletionList") {
|
||||
final cmp = filter.values[filter.state].value;
|
||||
url += "${ll(url)}st=$cmp";
|
||||
} else if (filter.type == "RatingList") {
|
||||
url += "${ll(url)}rating_method=gt";
|
||||
final rt = filter.values[filter.state].value;
|
||||
url += "${ll(url)}rating=$rt";
|
||||
} else if (filter.type == "GenreList") {
|
||||
final included = (filter.state as List)
|
||||
.where((e) => e.state == 1 ? true : false)
|
||||
.toList();
|
||||
final excluded = (filter.state as List)
|
||||
.where((e) => e.state == 2 ? true : false)
|
||||
.toList();
|
||||
if (included.isNotEmpty) {
|
||||
url += "${ll(url)}genres=";
|
||||
for (var val in included) {
|
||||
url += "${val.value},";
|
||||
}
|
||||
}
|
||||
if (excluded.isNotEmpty) {
|
||||
url += "${ll(url)}nogenres=";
|
||||
for (var val in excluded) {
|
||||
url += "${val.value},";
|
||||
}
|
||||
}
|
||||
} else if (filter.type == "ArtistFilter") {
|
||||
url += "${ll(url)}artist_method=cw";
|
||||
url += "${ll(url)}artist=${Uri.encodeComponent(filter.state)}";
|
||||
} else if (filter.type == "AuthorFilter") {
|
||||
url += "${ll(url)}author_method=cw";
|
||||
url += "${ll(url)}author=${Uri.encodeComponent(filter.state)}";
|
||||
} else if (filter.type == "YearFilter") {
|
||||
url += "${ll(url)}released_method=cw";
|
||||
url += "${ll(url)}released=${Uri.encodeComponent(filter.state)}";
|
||||
}
|
||||
}
|
||||
url += "${ll(url)}title=$query&page=$page";
|
||||
final res =
|
||||
(await client.get(Uri.parse(url), headers: getHeader(source.baseUrl)))
|
||||
.body;
|
||||
|
||||
List<MManga> mangaList = [];
|
||||
final names =
|
||||
xpath(res, '//*[contains(@class, "manga-list-4-list")]/li/a/@title');
|
||||
final images = xpath(res,
|
||||
'//*[contains(@class, "manga-list-4-list")]/li/a/img[@class="manga-list-4-cover"]/@src');
|
||||
final urls =
|
||||
xpath(res, '//*[contains(@class, "manga-list-4-list")]/li/a/@href');
|
||||
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
MManga manga = MManga();
|
||||
manga.name = names[i];
|
||||
manga.imageUrl = images[i];
|
||||
manga.link = urls[i];
|
||||
mangaList.add(manga);
|
||||
}
|
||||
|
||||
return MPages(mangaList, true);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MManga> getDetail(String url) async {
|
||||
final statusList = [
|
||||
{"Ongoing": 0, "Completed": 1}
|
||||
];
|
||||
final res = (await client.get(Uri.parse("${source.baseUrl}/$url"),
|
||||
headers: getHeader(source.baseUrl)))
|
||||
.body;
|
||||
MManga manga = MManga();
|
||||
manga.author =
|
||||
xpath(res, '//*[@class="detail-info-right-say"]/a/text()').first;
|
||||
manga.description = xpath(res, '//*[@class="fullcontent"]/text()').first;
|
||||
final status =
|
||||
xpath(res, '//*[@class="detail-info-right-title-tip"]/text()').first;
|
||||
manga.status = parseStatus(status, statusList);
|
||||
manga.genre =
|
||||
xpath(res, '//*[@class="detail-info-right-tag-list"]/a/text()');
|
||||
|
||||
var chapUrls = xpath(res, '//*[@class="detail-main-list"]/li/a/@href');
|
||||
var chaptersNames = xpath(res,
|
||||
'//*[@class="detail-main-list"]/li/a/div/p[@class="title3"]/text()');
|
||||
final chapterDates = xpath(res,
|
||||
'//*[@class="detail-main-list"]/li/a/div/p[@class="title2"]/text()');
|
||||
var dateUploads =
|
||||
parseDates(chapterDates, source.dateFormat, source.dateFormatLocale);
|
||||
|
||||
List<MChapter>? chaptersList = [];
|
||||
for (var i = 0; i < chaptersNames.length; i++) {
|
||||
MChapter chapter = MChapter();
|
||||
chapter.name = chaptersNames[i];
|
||||
chapter.url = chapUrls[i];
|
||||
chapter.dateUpload = dateUploads[i];
|
||||
chaptersList.add(chapter);
|
||||
}
|
||||
manga.chapters = chaptersList;
|
||||
return manga;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getPageList(String url) async {
|
||||
final headers = getHeader(source.baseUrl);
|
||||
final urll = "${source.baseUrl}$url";
|
||||
final res = (await client.get(Uri.parse(urll), headers: headers)).body;
|
||||
final pages = xpath(res, "//body/div/div/span/a/text()");
|
||||
List<String> pageUrls = [];
|
||||
if (pages.isEmpty) {
|
||||
final script = xpath(
|
||||
res, "//script[contains(text(),'function(p,a,c,k,e,d)')]/text()")
|
||||
.first
|
||||
.replaceAll("eval", "");
|
||||
String deobfuscatedScript = unpackJs(script);
|
||||
int a = deobfuscatedScript.indexOf("newImgs=['") + 10;
|
||||
int b = deobfuscatedScript.indexOf("'];");
|
||||
List<String> urls = deobfuscatedScript.substring(a, b).split("','");
|
||||
for (var url in urls) {
|
||||
pageUrls.add("https:$url");
|
||||
}
|
||||
} else {
|
||||
final pagesNumberList = pages;
|
||||
int pagesNumber = int.parse(pagesNumberList[pagesNumberList.length - 2]);
|
||||
int secretKeyScriptLocation = res.indexOf("eval(function(p,a,c,k,e,d)");
|
||||
int secretKeyScriptEndLocation =
|
||||
res.indexOf("</script>", secretKeyScriptLocation);
|
||||
String secretKeyScript = res
|
||||
.substring(secretKeyScriptLocation, secretKeyScriptEndLocation)
|
||||
.replaceAll("eval", "");
|
||||
String secretKeyDeobfuscatedScript = unpackJs(secretKeyScript);
|
||||
int secretKeyStartLoc = secretKeyDeobfuscatedScript.indexOf("'");
|
||||
int secretKeyEndLoc = secretKeyDeobfuscatedScript.indexOf(";");
|
||||
|
||||
String secretKey = secretKeyDeobfuscatedScript.substring(
|
||||
secretKeyStartLoc, secretKeyEndLoc);
|
||||
int chapterIdStartLoc = res.indexOf("chapterid");
|
||||
String chapterId = res.substring(
|
||||
chapterIdStartLoc + 11, res.indexOf(";", chapterIdStartLoc));
|
||||
String pageBase = urll.substring(0, urll.lastIndexOf("/"));
|
||||
for (int i = 1; i <= pagesNumber; i++) {
|
||||
String pageLink =
|
||||
"$pageBase/chapterfun.ashx?cid=$chapterId&page=$i&key=$secretKey";
|
||||
String responseText = "".toString();
|
||||
for (int tr = 1; tr <= 3; tr++) {
|
||||
if (responseText.isEmpty) {
|
||||
final headers = {
|
||||
"Referer": urll,
|
||||
"Accept": "*/*",
|
||||
"Accept-Language": "en-US,en;q=0.9",
|
||||
"Connection": "keep-alive",
|
||||
"Host": "www.mangahere.cc",
|
||||
"X-Requested-With": "XMLHttpRequest"
|
||||
};
|
||||
|
||||
final ress =
|
||||
(await client.get(Uri.parse(pageLink), headers: headers)).body;
|
||||
|
||||
responseText = ress;
|
||||
|
||||
if (responseText.isEmpty) {
|
||||
secretKey = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
String deobfuscatedScript =
|
||||
unpackJs(responseText.replaceAll("eval", ""));
|
||||
|
||||
int baseLinkStartPos = deobfuscatedScript.indexOf("pix=") + 5;
|
||||
int baseLinkEndPos =
|
||||
deobfuscatedScript.indexOf(";", baseLinkStartPos) - 1;
|
||||
String baseLink =
|
||||
deobfuscatedScript.substring(baseLinkStartPos, baseLinkEndPos);
|
||||
|
||||
int imageLinkStartPos = deobfuscatedScript.indexOf("pvalue=") + 9;
|
||||
int imageLinkEndPos =
|
||||
deobfuscatedScript.indexOf("\"", imageLinkStartPos);
|
||||
String imageLink =
|
||||
deobfuscatedScript.substring(imageLinkStartPos, imageLinkEndPos);
|
||||
pageUrls.add("https:$baseLink$imageLink");
|
||||
}
|
||||
}
|
||||
|
||||
return pageUrls;
|
||||
}
|
||||
|
||||
String ll(String url) {
|
||||
if (url.contains("?")) {
|
||||
return "&";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
@override
|
||||
List<dynamic> getFilterList() {
|
||||
return [
|
||||
SelectFilter("TypeList", "Type", 1, [
|
||||
SelectFilterOption("American Manga", "5"),
|
||||
SelectFilterOption("Any", "0"),
|
||||
SelectFilterOption("Chinese Manhua", "3"),
|
||||
SelectFilterOption("European Manga", "4"),
|
||||
SelectFilterOption("Hong Kong Manga", "6"),
|
||||
SelectFilterOption("Japanese Manga", "1"),
|
||||
SelectFilterOption("Korean Manhwa", "2"),
|
||||
SelectFilterOption("Other Manga", "7"),
|
||||
]),
|
||||
TextFilter("ArtistFilter", "Artist"),
|
||||
TextFilter("AuthorFilter", "Author"),
|
||||
GroupFilter("GenreList", "Genres", [
|
||||
TriStateFilter("Action", "1"),
|
||||
TriStateFilter("Adventure", "2"),
|
||||
TriStateFilter("Comedy", "3"),
|
||||
TriStateFilter("Fantasy", "4"),
|
||||
TriStateFilter("Historical", "5"),
|
||||
TriStateFilter("Horror", "6"),
|
||||
TriStateFilter("Martial Arts", "7"),
|
||||
TriStateFilter("Mystery", "8"),
|
||||
TriStateFilter("Romance", "9"),
|
||||
TriStateFilter("Shounen Ai", "10"),
|
||||
TriStateFilter("Supernatural", "11"),
|
||||
TriStateFilter("Drama", "12"),
|
||||
TriStateFilter("Shounen", "13"),
|
||||
TriStateFilter("School Life", "14"),
|
||||
TriStateFilter("Shoujo", "15"),
|
||||
TriStateFilter("Gender Bender", "16"),
|
||||
TriStateFilter("Josei", "17"),
|
||||
TriStateFilter("Psychological", "18"),
|
||||
TriStateFilter("Seinen", "19"),
|
||||
TriStateFilter("Slice of Life", "20"),
|
||||
TriStateFilter("Sci-fi", "21"),
|
||||
TriStateFilter("Ecchi", "22"),
|
||||
TriStateFilter("Harem", "23"),
|
||||
TriStateFilter("Shoujo Ai", "24"),
|
||||
TriStateFilter("Yuri", "25"),
|
||||
TriStateFilter("Mature", "26"),
|
||||
TriStateFilter("Tragedy", "27"),
|
||||
TriStateFilter("Yaoi", "28"),
|
||||
TriStateFilter("Doujinshi", "29"),
|
||||
TriStateFilter("Sports", "30"),
|
||||
TriStateFilter("Adult", "31"),
|
||||
TriStateFilter("One Shot", "32"),
|
||||
TriStateFilter("Smut", "33"),
|
||||
TriStateFilter("Mecha", "34"),
|
||||
TriStateFilter("Shotacon", "35"),
|
||||
TriStateFilter("Lolicon", "36"),
|
||||
TriStateFilter("Webtoons", "37"),
|
||||
]),
|
||||
SelectFilter("RatingList", "Minimum rating", 0, [
|
||||
SelectFilterOption("No Stars", "0"),
|
||||
SelectFilterOption("1 Star", "1"),
|
||||
SelectFilterOption("2 Stars", "2"),
|
||||
SelectFilterOption("3 Stars", "3"),
|
||||
SelectFilterOption("4 Stars", "4"),
|
||||
SelectFilterOption("5 Stars", "5"),
|
||||
]),
|
||||
TextFilter("YearFilter", "Year released"),
|
||||
SelectFilter("CompletionList", "Completed series", 0, [
|
||||
SelectFilterOption("Either", "0"),
|
||||
SelectFilterOption("No", "1"),
|
||||
SelectFilterOption("Yes", "2"),
|
||||
]),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> getHeader(String url) {
|
||||
final headers = {'Referer': '$url/', "Cookie": "isAdult=1"};
|
||||
return headers;
|
||||
}
|
||||
|
||||
MangaHere main(MSource source) {
|
||||
return MangaHere(source: source);
|
||||
}
|
||||
18
dart/manga/src/en/mangahere/source.dart
Normal file
18
dart/manga/src/en/mangahere/source.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import '../../../../../model/source.dart';
|
||||
|
||||
Source get mangahereSource => _mangahereSource;
|
||||
const _mangahereVersion = "0.0.7";
|
||||
const _mangahereSourceCodeUrl =
|
||||
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/manga/src/en/mangahere/mangahere.dart";
|
||||
Source _mangahereSource = Source(
|
||||
name: "MangaHere",
|
||||
baseUrl: "http://www.mangahere.cc",
|
||||
lang: "en",
|
||||
typeSource: "single",
|
||||
iconUrl:
|
||||
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/manga/src/en/mangahere/icon.png",
|
||||
sourceCodeUrl: _mangahereSourceCodeUrl,
|
||||
version: _mangahereVersion,
|
||||
dateFormat: "MMM dd,yyyy",
|
||||
dateFormatLocale: "en",
|
||||
);
|
||||
Reference in New Issue
Block a user