forked from sergiotarxz/mangareader
Adding image cache.
This commit is contained in:
parent
0b3c459482
commit
3050ac8230
@ -16,7 +16,7 @@ mg_database_prepare (MgDatabase *self, char *z_sql, const char **pz_tail);
|
|||||||
int
|
int
|
||||||
mg_database_get_affected_rows (MgDatabase *self);
|
mg_database_get_affected_rows (MgDatabase *self);
|
||||||
|
|
||||||
char *
|
const char *
|
||||||
mg_database_get_error_string (MgDatabase *self);
|
mg_database_get_error_string (MgDatabase *self);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@ -3,7 +3,7 @@ const char *const MIGRATIONS[] = {
|
|||||||
"key TEXT PRIMARY KEY,\n"
|
"key TEXT PRIMARY KEY,\n"
|
||||||
"value TEXT\n"
|
"value TEXT\n"
|
||||||
");\n"),
|
");\n"),
|
||||||
("CREATE TABLE image (\n"
|
("CREATE TABLE images (\n"
|
||||||
"url TEXT PRIMARY KEY,\n"
|
"url TEXT PRIMARY KEY,\n"
|
||||||
"file TEXT\n"
|
"file TEXT\n"
|
||||||
");\n"),
|
");\n"),
|
||||||
|
@ -8,8 +8,19 @@ G_DECLARE_FINAL_TYPE (MgDatabaseStatement, mg_database_statement, MG, DATABASE_S
|
|||||||
|
|
||||||
MgDatabaseStatement *mg_database_statement_new ();
|
MgDatabaseStatement *mg_database_statement_new ();
|
||||||
|
|
||||||
void
|
int
|
||||||
mg_database_statement_bind_text (MgDatabaseStatement *self, int index, char *value);
|
mg_database_statement_bind_text (MgDatabaseStatement *self,
|
||||||
|
int index, const char *value);
|
||||||
|
int
|
||||||
|
mg_database_statement_step (MgDatabaseStatement *self);
|
||||||
|
|
||||||
|
const unsigned char *
|
||||||
|
mg_database_statement_column_text (MgDatabaseStatement *self,
|
||||||
|
int i_col);
|
||||||
|
|
||||||
|
int
|
||||||
|
mg_database_statement_column_int (MgDatabaseStatement *self,
|
||||||
|
int i_col);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ struct _MgDatabaseStatement {
|
|||||||
G_DEFINE_TYPE (MgDatabaseStatement, mg_database_statement, G_TYPE_OBJECT)
|
G_DEFINE_TYPE (MgDatabaseStatement, mg_database_statement, G_TYPE_OBJECT)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MG_DATABASE_STATEMENT_OWNER,
|
MG_DATABASE_STATEMENT_OWNER = 1,
|
||||||
MG_DATABASE_STATEMENT_STMT,
|
MG_DATABASE_STATEMENT_STMT,
|
||||||
MG_DATABASE_STATEMENT_N_PROPERTIES
|
MG_DATABASE_STATEMENT_N_PROPERTIES
|
||||||
} MgDatabaseStatementProperties;
|
} MgDatabaseStatementProperties;
|
||||||
@ -38,7 +38,7 @@ MgDatabaseStatement *
|
|||||||
mg_database_statement_new (MgDatabase *owner, sqlite3_stmt *statement) {
|
mg_database_statement_new (MgDatabase *owner, sqlite3_stmt *statement) {
|
||||||
MgDatabaseStatement *self = NULL;
|
MgDatabaseStatement *self = NULL;
|
||||||
self = MG_DATABASE_STATEMENT ((g_object_new (MG_TYPE_DATABASE_STATEMENT,
|
self = MG_DATABASE_STATEMENT ((g_object_new (MG_TYPE_DATABASE_STATEMENT,
|
||||||
"owner", owner, "stmt", statement)));
|
"owner", owner, "stmt", statement, NULL)));
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ mg_database_statement_class_init (MgDatabaseStatementClass *class) {
|
|||||||
"owner",
|
"owner",
|
||||||
"Owner",
|
"Owner",
|
||||||
"Owner MgDatabase.",
|
"Owner MgDatabase.",
|
||||||
MG_TYPE_DATABASE_STATEMENT,
|
MG_TYPE_DATABASE,
|
||||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
||||||
database_statement_properties[MG_DATABASE_STATEMENT_STMT] = g_param_spec_pointer (
|
database_statement_properties[MG_DATABASE_STATEMENT_STMT] = g_param_spec_pointer (
|
||||||
"stmt",
|
"stmt",
|
||||||
@ -95,6 +95,7 @@ mg_database_statement_set_property (GObject *object,
|
|||||||
g_clear_object (&(self->owner));
|
g_clear_object (&(self->owner));
|
||||||
}
|
}
|
||||||
self->owner = g_value_peek_pointer (value);
|
self->owner = g_value_peek_pointer (value);
|
||||||
|
g_object_ref (self->owner);
|
||||||
break;
|
break;
|
||||||
case MG_DATABASE_STATEMENT_STMT:
|
case MG_DATABASE_STATEMENT_STMT:
|
||||||
if (self->stmt) {
|
if (self->stmt) {
|
||||||
@ -124,17 +125,47 @@ mg_database_statement_get_stmt (MgDatabaseStatement *self) {
|
|||||||
static void
|
static void
|
||||||
mg_database_statement_dispose (GObject *object) {
|
mg_database_statement_dispose (GObject *object) {
|
||||||
MgDatabaseStatement *self = MG_DATABASE_STATEMENT (object);
|
MgDatabaseStatement *self = MG_DATABASE_STATEMENT (object);
|
||||||
g_clear_object (&(self->owner));
|
if (self->owner) {
|
||||||
|
g_clear_object (&(self->owner));
|
||||||
|
}
|
||||||
sqlite3_finalize (self->stmt);
|
sqlite3_finalize (self->stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
mg_database_statement_bind_text (MgDatabaseStatement *self, int index, char *value) {
|
mg_database_statement_bind_text (MgDatabaseStatement *self,
|
||||||
|
int index, const char *value) {
|
||||||
sqlite3_stmt *stmt = mg_database_statement_get_stmt (self);
|
sqlite3_stmt *stmt = mg_database_statement_get_stmt (self);
|
||||||
int error = sqlite3_bind_text (stmt, index, value, -1, SQLITE_TRANSIENT);
|
int error = sqlite3_bind_text (stmt, index, value, -1, SQLITE_TRANSIENT);
|
||||||
if ( error != SQLITE_OK ) {
|
if ( error != SQLITE_OK ) {
|
||||||
g_error (mg_database_get_error_string (self->owner));
|
g_error (mg_database_get_error_string (self->owner));
|
||||||
}
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mg_database_statement_step (MgDatabaseStatement *self) {
|
||||||
|
sqlite3_stmt *stmt = mg_database_statement_get_stmt (self);
|
||||||
|
int error;
|
||||||
|
while ((error = sqlite3_step (stmt)) == SQLITE_BUSY) {
|
||||||
|
}
|
||||||
|
if (error != SQLITE_DONE && error != SQLITE_ROW) {
|
||||||
|
g_error (mg_database_get_error_string (self->owner));
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned char *
|
||||||
|
mg_database_statement_column_text (MgDatabaseStatement *self,
|
||||||
|
int i_col) {
|
||||||
|
sqlite3_stmt *stmt = mg_database_statement_get_stmt (self);
|
||||||
|
return sqlite3_column_text (stmt, i_col);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mg_database_statement_column_int (MgDatabaseStatement *self,
|
||||||
|
int i_col) {
|
||||||
|
sqlite3_stmt *stmt = mg_database_statement_get_stmt (self);
|
||||||
|
return sqlite3_column_int (stmt, i_col);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1,38 +1,57 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
#include <openmg/util/soup.h>
|
#include <openmg/util/soup.h>
|
||||||
#include <openmg/util/gobject_utility_extensions.h>
|
#include <openmg/util/gobject_utility_extensions.h>
|
||||||
|
|
||||||
|
#include <openmg/database.h>
|
||||||
|
#include <openmg/database/statement.h>
|
||||||
|
|
||||||
|
const char *const IMAGE_CACHE_FORMAT_STRING =
|
||||||
|
"%s/.cache/openmg/%s";
|
||||||
|
|
||||||
|
static char *
|
||||||
|
generate_cache_file_name (void);
|
||||||
|
GFile *
|
||||||
|
get_image_for_url (const char *url);
|
||||||
|
|
||||||
GtkPicture *
|
GtkPicture *
|
||||||
create_picture_from_url (const char *const url, gint picture_size) {
|
create_picture_from_url (const char *const url, gint picture_size) {
|
||||||
GtkPicture *picture = NULL;
|
GtkPicture *picture = NULL;
|
||||||
GFileIOStream *iostream;
|
GFileIOStream *iostream = NULL;
|
||||||
GFile *tmp_image;
|
GFile *image = NULL;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GdkTexture *texture;
|
GdkTexture *texture = NULL;
|
||||||
|
|
||||||
size_t size_downloaded_image = 0;
|
size_t size_downloaded_image = 0;
|
||||||
char *downloaded_image;
|
char *downloaded_image = NULL;
|
||||||
|
|
||||||
MgUtilSoup *util_soup = mg_util_soup_new ();
|
MgUtilSoup *util_soup = mg_util_soup_new ();
|
||||||
downloaded_image = mg_util_soup_get_request (util_soup,
|
image = get_image_for_url (url);
|
||||||
url, &size_downloaded_image);
|
if (!g_file_query_exists (image, NULL)) {
|
||||||
tmp_image = g_file_new_tmp ("mangareadertmpfileXXXXXX", &iostream, &error);
|
downloaded_image =
|
||||||
if (error) {
|
mg_util_soup_get_request
|
||||||
fprintf (stderr, "Unable to read file: %s\n", error->message);
|
(util_soup,
|
||||||
g_clear_error (&error);
|
url, &size_downloaded_image);
|
||||||
goto cleanup_create_picture_from_url;
|
iostream = g_file_create_readwrite (image, G_FILE_CREATE_NONE,
|
||||||
|
NULL, &error);
|
||||||
|
if (error) {
|
||||||
|
fprintf (stderr, "Unable to read file: %s\n", error->message);
|
||||||
|
g_clear_error (&error);
|
||||||
|
goto cleanup_create_picture_from_url;
|
||||||
|
}
|
||||||
|
g_output_stream_write (g_io_stream_get_output_stream (G_IO_STREAM (iostream)),
|
||||||
|
downloaded_image, size_downloaded_image, NULL, &error);
|
||||||
|
if (error) {
|
||||||
|
fprintf (stderr, "Unable to write file: %s\n", error->message);
|
||||||
|
g_clear_error (&error);
|
||||||
|
goto cleanup_create_picture_from_url;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g_output_stream_write (g_io_stream_get_output_stream (G_IO_STREAM (iostream)),
|
texture = gdk_texture_new_from_file (image, &error);
|
||||||
downloaded_image, size_downloaded_image, NULL, &error);
|
|
||||||
if (error) {
|
|
||||||
fprintf (stderr, "Unable to write file: %s\n", error->message);
|
|
||||||
g_clear_error (&error);
|
|
||||||
goto cleanup_create_picture_from_url;
|
|
||||||
}
|
|
||||||
texture = gdk_texture_new_from_file (tmp_image, &error);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
fprintf (stderr, "Texture malformed.");
|
fprintf (stderr, "Texture malformed.");
|
||||||
goto cleanup_create_picture_from_url;
|
goto cleanup_create_picture_from_url;
|
||||||
@ -42,9 +61,67 @@ create_picture_from_url (const char *const url, gint picture_size) {
|
|||||||
g_object_set_property_int (G_OBJECT(picture), "width-request", picture_size);
|
g_object_set_property_int (G_OBJECT(picture), "width-request", picture_size);
|
||||||
|
|
||||||
cleanup_create_picture_from_url:
|
cleanup_create_picture_from_url:
|
||||||
g_free (downloaded_image);
|
if (downloaded_image) {
|
||||||
|
g_free (downloaded_image);
|
||||||
|
}
|
||||||
g_clear_object (&util_soup);
|
g_clear_object (&util_soup);
|
||||||
g_clear_object (&iostream);
|
if (iostream) {
|
||||||
g_clear_object (&tmp_image);
|
g_clear_object (&iostream);
|
||||||
|
}
|
||||||
|
g_clear_object (&image);
|
||||||
return picture;
|
return picture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GFile *
|
||||||
|
get_image_for_url (const char *url) {
|
||||||
|
GFile *image;
|
||||||
|
MgDatabase *db = mg_database_new ();
|
||||||
|
MgDatabaseStatement *statement = mg_database_prepare (db,
|
||||||
|
"select file from images where url = ?;", NULL);
|
||||||
|
char *file_name = NULL;
|
||||||
|
mg_database_statement_bind_text (statement, 1, url);
|
||||||
|
if (mg_database_statement_step (statement) == SQLITE_ROW) {
|
||||||
|
const char *file_name = (const char *) mg_database_statement_column_text
|
||||||
|
(statement, 0);
|
||||||
|
image = g_file_new_for_path (file_name);
|
||||||
|
goto cleanup_get_image_for_url;
|
||||||
|
}
|
||||||
|
g_clear_object (&statement);
|
||||||
|
file_name = generate_cache_file_name ();
|
||||||
|
statement = mg_database_prepare (db,
|
||||||
|
"insert into images (url, file) values (?, ?);", NULL);
|
||||||
|
mg_database_statement_bind_text (statement, 1, url);
|
||||||
|
mg_database_statement_bind_text (statement, 2, file_name);
|
||||||
|
mg_database_statement_step (statement);
|
||||||
|
image = g_file_new_for_path (file_name);
|
||||||
|
cleanup_get_image_for_url:
|
||||||
|
if (file_name) {
|
||||||
|
g_free (file_name);
|
||||||
|
}
|
||||||
|
g_clear_object (&statement);
|
||||||
|
g_clear_object (&db);
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
generate_cache_file_name (void) {
|
||||||
|
const char *home_dir = g_get_home_dir();
|
||||||
|
char *file_basename = g_uuid_string_random ();
|
||||||
|
char *file_path;
|
||||||
|
char *file_path_directory;
|
||||||
|
size_t file_path_len;
|
||||||
|
file_path_len = snprintf
|
||||||
|
(NULL, 0, IMAGE_CACHE_FORMAT_STRING,
|
||||||
|
home_dir, file_basename);
|
||||||
|
file_path = g_malloc
|
||||||
|
(sizeof *file_path
|
||||||
|
* (file_path_len + 1));
|
||||||
|
snprintf (file_path, file_path_len,
|
||||||
|
IMAGE_CACHE_FORMAT_STRING,
|
||||||
|
home_dir, file_basename);
|
||||||
|
file_path_directory = g_path_get_dirname
|
||||||
|
(file_path);
|
||||||
|
g_mkdir_with_parents
|
||||||
|
(file_path_directory, 00755);
|
||||||
|
return file_path;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user