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
|
||||
mg_database_get_affected_rows (MgDatabase *self);
|
||||
|
||||
char *
|
||||
const char *
|
||||
mg_database_get_error_string (MgDatabase *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -3,7 +3,7 @@ const char *const MIGRATIONS[] = {
|
||||
"key TEXT PRIMARY KEY,\n"
|
||||
"value TEXT\n"
|
||||
");\n"),
|
||||
("CREATE TABLE image (\n"
|
||||
("CREATE TABLE images (\n"
|
||||
"url TEXT PRIMARY KEY,\n"
|
||||
"file TEXT\n"
|
||||
");\n"),
|
||||
|
@ -8,8 +8,19 @@ G_DECLARE_FINAL_TYPE (MgDatabaseStatement, mg_database_statement, MG, DATABASE_S
|
||||
|
||||
MgDatabaseStatement *mg_database_statement_new ();
|
||||
|
||||
void
|
||||
mg_database_statement_bind_text (MgDatabaseStatement *self, int index, char *value);
|
||||
int
|
||||
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
|
||||
|
||||
|
@ -13,7 +13,7 @@ struct _MgDatabaseStatement {
|
||||
G_DEFINE_TYPE (MgDatabaseStatement, mg_database_statement, G_TYPE_OBJECT)
|
||||
|
||||
typedef enum {
|
||||
MG_DATABASE_STATEMENT_OWNER,
|
||||
MG_DATABASE_STATEMENT_OWNER = 1,
|
||||
MG_DATABASE_STATEMENT_STMT,
|
||||
MG_DATABASE_STATEMENT_N_PROPERTIES
|
||||
} MgDatabaseStatementProperties;
|
||||
@ -38,7 +38,7 @@ MgDatabaseStatement *
|
||||
mg_database_statement_new (MgDatabase *owner, sqlite3_stmt *statement) {
|
||||
MgDatabaseStatement *self = NULL;
|
||||
self = MG_DATABASE_STATEMENT ((g_object_new (MG_TYPE_DATABASE_STATEMENT,
|
||||
"owner", owner, "stmt", statement)));
|
||||
"owner", owner, "stmt", statement, NULL)));
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ mg_database_statement_class_init (MgDatabaseStatementClass *class) {
|
||||
"owner",
|
||||
"Owner",
|
||||
"Owner MgDatabase.",
|
||||
MG_TYPE_DATABASE_STATEMENT,
|
||||
MG_TYPE_DATABASE,
|
||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
||||
database_statement_properties[MG_DATABASE_STATEMENT_STMT] = g_param_spec_pointer (
|
||||
"stmt",
|
||||
@ -95,6 +95,7 @@ mg_database_statement_set_property (GObject *object,
|
||||
g_clear_object (&(self->owner));
|
||||
}
|
||||
self->owner = g_value_peek_pointer (value);
|
||||
g_object_ref (self->owner);
|
||||
break;
|
||||
case MG_DATABASE_STATEMENT_STMT:
|
||||
if (self->stmt) {
|
||||
@ -124,17 +125,47 @@ mg_database_statement_get_stmt (MgDatabaseStatement *self) {
|
||||
static void
|
||||
mg_database_statement_dispose (GObject *object) {
|
||||
MgDatabaseStatement *self = MG_DATABASE_STATEMENT (object);
|
||||
g_clear_object (&(self->owner));
|
||||
if (self->owner) {
|
||||
g_clear_object (&(self->owner));
|
||||
}
|
||||
sqlite3_finalize (self->stmt);
|
||||
}
|
||||
|
||||
void
|
||||
mg_database_statement_bind_text (MgDatabaseStatement *self, int index, char *value) {
|
||||
int
|
||||
mg_database_statement_bind_text (MgDatabaseStatement *self,
|
||||
int index, const char *value) {
|
||||
sqlite3_stmt *stmt = mg_database_statement_get_stmt (self);
|
||||
int error = sqlite3_bind_text (stmt, index, value, -1, SQLITE_TRANSIENT);
|
||||
if ( error != SQLITE_OK ) {
|
||||
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
|
||||
|
@ -1,38 +1,57 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <openmg/util/soup.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 *
|
||||
create_picture_from_url (const char *const url, gint picture_size) {
|
||||
GtkPicture *picture = NULL;
|
||||
GFileIOStream *iostream;
|
||||
GFile *tmp_image;
|
||||
GFileIOStream *iostream = NULL;
|
||||
GFile *image = NULL;
|
||||
GError *error = NULL;
|
||||
GdkTexture *texture;
|
||||
GdkTexture *texture = NULL;
|
||||
|
||||
size_t size_downloaded_image = 0;
|
||||
char *downloaded_image;
|
||||
char *downloaded_image = NULL;
|
||||
|
||||
MgUtilSoup *util_soup = mg_util_soup_new ();
|
||||
downloaded_image = mg_util_soup_get_request (util_soup,
|
||||
url, &size_downloaded_image);
|
||||
tmp_image = g_file_new_tmp ("mangareadertmpfileXXXXXX", &iostream, &error);
|
||||
if (error) {
|
||||
fprintf (stderr, "Unable to read file: %s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
goto cleanup_create_picture_from_url;
|
||||
image = get_image_for_url (url);
|
||||
if (!g_file_query_exists (image, NULL)) {
|
||||
downloaded_image =
|
||||
mg_util_soup_get_request
|
||||
(util_soup,
|
||||
url, &size_downloaded_image);
|
||||
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)),
|
||||
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);
|
||||
texture = gdk_texture_new_from_file (image, &error);
|
||||
if (error) {
|
||||
fprintf (stderr, "Texture malformed.");
|
||||
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);
|
||||
|
||||
cleanup_create_picture_from_url:
|
||||
g_free (downloaded_image);
|
||||
if (downloaded_image) {
|
||||
g_free (downloaded_image);
|
||||
}
|
||||
g_clear_object (&util_soup);
|
||||
g_clear_object (&iostream);
|
||||
g_clear_object (&tmp_image);
|
||||
if (iostream) {
|
||||
g_clear_object (&iostream);
|
||||
}
|
||||
g_clear_object (&image);
|
||||
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