forked from sergiotarxz/mangareader
Migrating into using GObject to the manga retrieval.
This commit is contained in:
parent
eb5b631d50
commit
0ac7affa93
2
Makefile
2
Makefile
|
@ -6,4 +6,4 @@ LDFLAGS := $(shell pkg-config --libs ${LIBS})
|
||||||
CC_COMMAND := ${CC} ${INCDIR} ${CFLAGS}
|
CC_COMMAND := ${CC} ${INCDIR} ${CFLAGS}
|
||||||
all: build
|
all: build
|
||||||
build:
|
build:
|
||||||
${CC_COMMAND} readmng.c manga.c main.c -o main ${LDFLAGS} -ggdb
|
${CC_COMMAND} src/manga.c src/backend/readmng.c manga.c main.c -o main ${LDFLAGS} -ggdb
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
#ifndef MANGA
|
#pragma once
|
||||||
#define MANGA
|
|
||||||
|
|
||||||
#include <libsoup/soup.h>
|
#include <libsoup/soup.h>
|
||||||
#include <libxml/HTMLparser.h>
|
#include <libxml/HTMLparser.h>
|
||||||
#include <libxml/xpath.h>
|
#include <libxml/xpath.h>
|
||||||
|
@ -59,4 +57,3 @@ loop_search_class (const xmlNodePtr node, xmlNodePtr *nodes,
|
||||||
const char * class, size_t *len);
|
const char * class, size_t *len);
|
||||||
char *
|
char *
|
||||||
copy_binary_data (const char *input, size_t size);
|
copy_binary_data (const char *input, size_t size);
|
||||||
#endif
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
#include <openmg/manga.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Type declaration
|
||||||
|
*/
|
||||||
|
#define MG_TYPE_BACKEND_READMNG mg_backend_readmng_get_type ()
|
||||||
|
G_DECLARE_FINAL_TYPE (MgBackendReadmng, mg_backend_readmng, MG, BACKEND_READMNG, GObject)
|
||||||
|
|
||||||
|
void
|
||||||
|
mg_backend_readmng_set_property (GObject *object, guint property_id,
|
||||||
|
const GValue *value, GParamSpec *pspec);
|
||||||
|
void
|
||||||
|
mg_backend_readmng_get_property (GObject *object, guint property_id,
|
||||||
|
GValue *value, GParamSpec *pspec);
|
||||||
|
/*
|
||||||
|
* Method definitions.
|
||||||
|
*/
|
||||||
|
MgBackendReadmng *
|
||||||
|
mg_backend_readmng_new (void);
|
||||||
|
|
||||||
|
MgManga **
|
||||||
|
mg_backend_readmng_get_featured_manga (MgBackendReadmng *self, size_t *len);
|
||||||
|
|
||||||
|
G_END_DECLS
|
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Type declaration
|
||||||
|
*/
|
||||||
|
#define MG_TYPE_MANGA mg_manga_get_type()
|
||||||
|
G_DECLARE_FINAL_TYPE (MgManga, mg_manga, MG, MANGA, GObject)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Method definitions.
|
||||||
|
*/
|
||||||
|
char *mg_manga_get_image_url(MgManga *mg_manga);
|
||||||
|
char *mg_manga_get_title(MgManga *mg_manga);
|
||||||
|
|
||||||
|
MgManga *mg_manga_new (const char *const image_url, const char *const title);
|
||||||
|
|
||||||
|
G_END_DECLS
|
60
main.c
60
main.c
|
@ -1,6 +1,9 @@
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <adwaita.h>
|
#include <adwaita.h>
|
||||||
|
|
||||||
|
#include <openmg/backend/readmng.h>
|
||||||
|
#include <openmg/manga.h>
|
||||||
|
|
||||||
#include <readmng.h>
|
#include <readmng.h>
|
||||||
#include <manga.h>
|
#include <manga.h>
|
||||||
|
|
||||||
|
@ -10,11 +13,13 @@ GtkBox *
|
||||||
create_main_box (AdwApplicationWindow *window);
|
create_main_box (AdwApplicationWindow *window);
|
||||||
GtkBox *
|
GtkBox *
|
||||||
create_manga_container ();
|
create_manga_container ();
|
||||||
AdwCarousel *
|
GtkListBox *
|
||||||
create_adw_caroulsel (GtkBox *box);
|
create_list_box (GtkBox *box);
|
||||||
|
void
|
||||||
|
g_object_set_property_int(GObject *object, char *property_key, int value);
|
||||||
|
|
||||||
void
|
void
|
||||||
fill_carousel_of_mangas (AdwCarousel *carousel);
|
fill_list_of_mangas (GtkListBox *list);
|
||||||
|
|
||||||
void
|
void
|
||||||
activate (AdwApplication *app,
|
activate (AdwApplication *app,
|
||||||
|
@ -25,23 +30,26 @@ activate (AdwApplication *app,
|
||||||
GtkBox *box = create_main_box(
|
GtkBox *box = create_main_box(
|
||||||
ADW_APPLICATION_WINDOW
|
ADW_APPLICATION_WINDOW
|
||||||
(window));
|
(window));
|
||||||
AdwCarousel *carousel;
|
GtkListBox *list;
|
||||||
create_headerbar (box);
|
create_headerbar (box);
|
||||||
|
|
||||||
carousel = create_adw_caroulsel (box);
|
list = create_list_box (box);
|
||||||
fill_carousel_of_mangas (carousel);
|
gtk_widget_set_vexpand (GTK_WIDGET (list), 1);
|
||||||
|
fill_list_of_mangas (list);
|
||||||
|
|
||||||
gtk_widget_show (window);
|
gtk_widget_show (window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fill_carousel_of_mangas (AdwCarousel *carousel) {
|
fill_list_of_mangas (GtkListBox *list) {
|
||||||
struct Manga *mangas;
|
MgManga **mangas;
|
||||||
struct Manga *manga;
|
MgManga *manga;
|
||||||
GtkBox *manga_container;
|
GtkWidget *row;
|
||||||
size_t len_mangas = 0;
|
size_t len_mangas = 0;
|
||||||
|
|
||||||
mangas = retrieve_readmng_title_mangas (&len_mangas);
|
|
||||||
|
MgBackendReadmng *readmng = mg_backend_readmng_new ();
|
||||||
|
mangas = mg_backend_readmng_get_featured_manga (readmng, &len_mangas);
|
||||||
for (int i = 0; i<len_mangas; i++) {
|
for (int i = 0; i<len_mangas; i++) {
|
||||||
GtkWidget *picture;
|
GtkWidget *picture;
|
||||||
GFileIOStream *iostream;
|
GFileIOStream *iostream;
|
||||||
|
@ -51,10 +59,9 @@ fill_carousel_of_mangas (AdwCarousel *carousel) {
|
||||||
size_t size_downloaded_image = 0;
|
size_t size_downloaded_image = 0;
|
||||||
char *downloaded_image;
|
char *downloaded_image;
|
||||||
|
|
||||||
manga = &mangas[i];
|
manga = mangas[i];
|
||||||
manga_container = create_manga_container (manga);
|
|
||||||
adw_carousel_append (carousel, GTK_WIDGET (manga_container));
|
downloaded_image = get_request (mg_manga_get_image_url(manga), &size_downloaded_image);
|
||||||
downloaded_image = get_request (manga->image_url, &size_downloaded_image);
|
|
||||||
tmp_image = g_file_new_tmp ("mangareadertmpfileXXXXXX",
|
tmp_image = g_file_new_tmp ("mangareadertmpfileXXXXXX",
|
||||||
&iostream,
|
&iostream,
|
||||||
&error
|
&error
|
||||||
|
@ -71,10 +78,21 @@ fill_carousel_of_mangas (AdwCarousel *carousel) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
picture = gtk_picture_new_for_file (tmp_image);
|
picture = gtk_picture_new_for_file (tmp_image);
|
||||||
gtk_box_append (manga_container, picture);
|
g_object_set_property_int (G_OBJECT(picture), "height-request", 200);
|
||||||
|
row = gtk_list_box_row_new ();
|
||||||
|
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), picture);
|
||||||
|
gtk_list_box_append (list, row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
g_object_set_property_int(GObject *object, char *property_key, int value) {
|
||||||
|
GValue property = G_VALUE_INIT;
|
||||||
|
g_value_init (&property, G_TYPE_INT);
|
||||||
|
g_value_set_int (&property, value);
|
||||||
|
g_object_set_property (object, property_key, &property);
|
||||||
|
}
|
||||||
|
|
||||||
GtkBox *
|
GtkBox *
|
||||||
create_manga_container () {
|
create_manga_container () {
|
||||||
GtkBox *manga_container;
|
GtkBox *manga_container;
|
||||||
|
@ -95,11 +113,11 @@ create_main_box (AdwApplicationWindow *window) {
|
||||||
return GTK_BOX (box);
|
return GTK_BOX (box);
|
||||||
}
|
}
|
||||||
|
|
||||||
AdwCarousel *
|
GtkListBox *
|
||||||
create_adw_caroulsel (GtkBox *box) {
|
create_list_box (GtkBox *box) {
|
||||||
GtkWidget *carousel = adw_carousel_new ();
|
GtkWidget *list = gtk_list_box_new ();
|
||||||
gtk_box_append (box, carousel);
|
gtk_box_append (box, list);
|
||||||
return ADW_CAROUSEL (carousel);
|
return GTK_LIST_BOX (list);
|
||||||
}
|
}
|
||||||
|
|
||||||
AdwHeaderBar *
|
AdwHeaderBar *
|
||||||
|
|
153
readmng.c
153
readmng.c
|
@ -1,153 +0,0 @@
|
||||||
#include <manga.h>
|
|
||||||
#include <libxml/HTMLparser.h>
|
|
||||||
|
|
||||||
const char *readmng_url = "https://www.readmng.com/";
|
|
||||||
|
|
||||||
struct Manga *
|
|
||||||
parse_readmng_title_page (const xmlDocPtr html_document,
|
|
||||||
size_t *const len);
|
|
||||||
xmlNodePtr
|
|
||||||
retrieve_slides (const xmlDocPtr html_document);
|
|
||||||
xmlNodePtr
|
|
||||||
retrieve_ul_slides (xmlNodePtr const slides);
|
|
||||||
xmlNodePtr *
|
|
||||||
retrieve_li_slides (xmlNodePtr const slides, size_t *li_len);
|
|
||||||
xmlNodePtr
|
|
||||||
retrieve_img_from_thumnail (xmlNodePtr thumbnail);
|
|
||||||
xmlNodePtr
|
|
||||||
retrieve_thumbnail_from_li (xmlNodePtr current_li);
|
|
||||||
xmlNodePtr
|
|
||||||
retrieve_title_from_li (xmlNodePtr li);
|
|
||||||
struct Manga *
|
|
||||||
extract_manga_info_from_current_li (struct Manga *mangas,
|
|
||||||
xmlNodePtr current_li, size_t *len);
|
|
||||||
|
|
||||||
struct Manga *
|
|
||||||
retrieve_readmng_title_mangas (size_t *const len) {
|
|
||||||
xmlDocPtr html_response;
|
|
||||||
gsize size_response_text;
|
|
||||||
struct Manga *mangas;
|
|
||||||
char *response_text = get_request (readmng_url,
|
|
||||||
&size_response_text);
|
|
||||||
html_response = htmlReadMemory (response_text,
|
|
||||||
size_response_text,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
HTML_PARSE_RECOVER | HTML_PARSE_NODEFDTD
|
|
||||||
| HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING
|
|
||||||
);
|
|
||||||
mangas = parse_readmng_title_page (html_response, len);
|
|
||||||
xmlFreeDoc (html_response);
|
|
||||||
g_free (response_text);
|
|
||||||
return mangas;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Manga *
|
|
||||||
parse_readmng_title_page (const xmlDocPtr html_document,
|
|
||||||
size_t *const len) {
|
|
||||||
struct Manga *mangas = NULL;
|
|
||||||
xmlNodePtr slides = retrieve_slides (html_document);
|
|
||||||
*len = 0;
|
|
||||||
size_t li_len = 0;
|
|
||||||
xmlNodePtr *li = retrieve_li_slides (slides, &li_len);
|
|
||||||
for (int i = 0; i<li_len; i++) {
|
|
||||||
xmlNodePtr current_li = li[i];
|
|
||||||
mangas = extract_manga_info_from_current_li (mangas, current_li,
|
|
||||||
len);
|
|
||||||
}
|
|
||||||
return mangas;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Manga *
|
|
||||||
extract_manga_info_from_current_li (struct Manga *mangas, xmlNodePtr current_li,
|
|
||||||
size_t *len) {
|
|
||||||
xmlNodePtr thumbnail = retrieve_thumbnail_from_li (current_li);
|
|
||||||
xmlNodePtr title = retrieve_title_from_li (current_li);
|
|
||||||
xmlNodePtr img;
|
|
||||||
|
|
||||||
if (thumbnail && title && (img = retrieve_img_from_thumnail (thumbnail))) {
|
|
||||||
(*len)++;
|
|
||||||
mangas = g_realloc(mangas, sizeof *mangas * *len);
|
|
||||||
struct Manga *manga = &mangas[*len-1];
|
|
||||||
manga->image_url = get_attr (img, "src");
|
|
||||||
manga->title = (char *) xmlNodeGetContent (title);
|
|
||||||
}
|
|
||||||
return mangas;
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlNodePtr
|
|
||||||
retrieve_title_from_li (xmlNodePtr li) {
|
|
||||||
size_t title_len = 0;
|
|
||||||
xmlNodePtr *title = find_class (li, "title", &title_len, NULL, 1);
|
|
||||||
if (title_len) return title[0];
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlNodePtr
|
|
||||||
retrieve_img_from_thumnail (xmlNodePtr thumbnail) {
|
|
||||||
for (xmlNodePtr child = thumbnail->children; child; child=child->next) {
|
|
||||||
if (!strcmp((char *)child->name, "img")) {
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlNodePtr
|
|
||||||
retrieve_thumbnail_from_li (xmlNodePtr current_li) {
|
|
||||||
size_t thumbnail_len = 0;
|
|
||||||
xmlNodePtr *thumbnail = find_class (current_li, "thumbnail",
|
|
||||||
&thumbnail_len, NULL, 1);
|
|
||||||
if (thumbnail_len) return thumbnail[0];
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlNodePtr *
|
|
||||||
retrieve_li_slides (xmlNodePtr const slides, size_t *li_len) {
|
|
||||||
xmlNodePtr ul_slides = retrieve_ul_slides (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;
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlNodePtr
|
|
||||||
retrieve_ul_slides (xmlNodePtr const slides) {
|
|
||||||
for (xmlNodePtr child = slides->children; child; child = child->next) {
|
|
||||||
if (!strcmp((char *) child->name, "ul")) {
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlNodePtr
|
|
||||||
retrieve_slides (const xmlDocPtr html_document) {
|
|
||||||
xmlNodePtr *nodes = NULL;
|
|
||||||
xmlXPathObjectPtr xpath_result = NULL;
|
|
||||||
xpath_result = get_nodes_xpath_expression (html_document,
|
|
||||||
"//div[@class]");
|
|
||||||
xmlNodePtr slides = NULL;
|
|
||||||
xmlNodeSetPtr node_set = NULL;
|
|
||||||
size_t matching_classes_len = 0;
|
|
||||||
|
|
||||||
node_set = xpath_result->nodesetval;
|
|
||||||
if (!node_set) {
|
|
||||||
fprintf(stderr, "No match\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < node_set->nodeNr; i++) {
|
|
||||||
xmlNodePtr node = node_set->nodeTab[i];
|
|
||||||
nodes = loop_search_class (node, nodes, "slides", &matching_classes_len);
|
|
||||||
}
|
|
||||||
if (nodes) {
|
|
||||||
slides = nodes[0];
|
|
||||||
}
|
|
||||||
if (xpath_result) {
|
|
||||||
xmlXPathFreeObject(xpath_result);
|
|
||||||
}
|
|
||||||
return slides;
|
|
||||||
}
|
|
|
@ -0,0 +1,253 @@
|
||||||
|
#include <libxml/HTMLparser.h>
|
||||||
|
|
||||||
|
#include <openmg/backend/readmng.h>
|
||||||
|
#include <openmg/manga.h>
|
||||||
|
|
||||||
|
#include <manga.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MG_BACKEND_READMNG_BASE_URL = 1,
|
||||||
|
MG_BACKEND_READMNG_N_PROPERTIES
|
||||||
|
} MgBackendReadmngProperties;
|
||||||
|
|
||||||
|
struct _MgBackendReadmng {
|
||||||
|
GObject parent_instance;
|
||||||
|
char *base_url;
|
||||||
|
size_t main_page_html_len;
|
||||||
|
char *main_page_html;
|
||||||
|
MgManga *(*get_featured_manga) ();
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (MgBackendReadmng, mg_backend_readmng, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
static GParamSpec *mg_backend_readmng_properties[MG_BACKEND_READMNG_N_PROPERTIES] = { NULL, };
|
||||||
|
|
||||||
|
static void
|
||||||
|
mg_backend_readmng_class_init (MgBackendReadmngClass *class) {
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||||
|
object_class->set_property = mg_backend_readmng_set_property;
|
||||||
|
object_class->get_property = mg_backend_readmng_get_property;
|
||||||
|
|
||||||
|
mg_backend_readmng_properties[MG_BACKEND_READMNG_BASE_URL] = g_param_spec_string ("base_url",
|
||||||
|
"BaseURL",
|
||||||
|
"Url of the backend.",
|
||||||
|
NULL,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
|
||||||
|
g_object_class_install_properties (object_class,
|
||||||
|
MG_BACKEND_READMNG_N_PROPERTIES,
|
||||||
|
mg_backend_readmng_properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 MgManga **
|
||||||
|
mg_backend_readmng_extract_manga_info_from_current_li (MgBackendReadmng *self,
|
||||||
|
MgManga **mangas, xmlNodePtr current_li, size_t *len);
|
||||||
|
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 *
|
||||||
|
mg_backend_readmng_get_main_page (MgBackendReadmng *self, size_t *len);
|
||||||
|
static MgManga **
|
||||||
|
mg_backend_readmng_parse_main_page (MgBackendReadmng *self, size_t *len, const xmlDocPtr html_document);
|
||||||
|
static xmlDocPtr
|
||||||
|
mg_backend_readmng_fetch_xml_main_page (MgBackendReadmng *self);
|
||||||
|
|
||||||
|
MgBackendReadmng *
|
||||||
|
mg_backend_readmng_new(void) {
|
||||||
|
return (MG_BACKEND_READMNG) (g_object_new (MG_TYPE_BACKEND_READMNG, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mg_backend_readmng_init (MgBackendReadmng *self) {
|
||||||
|
if (!self->base_url) {
|
||||||
|
self->base_url = "https://www.readmng.com/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
mg_backend_readmng_get_base_url (MgBackendReadmng *self) {
|
||||||
|
return self->base_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mg_backend_readmng_set_property (GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec) {
|
||||||
|
MgBackendReadmng *self = MG_BACKEND_READMNG (object);
|
||||||
|
switch ((MgBackendReadmngProperties) property_id) {
|
||||||
|
case MG_BACKEND_READMNG_BASE_URL:
|
||||||
|
g_free (self->base_url);
|
||||||
|
self->base_url = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mg_backend_readmng_get_property (GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec) {
|
||||||
|
MgBackendReadmng *self = MG_BACKEND_READMNG (object);
|
||||||
|
switch ((MgBackendReadmngProperties) property_id) {
|
||||||
|
case MG_BACKEND_READMNG_BASE_URL:
|
||||||
|
g_value_set_string (value, self->base_url);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MgManga **
|
||||||
|
mg_backend_readmng_get_featured_manga (MgBackendReadmng *self, size_t *len) {
|
||||||
|
MgManga **mangas;
|
||||||
|
xmlDocPtr html_document;
|
||||||
|
html_document = mg_backend_readmng_fetch_xml_main_page (self);
|
||||||
|
mangas = mg_backend_readmng_parse_main_page (self, len, html_document);
|
||||||
|
return mangas;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static xmlDocPtr
|
||||||
|
mg_backend_readmng_fetch_xml_main_page (MgBackendReadmng *self) {
|
||||||
|
size_t size_response_text = 0;
|
||||||
|
return htmlReadMemory (mg_backend_readmng_get_main_page (self, &size_response_text),
|
||||||
|
size_response_text,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
HTML_PARSE_RECOVER | HTML_PARSE_NODEFDTD
|
||||||
|
| HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
mg_backend_readmng_get_main_page (MgBackendReadmng *self, size_t *len) {
|
||||||
|
if (!self->main_page_html) {
|
||||||
|
self->main_page_html = get_request (self->base_url,
|
||||||
|
&self->main_page_html_len);
|
||||||
|
}
|
||||||
|
if (len) {
|
||||||
|
*len = self->main_page_html_len;
|
||||||
|
}
|
||||||
|
return self->main_page_html;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MgManga **
|
||||||
|
mg_backend_readmng_parse_main_page (MgBackendReadmng *self, size_t *len, const xmlDocPtr html_document) {
|
||||||
|
MgManga **mangas = NULL;
|
||||||
|
xmlNodePtr *li;
|
||||||
|
|
||||||
|
*len = 0;
|
||||||
|
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];
|
||||||
|
mangas = mg_backend_readmng_extract_manga_info_from_current_li (self, mangas, current_li,
|
||||||
|
len);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
xpath_result = get_nodes_xpath_expression (html_document,
|
||||||
|
"//div[@class]");
|
||||||
|
xmlNodePtr slides = NULL;
|
||||||
|
xmlNodeSetPtr node_set = NULL;
|
||||||
|
size_t matching_classes_len = 0;
|
||||||
|
|
||||||
|
node_set = xpath_result->nodesetval;
|
||||||
|
if (!node_set) {
|
||||||
|
fprintf(stderr, "No match\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < node_set->nodeNr; i++) {
|
||||||
|
xmlNodePtr node = node_set->nodeTab[i];
|
||||||
|
nodes = loop_search_class (node, nodes, "slides", &matching_classes_len);
|
||||||
|
}
|
||||||
|
if (nodes) {
|
||||||
|
slides = nodes[0];
|
||||||
|
}
|
||||||
|
if (xpath_result) {
|
||||||
|
xmlXPathFreeObject(xpath_result);
|
||||||
|
}
|
||||||
|
return slides;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xmlNodePtr
|
||||||
|
mg_backend_readmng_retrieve_thumbnail_from_li (MgBackendReadmng *self, xmlNodePtr current_li) {
|
||||||
|
size_t thumbnail_len = 0;
|
||||||
|
xmlNodePtr *thumbnail = find_class (current_li, "thumbnail",
|
||||||
|
&thumbnail_len, NULL, 1);
|
||||||
|
if (thumbnail_len) return thumbnail[0];
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xmlNodePtr
|
||||||
|
mg_backend_readmng_retrieve_title_from_li (MgBackendReadmng *self, xmlNodePtr li) {
|
||||||
|
size_t title_len = 0;
|
||||||
|
xmlNodePtr *title = find_class (li, "title", &title_len, NULL, 1);
|
||||||
|
if (title_len) return title[0];
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MgManga **
|
||||||
|
mg_backend_readmng_extract_manga_info_from_current_li (MgBackendReadmng *self,
|
||||||
|
MgManga **mangas, xmlNodePtr current_li, size_t *len) {
|
||||||
|
|
||||||
|
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 img;
|
||||||
|
|
||||||
|
if (thumbnail && title && (img = mg_backend_readmng_retrieve_img_from_thumbnail (self, thumbnail))) {
|
||||||
|
(*len)++;
|
||||||
|
mangas = g_realloc(mangas, sizeof *mangas * *len);
|
||||||
|
mangas[*len-1] = mg_manga_new (get_attr (img, "src"), (char *)xmlNodeGetContent (title));
|
||||||
|
}
|
||||||
|
return mangas;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
#include <manga.h>
|
||||||
|
#include <openmg/manga.h>
|
||||||
|
|
||||||
|
struct _MgManga {
|
||||||
|
GObject parent_instance;
|
||||||
|
char *image_url;
|
||||||
|
char *title;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (MgManga, mg_manga, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MG_MANGA_IMAGE_URL = 1,
|
||||||
|
MG_MANGA_TITLE,
|
||||||
|
MG_MANGA_N_PROPERTIES
|
||||||
|
} MgMangaProperties;
|
||||||
|
|
||||||
|
static GParamSpec *manga_properties[MG_MANGA_N_PROPERTIES] = { NULL, };
|
||||||
|
|
||||||
|
static void
|
||||||
|
mg_manga_set_property (GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec);
|
||||||
|
static void
|
||||||
|
mg_manga_get_property (GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec);
|
||||||
|
|
||||||
|
static void
|
||||||
|
mg_manga_class_init (MgMangaClass *class) {
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||||
|
object_class->set_property = mg_manga_set_property;
|
||||||
|
object_class->get_property = mg_manga_get_property;
|
||||||
|
|
||||||
|
manga_properties[MG_MANGA_IMAGE_URL] = g_param_spec_string ("image_url",
|
||||||
|
"ImageURL",
|
||||||
|
"Url of the image.",
|
||||||
|
NULL,
|
||||||
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
||||||
|
manga_properties[MG_MANGA_TITLE] = g_param_spec_string ("title",
|
||||||
|
"Title",
|
||||||
|
"Title of the manga.",
|
||||||
|
NULL,
|
||||||
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
||||||
|
|
||||||
|
g_object_class_install_properties (object_class,
|
||||||
|
MG_MANGA_N_PROPERTIES,
|
||||||
|
manga_properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mg_manga_init (MgManga *self) {
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
mg_manga_get_image_url(MgManga *self) {
|
||||||
|
GValue value = G_VALUE_INIT;
|
||||||
|
g_value_init (&value, G_TYPE_STRING);
|
||||||
|
g_object_get_property (G_OBJECT (self),
|
||||||
|
"image_url",
|
||||||
|
&value);
|
||||||
|
return g_value_dup_string (&value);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
mg_manga_get_title(MgManga *self) {
|
||||||
|
GValue value = G_VALUE_INIT;
|
||||||
|
g_value_init (&value, G_TYPE_STRING);
|
||||||
|
g_object_get_property (G_OBJECT (self),
|
||||||
|
"title",
|
||||||
|
&value);
|
||||||
|
return g_value_dup_string (&value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mg_manga_set_property (GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec) {
|
||||||
|
MgManga *self = MG_MANGA (object);
|
||||||
|
switch ((MgMangaProperties) property_id) {
|
||||||
|
case MG_MANGA_IMAGE_URL:
|
||||||
|
g_free (self->image_url);
|
||||||
|
self->image_url = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
case MG_MANGA_TITLE:
|
||||||
|
g_free (self->title);
|
||||||
|
self->title = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mg_manga_get_property (GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec) {
|
||||||
|
MgManga *self = MG_MANGA (object);
|
||||||
|
switch ((MgMangaProperties) property_id) {
|
||||||
|
case MG_MANGA_IMAGE_URL:
|
||||||
|
g_value_set_string (value, self->image_url);
|
||||||
|
break;
|
||||||
|
case MG_MANGA_TITLE:
|
||||||
|
g_value_set_string (value, self->title);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MgManga *
|
||||||
|
mg_manga_new (const char *const image_url, const char *const title) {
|
||||||
|
MgManga *self = NULL;
|
||||||
|
self = (MG_MANGA) (g_object_new (MG_TYPE_MANGA, NULL));
|
||||||
|
self->image_url = alloc_string (strlen (image_url));
|
||||||
|
self->title = alloc_string (strlen (title));
|
||||||
|
copy_substring (image_url, self->image_url, strlen(image_url) + 1, 0, strlen (image_url));
|
||||||
|
copy_substring (title, self->title, strlen(title) + 1, 0, strlen (title));
|
||||||
|
return self;
|
||||||
|
}
|
Loading…
Reference in New Issue