Compare commits
No commits in common. "main" and "prueba" have entirely different histories.
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@ -1 +0,0 @@
|
|||||||
github: sergiotarxz
|
|
48
README.md
48
README.md
@ -2,44 +2,12 @@
|
|||||||
|
|
||||||
OpenMG is a GTK4 + Libadwaita manga reader written in C which uses `readmng` as its backend.
|
OpenMG is a GTK4 + Libadwaita manga reader written in C which uses `readmng` as its backend.
|
||||||
|
|
||||||
[![Please do not theme this app](https://stopthemingmy.app/badge.svg)](https://stopthemingmy.app)
|
|
||||||
|
|
||||||
## Demostration
|
## Demostration
|
||||||
|
|
||||||
![Demostration vídeo of the manga reader.](https://gitea.sergiotarxz.freemyip.com/sergiotarxz/mangareader/raw/branch/main/demostration.gif)
|
![Demostration vídeo of the manga reader.](https://gitea.sergiotarxz.freemyip.com/sergiotarxz/mangareader/raw/branch/main/demostration.gif)
|
||||||
|
|
||||||
## Installing the app.
|
## Installing the app.
|
||||||
|
|
||||||
These are the installation methods supported currently.
|
|
||||||
|
|
||||||
### Flatpak
|
|
||||||
|
|
||||||
Download from https://gitea.sergiotarxz.freemyip.com/sergiotarxz/mangareader/releases the latest `openmg-x86_64-(version).flatpak` and run:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
flatpak install openmg-x86_64-(version).flatpak
|
|
||||||
```
|
|
||||||
|
|
||||||
Beware that not being in Flathub yet you will have to come here again
|
|
||||||
to get updates.
|
|
||||||
|
|
||||||
### Gentoo
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo eselect repository enable sergiotarxz
|
|
||||||
echo 'app-misc/openmg ~amd64' | sudo tee -a /etc/portage/package.accept_keywords/zz-autounmask
|
|
||||||
sudo emerge -a openmg --autounmask
|
|
||||||
```
|
|
||||||
|
|
||||||
If the installation ask you for a package masked for ~amd64 you can run
|
|
||||||
`sudo etc-update`, upgrade the `package.accept_keywords` config file
|
|
||||||
and try again the latest command of the installation instructions.
|
|
||||||
|
|
||||||
|
|
||||||
## Build from source
|
|
||||||
|
|
||||||
### Flatpak
|
|
||||||
|
|
||||||
First fine tune the options in `me.sergiotarxz.openmg.json` for
|
First fine tune the options in `me.sergiotarxz.openmg.json` for
|
||||||
meson you want to have, for example preview images, complete list is
|
meson you want to have, for example preview images, complete list is
|
||||||
on `meson_options.txt`
|
on `meson_options.txt`
|
||||||
@ -52,28 +20,12 @@ flatpak-builder --install --user build me.sergiotarxz.openmg.json me.sergiotarxz
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Native
|
|
||||||
|
|
||||||
```shell
|
|
||||||
meson build
|
|
||||||
meson compile -C build
|
|
||||||
sudo meson install -C build
|
|
||||||
```
|
|
||||||
|
|
||||||
## Running the app
|
## Running the app
|
||||||
|
|
||||||
If using flatpak:
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
flatpak run me.sergiotarxz.openmg
|
flatpak run me.sergiotarxz.openmg
|
||||||
```
|
```
|
||||||
|
|
||||||
If native installated:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
openmg
|
|
||||||
```
|
|
||||||
|
|
||||||
## Donations welcome:
|
## Donations welcome:
|
||||||
|
|
||||||
btc: `bc1q0apxdedrm5vjn3zr0hxswnruk2x2uecwqrusmj`
|
btc: `bc1q0apxdedrm5vjn3zr0hxswnruk2x2uecwqrusmj`
|
||||||
|
92
RELEASE.PL
92
RELEASE.PL
@ -1,92 +0,0 @@
|
|||||||
use v5.30.0;
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
use Const::Fast;
|
|
||||||
|
|
||||||
use Path::Tiny qw/path/;
|
|
||||||
use JSON;
|
|
||||||
use File::pushd;
|
|
||||||
|
|
||||||
use Mojo::URL;
|
|
||||||
use Mojo::UserAgent;
|
|
||||||
|
|
||||||
my $tag = $ARGV[0];
|
|
||||||
my $title = $ARGV[1] // "Automated release without title $tag";
|
|
||||||
my $description = $ARGV[2] // '';
|
|
||||||
|
|
||||||
const my $config_file => "$ENV{HOME}/.config/openmg_releaser.json";
|
|
||||||
|
|
||||||
if ( !-f $config_file ) {
|
|
||||||
die "No credentials in $config_file.";
|
|
||||||
}
|
|
||||||
my $config_file_contents = path($config_file)->slurp_utf8;
|
|
||||||
my $config = decode_json($config_file_contents);
|
|
||||||
my $username = $config->{username} // die "No user in config.";
|
|
||||||
my $token = $config->{token} // die "No token in config.";
|
|
||||||
my $host = $config->{host} // die "No host in config.";
|
|
||||||
my $commit = `git rev-parse HEAD`;
|
|
||||||
my $clone_path = Path::Tiny->tempdir;
|
|
||||||
system qw/git clone/,
|
|
||||||
'https://gitea.sergiotarxz.freemyip.com/sergiotarxz/mangareader/',
|
|
||||||
$clone_path;
|
|
||||||
|
|
||||||
my @subs = (compile('x86_64'), compile('aarch64'));
|
|
||||||
|
|
||||||
my $arch = shift;
|
|
||||||
my $release = request(
|
|
||||||
POST => '/repos/sergiotarxz/mangareader/releases' => json => {
|
|
||||||
body => $description,
|
|
||||||
name => $title,
|
|
||||||
tag_name => $tag,
|
|
||||||
target_commitish => 'main',
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
print Data::Dumper::Dumper $release;
|
|
||||||
my $release_id = $release->{id};
|
|
||||||
|
|
||||||
for my $sub (@subs) {
|
|
||||||
$sub->() if ref $sub eq 'CODE';
|
|
||||||
}
|
|
||||||
|
|
||||||
sub compile {
|
|
||||||
my $arch = shift;
|
|
||||||
my $flatpak_builder_file = 'me.sergiotarxz.openmg.json';
|
|
||||||
my $app_id = 'me.sergiotarxz.openmg';
|
|
||||||
my $app_output_name = path("openmg-$arch-$tag.flatpak")->absolute;
|
|
||||||
system 'cp', '/usr/bin/qemu-aarch64',
|
|
||||||
"$ENV{HOME}/.local/share/flatpak/runtime/org.gnome.Sdk/aarch64/master/active/files/bin/";
|
|
||||||
|
|
||||||
my $push = pushd $clone_path;
|
|
||||||
system 'flatpak-builder', '--force-clean', '--arch', $arch, '--install', '--user',
|
|
||||||
'build', $flatpak_builder_file, $app_id
|
|
||||||
and return 1;
|
|
||||||
system 'flatpak', 'build-bundle', '--arch', $arch,
|
|
||||||
path( $ENV{HOME} )->child('.local/share/flatpak/repo/'),
|
|
||||||
$app_output_name, $app_id
|
|
||||||
and return 1;
|
|
||||||
return sub {
|
|
||||||
print Data::Dumper::Dumper request( POST =>
|
|
||||||
"/repos/sergiotarxz/mangareader/releases/$release_id/assets?name=@{[$app_output_name->basename]}"
|
|
||||||
=> form => { attachment => { file => "" . $app_output_name } } );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub request {
|
|
||||||
my $method = shift // die "No method passed.";
|
|
||||||
my $endpoint = shift // die "No endpoint passed.";
|
|
||||||
my $body_type = shift // die "No body type passed.";
|
|
||||||
my $body = shift // die "No body passed.";
|
|
||||||
my $ua = Mojo::UserAgent->new();
|
|
||||||
my $url = Mojo::URL->new("https://$host/api/v1/$endpoint");
|
|
||||||
$url->query( token => $token );
|
|
||||||
say $url;
|
|
||||||
my $tx = $ua->build_tx( $method => $url => {} => $body_type => $body );
|
|
||||||
$ua->start($tx);
|
|
||||||
my $response = $tx->result;
|
|
||||||
say $response->code;
|
|
||||||
say $response->message;
|
|
||||||
return decode_json( $response->body );
|
|
||||||
}
|
|
@ -8,12 +8,10 @@ G_DECLARE_FINAL_TYPE (MgUtilString, mg_util_string, MG, UTIL_STRING, GObject)
|
|||||||
|
|
||||||
MgUtilString *mg_util_string_new ();
|
MgUtilString *mg_util_string_new ();
|
||||||
char *
|
char *
|
||||||
mg_util_string_alloc_string (MgUtilString *self, size_t len);
|
mg_util_string_alloc_string(MgUtilString *self, size_t len);
|
||||||
void
|
void
|
||||||
mg_util_string_copy_substring (MgUtilString *self,
|
mg_util_string_copy_substring(MgUtilString *self,
|
||||||
const char *origin, char *dest, size_t dest_len, size_t start,
|
const char *origin, char *dest, size_t dest_len, size_t start,
|
||||||
size_t len);
|
size_t len);
|
||||||
|
|
||||||
int
|
|
||||||
g_asprintf (char **strp, const char *format, ...);
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@ -27,15 +27,11 @@ mg_util_xml_loop_search_class (MgUtilXML *self, const xmlNodePtr node, xmlNodePt
|
|||||||
const char * class, size_t *len);
|
const char * class, size_t *len);
|
||||||
xmlXPathObjectPtr
|
xmlXPathObjectPtr
|
||||||
mg_util_xml_get_nodes_xpath_expression (MgUtilXML *self,
|
mg_util_xml_get_nodes_xpath_expression (MgUtilXML *self,
|
||||||
const xmlDocPtr document, const xmlNodePtr node, char *xpath);
|
const xmlDocPtr document, char *xpath);
|
||||||
int
|
int
|
||||||
mg_util_xml_has_class (MgUtilXML *self,
|
mg_util_xml_has_class (MgUtilXML *self,
|
||||||
const char *class_attribute, const char *class_to_check);
|
const char *class_attribute, const char *class_to_check);
|
||||||
char *
|
char *
|
||||||
mg_util_xml_get_title_text (MgUtilXML *self,
|
mg_util_xml_get_title_text (MgUtilXML *self,
|
||||||
const char *const text);
|
const char *const text);
|
||||||
void
|
|
||||||
mg_util_xml_print_debug_nodes (MgUtilXML *self,
|
|
||||||
const xmlDocPtr html_document, xmlNodePtr *nodes,
|
|
||||||
size_t nodes_len);
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@ -57,6 +57,14 @@ mg_backend_readmng_class_init (MgBackendReadmngClass *class) {
|
|||||||
mg_backend_readmng_properties);
|
mg_backend_readmng_properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static xmlNodePtr
|
||||||
|
mg_backend_readmng_get_a_for_chapter (
|
||||||
|
MgBackendReadmng *self,
|
||||||
|
xmlNodePtr li);
|
||||||
|
static MgMangaChapter *
|
||||||
|
mg_backend_readmng_loop_li_chapter (
|
||||||
|
MgBackendReadmng *self,
|
||||||
|
xmlNodePtr li);
|
||||||
static char *
|
static char *
|
||||||
mg_backend_readmng_fetch_search (MgBackendReadmng *self,
|
mg_backend_readmng_fetch_search (MgBackendReadmng *self,
|
||||||
const char *search_query, size_t *response_len);
|
const char *search_query, size_t *response_len);
|
||||||
@ -68,10 +76,21 @@ mg_backend_readmng_fetch_page_url (MgBackendReadmng *self,
|
|||||||
MgMangaChapter *chapter);
|
MgMangaChapter *chapter);
|
||||||
static GListStore *
|
static GListStore *
|
||||||
mg_backend_readmng_recover_chapter_list (MgBackendReadmng *self,
|
mg_backend_readmng_recover_chapter_list (MgBackendReadmng *self,
|
||||||
xmlDocPtr html_document_details, MgManga *manga);
|
xmlDocPtr html_document_details);
|
||||||
static xmlDocPtr
|
static xmlDocPtr
|
||||||
mg_backend_readmng_fetch_xml_details (MgBackendReadmng *self,
|
mg_backend_readmng_fetch_xml_details (MgBackendReadmng *self,
|
||||||
MgManga *manga);
|
MgManga *manga);
|
||||||
|
static xmlNodePtr
|
||||||
|
mg_backend_readmng_retrieve_img_from_thumbnail (MgBackendReadmng *self, xmlNodePtr thumbnail);
|
||||||
|
static xmlNodePtr
|
||||||
|
mg_backend_readmng_retrieve_ul_slides (MgBackendReadmng *self, xmlNodePtr slides) ;
|
||||||
|
static void
|
||||||
|
mg_backend_readmng_extract_manga_info_from_current_li (MgBackendReadmng *self,
|
||||||
|
GListStore *mangas, xmlNodePtr current_li);
|
||||||
|
static xmlNodePtr *
|
||||||
|
mg_backend_readmng_retrieve_li_slides (MgBackendReadmng *self, const xmlNodePtr slides, size_t *li_len);
|
||||||
|
static xmlNodePtr
|
||||||
|
mg_backend_readmng_retrieve_slides (MgBackendReadmng *self, const xmlDocPtr html_document);
|
||||||
static const char *
|
static const char *
|
||||||
mg_backend_readmng_get_main_page (MgBackendReadmng *self, size_t *len);
|
mg_backend_readmng_get_main_page (MgBackendReadmng *self, size_t *len);
|
||||||
static GListStore *
|
static GListStore *
|
||||||
@ -80,21 +99,6 @@ static xmlDocPtr
|
|||||||
mg_backend_readmng_fetch_xml_main_page (MgBackendReadmng *self);
|
mg_backend_readmng_fetch_xml_main_page (MgBackendReadmng *self);
|
||||||
static char *
|
static char *
|
||||||
mg_backend_readmng_get_id_manga_link_from_string (MgBackendReadmng *self, const char *url);
|
mg_backend_readmng_get_id_manga_link_from_string (MgBackendReadmng *self, const char *url);
|
||||||
static char *
|
|
||||||
mg_backend_readmng_get_manga_id_main_page (MgBackendReadmng *self,
|
|
||||||
xmlDocPtr html_document, xmlNodePtr manga_slider_card);
|
|
||||||
static char *
|
|
||||||
mg_backend_readmng_get_manga_title_main_page (MgBackendReadmng *self,
|
|
||||||
xmlDocPtr html_document, xmlNodePtr manga_slider_card);
|
|
||||||
static char *
|
|
||||||
mg_backend_readmng_get_manga_image_main_page (MgBackendReadmng *self,
|
|
||||||
xmlDocPtr html_document, xmlNodePtr manga_slider_card);
|
|
||||||
static MgManga *
|
|
||||||
mg_backend_readmng_extract_from_manga_slider_card (MgBackendReadmng *self,
|
|
||||||
xmlDocPtr html_document, xmlNodePtr node);
|
|
||||||
static MgMangaChapter *
|
|
||||||
mg_backend_readmng_get_data_from_check_box_card (MgBackendReadmng *self,
|
|
||||||
xmlDocPtr html_document, xmlNodePtr check_box_card, MgManga *manga);
|
|
||||||
|
|
||||||
MgBackendReadmng *
|
MgBackendReadmng *
|
||||||
mg_backend_readmng_new(void) {
|
mg_backend_readmng_new(void) {
|
||||||
@ -104,7 +108,7 @@ mg_backend_readmng_new(void) {
|
|||||||
static void
|
static void
|
||||||
mg_backend_readmng_init (MgBackendReadmng *self) {
|
mg_backend_readmng_init (MgBackendReadmng *self) {
|
||||||
if (!self->base_url) {
|
if (!self->base_url) {
|
||||||
self->base_url = "https://www.readmng.com";
|
self->base_url = "https://www.readmng.com/";
|
||||||
}
|
}
|
||||||
self->xml_utils = mg_util_xml_new ();
|
self->xml_utils = mg_util_xml_new ();
|
||||||
}
|
}
|
||||||
@ -176,218 +180,30 @@ mg_backend_readmng_get_chapter_images (MgBackendReadmng *self, MgMangaChapter *c
|
|||||||
static GListModel *
|
static GListModel *
|
||||||
mg_backend_readmng_parse_page (MgBackendReadmng *self,
|
mg_backend_readmng_parse_page (MgBackendReadmng *self,
|
||||||
xmlDocPtr html_document) {
|
xmlDocPtr html_document) {
|
||||||
GListModel *images = G_LIST_MODEL (gtk_string_list_new (NULL));
|
GListModel *images = G_LIST_MODEL
|
||||||
MgUtilXML *xml_utils = self->xml_utils;
|
(gtk_string_list_new (NULL));
|
||||||
MgUtilRegex *regex_util = mg_util_regex_new ();
|
|
||||||
xmlNodeSetPtr node_set = NULL;
|
MgUtilXML *xml_utils = self->xml_utils;
|
||||||
xmlXPathObjectPtr xpath_result = NULL;
|
xmlXPathObjectPtr xpath_result = NULL;
|
||||||
xmlNodePtr script = NULL;
|
xmlNodeSetPtr node_set = NULL;
|
||||||
JsonParser *parser = json_parser_new ();
|
|
||||||
JsonNode *root = NULL;
|
|
||||||
JsonObject *root_object = NULL;
|
|
||||||
JsonArray *sources = NULL;
|
|
||||||
JsonArray *images_json_object = NULL;
|
|
||||||
JsonObject *source = NULL;
|
|
||||||
guint sources_len;
|
|
||||||
GError *error = NULL;
|
|
||||||
char *ts_reader_run = NULL;
|
|
||||||
char *ts_reader_run_json = NULL;
|
|
||||||
xpath_result = mg_util_xml_get_nodes_xpath_expression (xml_utils,
|
xpath_result = mg_util_xml_get_nodes_xpath_expression (xml_utils,
|
||||||
html_document, NULL, "//script[contains(., 'ts_reader')]");
|
html_document, "//img[@class]");
|
||||||
if (!xpath_result) {
|
node_set = xpath_result->nodesetval;
|
||||||
fprintf(stderr, "No match for images.\n");
|
if (!node_set) {
|
||||||
}
|
fprintf(stderr, "No match for images.\n");
|
||||||
node_set = xpath_result->nodesetval;
|
|
||||||
if (!node_set) {
|
|
||||||
fprintf(stderr, "No match for images.\n");
|
|
||||||
goto cleanup_mg_backend_readmng_parse_page;
|
goto cleanup_mg_backend_readmng_parse_page;
|
||||||
}
|
}
|
||||||
script = node_set->nodeTab[0];
|
for (int i = 0; i < node_set->nodeNr; i++) {
|
||||||
ts_reader_run = (char *)xmlNodeGetContent (script);
|
xmlNodePtr node = node_set->nodeTab[i];
|
||||||
ts_reader_run_json = mg_util_regex_match_1 (regex_util,
|
char *image_url = mg_util_xml_get_attr (xml_utils, node, "src");
|
||||||
"^\\s+ts_reader\\.run\\(((?:.|\\r|\\n)+)\\);", ts_reader_run);
|
gtk_string_list_append (GTK_STRING_LIST (images), image_url);
|
||||||
json_parser_load_from_data (parser, ts_reader_run_json, -1,
|
g_free (image_url);
|
||||||
&error);
|
}
|
||||||
if (error) {
|
|
||||||
g_warning ("Unable to parse json: %s.", error->message);
|
|
||||||
g_clear_error (&error);
|
|
||||||
goto cleanup_mg_backend_readmng_parse_page;
|
|
||||||
}
|
|
||||||
root = json_parser_get_root (parser);
|
|
||||||
if (json_node_get_node_type (root) != JSON_NODE_OBJECT) {
|
|
||||||
fprintf(stderr, "Expected object as JSON root.\n");
|
|
||||||
goto cleanup_mg_backend_readmng_parse_page;
|
|
||||||
}
|
|
||||||
root_object = json_node_get_object (root);
|
|
||||||
sources = json_object_get_array_member (root_object, "sources");
|
|
||||||
if (!sources) {
|
|
||||||
fprintf(stderr, "No source in JSON.\n");
|
|
||||||
goto cleanup_mg_backend_readmng_parse_page;
|
|
||||||
}
|
|
||||||
sources_len = json_array_get_length (sources);
|
|
||||||
if (!sources_len) {
|
|
||||||
fprintf(stderr, "No source element in JSON.\n");
|
|
||||||
goto cleanup_mg_backend_readmng_parse_page;
|
|
||||||
}
|
|
||||||
source = json_array_get_object_element (sources, 0);
|
|
||||||
images_json_object = json_object_get_array_member (source, "images");
|
|
||||||
if (!images_json_object) {
|
|
||||||
fprintf(stderr, "No images in JSON.\n");
|
|
||||||
goto cleanup_mg_backend_readmng_parse_page;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < json_array_get_length(images_json_object); i++) {
|
|
||||||
gtk_string_list_append (GTK_STRING_LIST (images),
|
|
||||||
json_array_get_string_element (images_json_object, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup_mg_backend_readmng_parse_page:
|
cleanup_mg_backend_readmng_parse_page:
|
||||||
if (ts_reader_run) {
|
xmlXPathFreeObject(xpath_result);
|
||||||
g_free (ts_reader_run);
|
|
||||||
}
|
|
||||||
if (ts_reader_run_json) {
|
|
||||||
pcre2_substring_free ((PCRE2_UCHAR8 *)ts_reader_run_json);
|
|
||||||
}
|
|
||||||
if (xpath_result) {
|
|
||||||
xmlXPathFreeObject(xpath_result);
|
|
||||||
}
|
|
||||||
if (parser) {
|
|
||||||
g_clear_object (&parser);
|
|
||||||
}
|
|
||||||
return images;
|
return images;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static MgManga *
|
|
||||||
mg_backend_readmng_extract_from_manga_slider_card (MgBackendReadmng *self,
|
|
||||||
xmlDocPtr html_document, xmlNodePtr node) {
|
|
||||||
MgManga *manga = NULL;
|
|
||||||
char *image = NULL;
|
|
||||||
char *title = NULL;
|
|
||||||
char *id = NULL;
|
|
||||||
image = mg_backend_readmng_get_manga_image_main_page (self, html_document,
|
|
||||||
node);
|
|
||||||
title = mg_backend_readmng_get_manga_title_main_page (self, html_document,
|
|
||||||
node);
|
|
||||||
id = mg_backend_readmng_get_manga_id_main_page (self, html_document,
|
|
||||||
node);
|
|
||||||
if (!image) {
|
|
||||||
fprintf (stderr, "Failed to find image\n");
|
|
||||||
goto cleanup_mg_backend_readmng_extract_from_manga_slider_card;
|
|
||||||
}
|
|
||||||
if (!title) {
|
|
||||||
fprintf (stderr, "Failed to find title\n");
|
|
||||||
goto cleanup_mg_backend_readmng_extract_from_manga_slider_card;
|
|
||||||
}
|
|
||||||
if (!id) {
|
|
||||||
fprintf (stderr, "Failed to find id\n");
|
|
||||||
goto cleanup_mg_backend_readmng_extract_from_manga_slider_card;
|
|
||||||
}
|
|
||||||
|
|
||||||
manga = mg_manga_new (image, title, id);
|
|
||||||
cleanup_mg_backend_readmng_extract_from_manga_slider_card:
|
|
||||||
if (image) {
|
|
||||||
g_free (image);
|
|
||||||
}
|
|
||||||
if (title) {
|
|
||||||
g_free (title);
|
|
||||||
}
|
|
||||||
if (id) {
|
|
||||||
pcre2_substring_free ((PCRE2_UCHAR8 *)id);
|
|
||||||
}
|
|
||||||
return manga;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *
|
|
||||||
mg_backend_readmng_get_manga_id_main_page (MgBackendReadmng *self,
|
|
||||||
xmlDocPtr html_document, xmlNodePtr manga_slider_card) {
|
|
||||||
MgUtilXML *xml_utils = self->xml_utils;
|
|
||||||
MgUtilRegex *regex_util = mg_util_regex_new ();
|
|
||||||
xmlXPathObjectPtr xpath_result = NULL;
|
|
||||||
char *id = NULL;
|
|
||||||
char *new_id = NULL;
|
|
||||||
xmlNodeSetPtr node_set = NULL;
|
|
||||||
xpath_result = mg_util_xml_get_nodes_xpath_expression (xml_utils, html_document,
|
|
||||||
manga_slider_card, "./a");
|
|
||||||
if (!xpath_result) {
|
|
||||||
fprintf (stderr, "No matching id.\n");
|
|
||||||
goto cleanup_mg_backend_readmng_get_manga_id_main_page;
|
|
||||||
}
|
|
||||||
node_set = xpath_result->nodesetval;
|
|
||||||
if (!node_set) {
|
|
||||||
fprintf (stderr, "No matching id node set.\n");
|
|
||||||
goto cleanup_mg_backend_readmng_get_manga_id_main_page;
|
|
||||||
}
|
|
||||||
xmlNodePtr a = node_set->nodeTab[0];
|
|
||||||
id = mg_util_xml_get_attr (xml_utils, a, "href");
|
|
||||||
if (id) {
|
|
||||||
new_id = mg_util_regex_match_1 (regex_util, "^/([^/]+)", id);
|
|
||||||
g_free (id);
|
|
||||||
id = new_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup_mg_backend_readmng_get_manga_id_main_page:
|
|
||||||
if (xpath_result) {
|
|
||||||
xmlXPathFreeObject (xpath_result);
|
|
||||||
}
|
|
||||||
g_clear_object (®ex_util);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *
|
|
||||||
mg_backend_readmng_get_manga_title_main_page (MgBackendReadmng *self,
|
|
||||||
xmlDocPtr html_document, xmlNodePtr manga_slider_card) {
|
|
||||||
MgUtilXML *xml_utils = self->xml_utils;
|
|
||||||
xmlXPathObjectPtr xpath_result = NULL;
|
|
||||||
char *title = NULL;
|
|
||||||
xmlNodeSetPtr node_set = NULL;
|
|
||||||
xpath_result = mg_util_xml_get_nodes_xpath_expression (xml_utils, html_document,
|
|
||||||
manga_slider_card, ".//div[@class='postDetail']//h2");
|
|
||||||
if (!xpath_result) {
|
|
||||||
fprintf (stderr, "No matching title.\n");
|
|
||||||
goto cleanup_mg_backend_readmng_get_manga_title_main_page;
|
|
||||||
}
|
|
||||||
node_set = xpath_result->nodesetval;
|
|
||||||
if (!node_set) {
|
|
||||||
fprintf (stderr, "No matching title node set.\n");
|
|
||||||
goto cleanup_mg_backend_readmng_get_manga_title_main_page;
|
|
||||||
}
|
|
||||||
xmlNodePtr h2 = node_set->nodeTab[0];
|
|
||||||
title = (char *)xmlNodeGetContent (h2);
|
|
||||||
cleanup_mg_backend_readmng_get_manga_title_main_page:
|
|
||||||
if (xpath_result) {
|
|
||||||
xmlXPathFreeObject (xpath_result);
|
|
||||||
}
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *
|
|
||||||
mg_backend_readmng_get_manga_image_main_page (MgBackendReadmng *self,
|
|
||||||
xmlDocPtr html_document, xmlNodePtr manga_slider_card) {
|
|
||||||
MgUtilXML *xml_utils = self->xml_utils;
|
|
||||||
xmlXPathObjectPtr xpath_result = NULL;
|
|
||||||
char *image = NULL;
|
|
||||||
xmlNodeSetPtr node_set = NULL;
|
|
||||||
xpath_result = mg_util_xml_get_nodes_xpath_expression (xml_utils, html_document,
|
|
||||||
manga_slider_card, ".//div[@class='sliderImg']//img");
|
|
||||||
if (!xpath_result) {
|
|
||||||
fprintf (stderr, "No matching image.\n");
|
|
||||||
goto cleanup_mg_backend_readmng_get_manga_image_main_page;
|
|
||||||
}
|
|
||||||
node_set = xpath_result->nodesetval;
|
|
||||||
if (!node_set) {
|
|
||||||
fprintf (stderr, "No matching image node set.\n");
|
|
||||||
goto cleanup_mg_backend_readmng_get_manga_image_main_page;
|
|
||||||
}
|
|
||||||
xmlNodePtr img = node_set->nodeTab[0];
|
|
||||||
image = mg_util_xml_get_attr (xml_utils, img, "src");
|
|
||||||
|
|
||||||
cleanup_mg_backend_readmng_get_manga_image_main_page:
|
|
||||||
if (xpath_result) {
|
|
||||||
xmlXPathFreeObject (xpath_result);
|
|
||||||
}
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
static xmlDocPtr
|
static xmlDocPtr
|
||||||
mg_backend_readmng_fetch_page_url (MgBackendReadmng *self,
|
mg_backend_readmng_fetch_page_url (MgBackendReadmng *self,
|
||||||
MgMangaChapter *chapter) {
|
MgMangaChapter *chapter) {
|
||||||
@ -423,13 +239,12 @@ mg_backend_readmng_search (MgBackendReadmng *self,
|
|||||||
size_t response_len = 0;
|
size_t response_len = 0;
|
||||||
char *response = mg_backend_readmng_fetch_search (self, search_query,
|
char *response = mg_backend_readmng_fetch_search (self, search_query,
|
||||||
&response_len);
|
&response_len);
|
||||||
JsonParser *parser = json_parser_new ();
|
JsonParser *parser = json_parser_new ();
|
||||||
GListStore *mangas = g_list_store_new (MG_TYPE_MANGA);
|
GListStore *mangas = g_list_store_new (MG_TYPE_MANGA);
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
JsonNode *root = NULL;
|
JsonNode *root = NULL;
|
||||||
JsonArray *mangas_json_array = NULL;
|
JsonArray *mangas_json_array = NULL;
|
||||||
JsonObject *root_object = NULL;
|
guint mangas_json_array_len = 0;
|
||||||
guint mangas_json_array_len = 0;
|
|
||||||
|
|
||||||
if (!response) {
|
if (!response) {
|
||||||
g_warning ("Json search response is null.");
|
g_warning ("Json search response is null.");
|
||||||
@ -442,13 +257,13 @@ mg_backend_readmng_search (MgBackendReadmng *self,
|
|||||||
goto cleanup_mg_backend_readmng_search;
|
goto cleanup_mg_backend_readmng_search;
|
||||||
}
|
}
|
||||||
root = json_parser_get_root (parser);
|
root = json_parser_get_root (parser);
|
||||||
if (json_node_get_node_type (root) != JSON_NODE_OBJECT) {
|
if (json_node_get_node_type (root) != JSON_NODE_ARRAY) {
|
||||||
goto cleanup_mg_backend_readmng_search;
|
goto cleanup_mg_backend_readmng_search;
|
||||||
}
|
}
|
||||||
root_object = json_node_get_object (root);
|
mangas_json_array = json_node_get_array (root);
|
||||||
mangas_json_array = json_object_get_array_member (root_object, "manga");
|
mangas_json_array_len = json_array_get_length (
|
||||||
mangas_json_array_len = json_array_get_length (mangas_json_array);
|
mangas_json_array);
|
||||||
for (guint i = 0; i < mangas_json_array_len && i < 5; i++) {
|
for (guint i = 0; i < mangas_json_array_len && i < 19; i++) {
|
||||||
JsonObject *manga_json_object =
|
JsonObject *manga_json_object =
|
||||||
json_array_get_object_element (mangas_json_array, i);
|
json_array_get_object_element (mangas_json_array, i);
|
||||||
char *id_manga = NULL;
|
char *id_manga = NULL;
|
||||||
@ -479,9 +294,13 @@ mg_backend_readmng_fetch_search (MgBackendReadmng *self,
|
|||||||
|
|
||||||
char *request_url;
|
char *request_url;
|
||||||
|
|
||||||
|
size_t request_url_len;
|
||||||
|
|
||||||
util_soup = mg_util_soup_new ();
|
util_soup = mg_util_soup_new ();
|
||||||
string_util = mg_util_string_new ();
|
string_util = mg_util_string_new ();
|
||||||
g_asprintf ( &request_url, "%s/%s/", self->base_url, "search/live");
|
request_url_len = snprintf ( NULL, 0, "%s/%s/", self->base_url, "service/search");
|
||||||
|
request_url = mg_util_string_alloc_string (string_util, request_url_len);
|
||||||
|
snprintf ( request_url, request_url_len+1, "%s/%s/", self->base_url, "service/search");
|
||||||
|
|
||||||
SoupParam headers[] = {
|
SoupParam headers[] = {
|
||||||
{
|
{
|
||||||
@ -564,17 +383,23 @@ mg_backend_readmng_retrieve_manga_details (MgBackendReadmng *self,
|
|||||||
html_document = mg_backend_readmng_fetch_xml_details (self,
|
html_document = mg_backend_readmng_fetch_xml_details (self,
|
||||||
manga);
|
manga);
|
||||||
xpath_result = mg_util_xml_get_nodes_xpath_expression (xml_utils,
|
xpath_result = mg_util_xml_get_nodes_xpath_expression (xml_utils,
|
||||||
html_document, NULL, "//div[@class='infox']//div[@class='wd-full'][2]");
|
html_document, "//li[@class]");
|
||||||
node_set = xpath_result->nodesetval;
|
node_set = xpath_result->nodesetval;
|
||||||
if (!node_set) {
|
if (!node_set) {
|
||||||
fprintf(stderr, "No match\n");
|
fprintf(stderr, "No match\n");
|
||||||
goto cleanup_mg_backend_readmng_retrieve_manga_details;
|
goto cleanup_mg_backend_readmng_retrieve_manga_details;
|
||||||
}
|
}
|
||||||
xmlNodePtr description_node = node_set->nodeTab[0];
|
for (int i = 0; i < node_set->nodeNr; i++) {
|
||||||
char *description = (char *) xmlNodeGetContent (description_node);
|
xmlNodePtr node = node_set->nodeTab[i];
|
||||||
mg_manga_set_description (manga, description);
|
movie_detail = mg_util_xml_loop_search_class (xml_utils,
|
||||||
g_free (description);
|
node, movie_detail, "movie-detail", &movie_detail_len);
|
||||||
manga_chapters = mg_backend_readmng_recover_chapter_list (self, html_document, manga);
|
}
|
||||||
|
if (movie_detail) {
|
||||||
|
char *description = (char *) xmlNodeGetContent (movie_detail[0]);
|
||||||
|
mg_manga_set_description (manga, description);
|
||||||
|
g_free (description);
|
||||||
|
}
|
||||||
|
manga_chapters = mg_backend_readmng_recover_chapter_list (self, html_document);
|
||||||
mg_manga_set_chapter_list (manga, manga_chapters);
|
mg_manga_set_chapter_list (manga, manga_chapters);
|
||||||
mg_manga_details_recovered (manga);
|
mg_manga_details_recovered (manga);
|
||||||
cleanup_mg_backend_readmng_retrieve_manga_details:
|
cleanup_mg_backend_readmng_retrieve_manga_details:
|
||||||
@ -594,74 +419,104 @@ cleanup_mg_backend_readmng_retrieve_manga_details:
|
|||||||
|
|
||||||
static GListStore *
|
static GListStore *
|
||||||
mg_backend_readmng_recover_chapter_list (MgBackendReadmng *self,
|
mg_backend_readmng_recover_chapter_list (MgBackendReadmng *self,
|
||||||
xmlDocPtr html_document_details, MgManga *manga) {
|
xmlDocPtr html_document_details) {
|
||||||
MgUtilXML *xml_utils = self->xml_utils;
|
MgUtilXML *xml_utils = self->xml_utils;
|
||||||
xmlXPathObjectPtr xpath_result = NULL;
|
xmlXPathObjectPtr xpath_result = NULL;
|
||||||
xmlNodeSetPtr node_set = NULL;
|
xmlNodeSetPtr node_set = NULL;
|
||||||
GListStore *return_value = g_list_store_new (
|
xmlNodePtr *uls = NULL;
|
||||||
|
xmlNodePtr ul;
|
||||||
|
GListStore *return_value = g_list_store_new (
|
||||||
MG_TYPE_MANGA_CHAPTER);
|
MG_TYPE_MANGA_CHAPTER);
|
||||||
|
size_t ul_len = 0;
|
||||||
|
|
||||||
xpath_result = mg_util_xml_get_nodes_xpath_expression (xml_utils,
|
xpath_result = mg_util_xml_get_nodes_xpath_expression (xml_utils,
|
||||||
html_document_details, NULL, "//div[@class='checkBoxCard']");
|
html_document_details, "//ul[@class]");
|
||||||
node_set = xpath_result->nodesetval;
|
node_set = xpath_result->nodesetval;
|
||||||
|
|
||||||
if (!node_set) {
|
if (!node_set) {
|
||||||
fprintf(stderr, "No matching chapter\n");
|
fprintf(stderr, "No matching ul\n");
|
||||||
goto cleanup_mg_backend_readmng_recover_chapter_list;
|
goto cleanup_mg_backend_readmng_recover_chapter_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < node_set->nodeNr; i++) {
|
for (int i = 0; i < node_set->nodeNr; i++) {
|
||||||
xmlNodePtr check_box_card = node_set->nodeTab[i];
|
xmlNodePtr node = node_set->nodeTab[i];
|
||||||
MgMangaChapter *chapter = mg_backend_readmng_get_data_from_check_box_card
|
uls = mg_util_xml_loop_search_class (xml_utils,
|
||||||
(self, html_document_details, check_box_card, manga);
|
node, uls, "chp_lst", &ul_len);
|
||||||
if (chapter) {
|
}
|
||||||
g_list_store_append (return_value, chapter);
|
if (!ul_len) {
|
||||||
}
|
fprintf(stderr, "No matching chp_lst\n");
|
||||||
|
goto cleanup_mg_backend_readmng_recover_chapter_list;
|
||||||
|
}
|
||||||
|
ul = uls[0];
|
||||||
|
for (xmlNodePtr li = ul->children; li; li = li->next) {
|
||||||
|
if (!strcmp ((char *) li->name, "li")) {
|
||||||
|
MgMangaChapter *chapter = mg_backend_readmng_loop_li_chapter (self, li);
|
||||||
|
if (chapter) {
|
||||||
|
g_list_store_append (return_value, chapter);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cleanup_mg_backend_readmng_recover_chapter_list:
|
cleanup_mg_backend_readmng_recover_chapter_list:
|
||||||
if (xpath_result) {
|
if (xpath_result) {
|
||||||
xmlXPathFreeObject(xpath_result);
|
xmlXPathFreeObject(xpath_result);
|
||||||
}
|
}
|
||||||
|
if (uls) {
|
||||||
|
for (size_t i = 0; i < ul_len; i++) {
|
||||||
|
xmlFreeNode(uls[i]);
|
||||||
|
}
|
||||||
|
g_free (uls);
|
||||||
|
}
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MgMangaChapter *
|
static MgMangaChapter *
|
||||||
mg_backend_readmng_get_data_from_check_box_card (MgBackendReadmng *self,
|
mg_backend_readmng_loop_li_chapter (
|
||||||
xmlDocPtr html_document, xmlNodePtr check_box_card, MgManga *manga) {
|
MgBackendReadmng *self,
|
||||||
xmlXPathObjectPtr xpath_result = NULL;
|
xmlNodePtr li) {
|
||||||
xmlNodeSetPtr node_set = NULL;
|
MgUtilXML *xml_utils = self->xml_utils;
|
||||||
MgMangaChapter *chapter = NULL;
|
MgMangaChapter *chapter = NULL;
|
||||||
MgUtilXML *xml_utils = self->xml_utils;
|
xmlNodePtr a = mg_backend_readmng_get_a_for_chapter (
|
||||||
char *chapter_id = NULL;
|
self, li);
|
||||||
char *title = NULL;
|
if (!a) return NULL;
|
||||||
char *url = NULL;
|
|
||||||
char *manga_id = mg_manga_get_id (manga);
|
|
||||||
xpath_result = mg_util_xml_get_nodes_xpath_expression (xml_utils,
|
|
||||||
html_document, check_box_card, ".//label[@data-chapter-id]");
|
|
||||||
if (!xpath_result) {
|
|
||||||
fprintf(stderr, "Unable to parse chapter, xpath failed.\n");
|
|
||||||
goto cleanup_mg_backend_readmng_get_data_from_check_box_card;
|
|
||||||
}
|
|
||||||
node_set = xpath_result->nodesetval;
|
|
||||||
if (!node_set) {
|
|
||||||
fprintf(stderr, "Unable to parse chapter, no nodeset.\n");
|
|
||||||
goto cleanup_mg_backend_readmng_get_data_from_check_box_card;
|
|
||||||
}
|
|
||||||
xmlNodePtr chapter_node = node_set->nodeTab[0];
|
|
||||||
chapter_id = mg_util_xml_get_attr (xml_utils, chapter_node, "data-chapter-id");
|
|
||||||
|
|
||||||
g_asprintf (&title, "Chapter %s", chapter_id);
|
char *url = mg_util_xml_get_attr (xml_utils, a, "href");
|
||||||
g_asprintf (&url, "%s/%s/%s", self->base_url, manga_id, chapter_id);
|
size_t val_len = 0;
|
||||||
chapter = mg_manga_chapter_new (title, "", url);
|
size_t dte_len = 0;
|
||||||
|
|
||||||
cleanup_mg_backend_readmng_get_data_from_check_box_card:
|
xmlNodePtr *val = mg_util_xml_find_class (xml_utils, a, "val", &val_len, NULL, 1);
|
||||||
if (xpath_result) {
|
xmlNodePtr *dte = mg_util_xml_find_class (xml_utils, a, "dte", &dte_len, NULL, 1);
|
||||||
xmlXPathFreeObject (xpath_result);
|
if (val_len && dte_len) {
|
||||||
}
|
char *val_str = (char *) xmlNodeGetContent (val[0]);
|
||||||
if (chapter_id) {
|
char *dte_str = (char *) xmlNodeGetContent (dte[0]);
|
||||||
g_free (chapter_id);
|
|
||||||
}
|
chapter = mg_manga_chapter_new (val_str, dte_str, url);
|
||||||
return chapter;
|
|
||||||
|
g_free (val_str);
|
||||||
|
g_free (dte_str);
|
||||||
|
}
|
||||||
|
if (url) {
|
||||||
|
g_free (url);
|
||||||
|
}
|
||||||
|
if (val) {
|
||||||
|
g_free (val);
|
||||||
|
val = NULL;
|
||||||
|
}
|
||||||
|
if (dte) {
|
||||||
|
g_free (dte);
|
||||||
|
dte = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xmlNodePtr
|
||||||
|
mg_backend_readmng_get_a_for_chapter (
|
||||||
|
MgBackendReadmng *self,
|
||||||
|
xmlNodePtr li) {
|
||||||
|
for (xmlNodePtr child = li->children; child; child = child->next) {
|
||||||
|
if (!strcmp((char *) child->name, "a")) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static xmlDocPtr
|
static xmlDocPtr
|
||||||
@ -673,12 +528,15 @@ mg_backend_readmng_fetch_xml_details (MgBackendReadmng *self,
|
|||||||
char *request_url;
|
char *request_url;
|
||||||
char *manga_id;
|
char *manga_id;
|
||||||
|
|
||||||
|
size_t request_url_len;
|
||||||
size_t response_len = 0;
|
size_t response_len = 0;
|
||||||
|
|
||||||
util_soup = mg_util_soup_new ();
|
util_soup = mg_util_soup_new ();
|
||||||
string_util = mg_util_string_new ();
|
string_util = mg_util_string_new ();
|
||||||
manga_id = mg_manga_get_id (manga);
|
manga_id = mg_manga_get_id (manga);
|
||||||
g_asprintf ( &request_url, "%s/%s", self->base_url, manga_id);
|
request_url_len = snprintf ( NULL, 0, "%s/%s/", self->base_url, manga_id);
|
||||||
|
request_url = mg_util_string_alloc_string (string_util, request_url_len);
|
||||||
|
snprintf ( request_url, request_url_len+1, "%s/%s/", self->base_url, manga_id);
|
||||||
g_free (manga_id);
|
g_free (manga_id);
|
||||||
|
|
||||||
char *html_response = mg_util_soup_get_request (util_soup,
|
char *html_response = mg_util_soup_get_request (util_soup,
|
||||||
@ -725,39 +583,176 @@ mg_backend_readmng_get_main_page (MgBackendReadmng *self, size_t *len) {
|
|||||||
|
|
||||||
static GListStore *
|
static GListStore *
|
||||||
mg_backend_readmng_parse_main_page (MgBackendReadmng *self, const xmlDocPtr html_document) {
|
mg_backend_readmng_parse_main_page (MgBackendReadmng *self, const xmlDocPtr html_document) {
|
||||||
GListStore *mangas = g_list_store_new (MG_TYPE_MANGA);
|
GListStore *mangas = g_list_store_new(MG_TYPE_MANGA);
|
||||||
|
xmlNodePtr *li;
|
||||||
|
|
||||||
MgUtilXML *xml_utils = self->xml_utils;
|
xmlNodePtr slides = mg_backend_readmng_retrieve_slides (self, html_document);
|
||||||
|
|
||||||
|
size_t li_len = 0;
|
||||||
|
li = mg_backend_readmng_retrieve_li_slides (self, slides, &li_len);
|
||||||
|
for (int i = 0; i<li_len; i++) {
|
||||||
|
xmlNodePtr current_li = li[i];
|
||||||
|
mg_backend_readmng_extract_manga_info_from_current_li (self,
|
||||||
|
mangas, current_li);
|
||||||
|
xmlFreeNode (current_li);
|
||||||
|
li[i] = NULL;
|
||||||
|
}
|
||||||
|
xmlFreeNode(slides);
|
||||||
|
g_free (li);
|
||||||
|
return mangas;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xmlNodePtr *
|
||||||
|
mg_backend_readmng_retrieve_li_slides (MgBackendReadmng *self, const xmlNodePtr slides, size_t *li_len) {
|
||||||
|
xmlNodePtr ul_slides = mg_backend_readmng_retrieve_ul_slides (self, slides);
|
||||||
|
xmlNodePtr *li = NULL;
|
||||||
|
for (xmlNodePtr child = ul_slides->children; child; child=child->next) {
|
||||||
|
(*li_len)++;
|
||||||
|
li = g_realloc(li, sizeof *li * *li_len);
|
||||||
|
li[*li_len-1] = xmlCopyNode(child, XML_COPY_NODE_RECURSIVE);
|
||||||
|
}
|
||||||
|
return li;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xmlNodePtr
|
||||||
|
mg_backend_readmng_retrieve_ul_slides(MgBackendReadmng *self, xmlNodePtr slides) {
|
||||||
|
for (xmlNodePtr child = slides->children; child; child = child->next) {
|
||||||
|
if (!strcmp((char *) child->name, "ul")) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xmlNodePtr
|
||||||
|
mg_backend_readmng_retrieve_slides (MgBackendReadmng *self, const xmlDocPtr html_document) {
|
||||||
|
xmlNodePtr *nodes = NULL;
|
||||||
xmlXPathObjectPtr xpath_result = NULL;
|
xmlXPathObjectPtr xpath_result = NULL;
|
||||||
xmlNodeSetPtr node_set = NULL;
|
MgUtilXML *xml_utils = self->xml_utils;
|
||||||
xpath_result = mg_util_xml_get_nodes_xpath_expression (xml_utils,
|
xpath_result = mg_util_xml_get_nodes_xpath_expression (xml_utils,
|
||||||
html_document, NULL, "//div[@class='mangaSliderCard']");
|
html_document, "//div[@class]");
|
||||||
|
xmlNodePtr slides = NULL;
|
||||||
|
xmlNodeSetPtr node_set = NULL;
|
||||||
|
size_t matching_classes_len = 0;
|
||||||
|
|
||||||
node_set = xpath_result->nodesetval;
|
node_set = xpath_result->nodesetval;
|
||||||
if (!node_set) {
|
if (!node_set) {
|
||||||
fprintf(stderr, "No match for mangas.\n");
|
fprintf(stderr, "No match\n");
|
||||||
goto cleanup_mg_backend_readmng_parse_main_page;
|
goto cleanup_mg_backend_readmng_retrieve_slides;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < node_set->nodeNr; i++) {
|
for (int i = 0; i < node_set->nodeNr; i++) {
|
||||||
xmlNodePtr node = node_set->nodeTab[i];
|
xmlNodePtr node = node_set->nodeTab[i];
|
||||||
MgManga *manga = mg_backend_readmng_extract_from_manga_slider_card (self,
|
nodes = mg_util_xml_loop_search_class (xml_utils, node, nodes,
|
||||||
html_document, node);
|
"slides", &matching_classes_len);
|
||||||
if (!manga) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
g_list_store_append (mangas, manga);
|
|
||||||
}
|
}
|
||||||
cleanup_mg_backend_readmng_parse_main_page:
|
if (nodes) {
|
||||||
|
slides = nodes[0];
|
||||||
|
}
|
||||||
|
cleanup_mg_backend_readmng_retrieve_slides:
|
||||||
if (xpath_result) {
|
if (xpath_result) {
|
||||||
xmlXPathFreeObject (xpath_result);
|
xmlXPathFreeObject(xpath_result);
|
||||||
}
|
}
|
||||||
return mangas;
|
if (nodes) {
|
||||||
|
for (size_t i = 1; i < matching_classes_len; i++)
|
||||||
|
{
|
||||||
|
xmlFreeNode(nodes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (nodes);
|
||||||
|
}
|
||||||
|
return slides;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xmlNodePtr
|
||||||
|
mg_backend_readmng_retrieve_thumbnail_from_li (MgBackendReadmng *self, xmlNodePtr current_li) {
|
||||||
|
size_t thumbnail_len = 0;
|
||||||
|
MgUtilXML *xml_utils = self->xml_utils;
|
||||||
|
xmlNodePtr return_value = NULL;
|
||||||
|
xmlNodePtr *thumbnail = mg_util_xml_find_class (xml_utils, current_li, "thumbnail",
|
||||||
|
&thumbnail_len, NULL, 1);
|
||||||
|
if (!thumbnail_len) goto cleanup_mg_backend_retrieve_thumbnail_from_li;
|
||||||
|
return_value = thumbnail[0];
|
||||||
|
cleanup_mg_backend_retrieve_thumbnail_from_li:
|
||||||
|
if (thumbnail) {
|
||||||
|
g_free (thumbnail);
|
||||||
|
}
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xmlNodePtr
|
||||||
|
mg_backend_readmng_retrieve_title_from_li (MgBackendReadmng *self, xmlNodePtr li) {
|
||||||
|
size_t title_len = 0;
|
||||||
|
MgUtilXML *xml_utils = self->xml_utils;
|
||||||
|
xmlNodePtr return_value = NULL;
|
||||||
|
xmlNodePtr *title = mg_util_xml_find_class (xml_utils, li, "title", &title_len, NULL, 1);
|
||||||
|
if (title_len) {
|
||||||
|
return_value = title[0];
|
||||||
|
}
|
||||||
|
if (title) {
|
||||||
|
g_free (title);
|
||||||
|
}
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xmlNodePtr
|
||||||
|
mg_backend_readmng_find_a_link_chapter (MgBackendReadmng *self,
|
||||||
|
xmlNodePtr current_li) {
|
||||||
|
for (xmlNodePtr child = current_li->children; child; child = child->next) {
|
||||||
|
if (!strcmp((char *)child->name, "a")) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
mg_backend_readmng_get_id_manga_link (MgBackendReadmng *self, xmlNodePtr a) {
|
||||||
|
MgUtilXML *xml_utils = self->xml_utils;
|
||||||
|
char *href = mg_util_xml_get_attr (xml_utils, a, "href");
|
||||||
|
char *result = mg_backend_readmng_get_id_manga_link_from_string (self, href);
|
||||||
|
g_free (href);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
mg_backend_readmng_get_id_manga_link_from_string (MgBackendReadmng *self, const char *url) {
|
mg_backend_readmng_get_id_manga_link_from_string (MgBackendReadmng *self, const char *url) {
|
||||||
MgUtilRegex *regex_util = mg_util_regex_new ();
|
MgUtilRegex *regex_util = mg_util_regex_new ();
|
||||||
char *re_str = "/([^/]+)";
|
char *re_str = "readmng\\.com/([^/]+)";
|
||||||
char *result = mg_util_regex_match_1 (regex_util, re_str, url);
|
char *result = mg_util_regex_match_1 (regex_util, re_str, url);
|
||||||
g_clear_object (®ex_util);
|
g_clear_object (®ex_util);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mg_backend_readmng_extract_manga_info_from_current_li (MgBackendReadmng *self,
|
||||||
|
GListStore *mangas, xmlNodePtr current_li) {
|
||||||
|
|
||||||
|
xmlNodePtr thumbnail = mg_backend_readmng_retrieve_thumbnail_from_li (self, current_li);
|
||||||
|
xmlNodePtr title = mg_backend_readmng_retrieve_title_from_li (self, current_li);
|
||||||
|
xmlNodePtr a = mg_backend_readmng_find_a_link_chapter (self, current_li);
|
||||||
|
xmlNodePtr img;
|
||||||
|
MgUtilXML *xml_utils = self->xml_utils;
|
||||||
|
char *id_manga = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
if (thumbnail && title && (img = mg_backend_readmng_retrieve_img_from_thumbnail (self, thumbnail))
|
||||||
|
&& a && (id_manga = mg_backend_readmng_get_id_manga_link (self, a))) {
|
||||||
|
char *src = mg_util_xml_get_attr (xml_utils, img, "src");
|
||||||
|
char *title_string = (char *)xmlNodeGetContent (title);
|
||||||
|
g_list_store_append (mangas, mg_manga_new (src, title_string, id_manga));
|
||||||
|
|
||||||
|
g_free (src);
|
||||||
|
g_free (title_string);
|
||||||
|
pcre2_substring_free ((PCRE2_UCHAR8 *) id_manga);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static xmlNodePtr
|
||||||
|
mg_backend_readmng_retrieve_img_from_thumbnail (MgBackendReadmng *self, xmlNodePtr thumbnail) {
|
||||||
|
for (xmlNodePtr child = thumbnail->children; child; child=child->next) {
|
||||||
|
if (!strcmp((char *)child->name, "img")) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <glib/gprintf.h>
|
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
|
|
||||||
#include <openmg/util/string.h>
|
#include <openmg/util/string.h>
|
||||||
@ -47,11 +46,3 @@ mg_util_string_new () {
|
|||||||
self = MG_UTIL_STRING ((g_object_new (MG_TYPE_UTIL_STRING, NULL)));
|
self = MG_UTIL_STRING ((g_object_new (MG_TYPE_UTIL_STRING, NULL)));
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
int
|
|
||||||
g_asprintf (char **strp, const char *format, ...) {
|
|
||||||
va_list ap;
|
|
||||||
va_start (ap, format);
|
|
||||||
int retval = g_vasprintf (strp, format, ap);
|
|
||||||
va_end (ap);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
@ -143,14 +143,11 @@ mg_util_xml_loop_search_class (MgUtilXML *self, const xmlNodePtr node, xmlNodePt
|
|||||||
|
|
||||||
xmlXPathObjectPtr
|
xmlXPathObjectPtr
|
||||||
mg_util_xml_get_nodes_xpath_expression (MgUtilXML *self,
|
mg_util_xml_get_nodes_xpath_expression (MgUtilXML *self,
|
||||||
const xmlDocPtr document, const xmlNodePtr node, char *xpath) {
|
const xmlDocPtr document, char *xpath) {
|
||||||
xmlXPathContextPtr context;
|
xmlXPathContextPtr context;
|
||||||
xmlXPathObjectPtr result;
|
xmlXPathObjectPtr result;
|
||||||
|
|
||||||
context = xmlXPathNewContext (document);
|
context = xmlXPathNewContext (document);
|
||||||
if (node) {
|
|
||||||
context->node = node;
|
|
||||||
}
|
|
||||||
result = xmlXPathEvalExpression ((const xmlChar *)xpath, context);
|
result = xmlXPathEvalExpression ((const xmlChar *)xpath, context);
|
||||||
|
|
||||||
xmlXPathFreeContext (context);
|
xmlXPathFreeContext (context);
|
||||||
|
Loading…
Reference in New Issue
Block a user