Deprecate KotoFlipperButton, integrate flip functionality with an alt image into KotoButton.
We are now leveraging KotoButton in the KotoPlayerBar and KotoExpander. Dropped Glade UI templating from KotoWindow, set its default size using gtk_widget_set_size_request to force a minimum window size, set window title, WMClass, and icon name. Start implementing KotoIndexedFile class to handle our provided audio files, setting its file name and attempting to parse the file name when we are not using ID3 data. The parsing is as follows: - All `_` are replaced with whitespace - We will attempt to remove nested references to the artist and album name (we need to implemented the relevant classes to leverage that). - Remove any references to ` - ` followed by any stragglers `-` (without the whitespace around it). - Split based on `.` and remove the trailing file extension, preserving the rest (so something like `Ch. 01.ogg` would be considered just `Ch. 01`).
This commit is contained in:
parent
625c1be645
commit
9b6fa4593a
19 changed files with 472 additions and 333 deletions
274
src/indexer/file.c
Normal file
274
src/indexer/file.c
Normal file
|
@ -0,0 +1,274 @@
|
|||
/* file.c
|
||||
*
|
||||
* Copyright 2021 Joshua Strobl
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <glib-2.0/glib.h>
|
||||
#include "file.h"
|
||||
|
||||
struct _KotoIndexedFile {
|
||||
GObject parent_instance;
|
||||
gchar *path;
|
||||
gchar *file_name;
|
||||
gchar *parsed_name;
|
||||
gchar *artist;
|
||||
gchar *album;
|
||||
|
||||
guint position;
|
||||
gboolean acquired_metadata_from_id3;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(KotoIndexedFile, koto_indexed_file, G_TYPE_OBJECT);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_PATH,
|
||||
PROP_ARTIST,
|
||||
PROP_ALBUM,
|
||||
PROP_FILE_NAME,
|
||||
PROP_PARSED_NAME,
|
||||
PROP_POSITION,
|
||||
N_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *props[N_PROPERTIES] = { NULL };
|
||||
|
||||
static void koto_indexed_file_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec);
|
||||
static void koto_indexed_file_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec);
|
||||
|
||||
static void koto_indexed_file_class_init(KotoIndexedFileClass *c) {
|
||||
GObjectClass *gobject_class;
|
||||
gobject_class = G_OBJECT_CLASS(c);
|
||||
gobject_class->set_property = koto_indexed_file_set_property;
|
||||
gobject_class->get_property = koto_indexed_file_get_property;
|
||||
|
||||
props[PROP_PATH] = g_param_spec_string(
|
||||
"path",
|
||||
"Path",
|
||||
"Path to File",
|
||||
NULL,
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
props[PROP_ARTIST] = g_param_spec_string(
|
||||
"artist",
|
||||
"Name of Artist",
|
||||
"Name of Artist",
|
||||
NULL,
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
props[PROP_ALBUM] = g_param_spec_string(
|
||||
"album",
|
||||
"Name of Album",
|
||||
"Name of Album",
|
||||
NULL,
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
props[PROP_FILE_NAME] = g_param_spec_string(
|
||||
"file-name",
|
||||
"Name of File",
|
||||
"Name of File",
|
||||
NULL,
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
props[PROP_PARSED_NAME] = g_param_spec_string(
|
||||
"parsed-name",
|
||||
"Parsed Name of File",
|
||||
"Parsed Name of File",
|
||||
NULL,
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
props[PROP_POSITION] = g_param_spec_uint(
|
||||
"position",
|
||||
"Position in Audiobook, Album, etc.",
|
||||
"Position in Audiobook, Album, etc.",
|
||||
0,
|
||||
G_MAXUINT16,
|
||||
0,
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
g_object_class_install_properties(gobject_class, N_PROPERTIES, props);
|
||||
}
|
||||
|
||||
static void koto_indexed_file_init(KotoIndexedFile *self) {
|
||||
self->acquired_metadata_from_id3 = FALSE;
|
||||
}
|
||||
|
||||
static void koto_indexed_file_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) {
|
||||
KotoIndexedFile *self = KOTO_INDEXED_FILE(obj);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_PATH:
|
||||
g_value_set_string(val, self->path);
|
||||
break;
|
||||
case PROP_ARTIST:
|
||||
g_value_set_string(val, self->artist);
|
||||
break;
|
||||
case PROP_ALBUM:
|
||||
g_value_set_string(val, self->album);
|
||||
break;
|
||||
case PROP_FILE_NAME:
|
||||
g_value_set_string(val, self->file_name);
|
||||
break;
|
||||
case PROP_PARSED_NAME:
|
||||
g_value_set_string(val, self->parsed_name);
|
||||
break;
|
||||
case PROP_POSITION:
|
||||
g_value_set_uint(val, self->position);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void koto_indexed_file_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) {
|
||||
KotoIndexedFile *self = KOTO_INDEXED_FILE(obj);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_PATH:
|
||||
self->path = g_strdup(g_value_get_string(val)); // Update our path
|
||||
koto_indexed_file_set_file_name(self, g_path_get_basename(self->path)); // Update our file name
|
||||
break;
|
||||
case PROP_ARTIST:
|
||||
self->artist = g_strdup(g_value_get_string(val));
|
||||
break;
|
||||
case PROP_ALBUM:
|
||||
self->album = g_strdup(g_value_get_string(val));
|
||||
break;
|
||||
case PROP_FILE_NAME:
|
||||
koto_indexed_file_set_file_name(self, g_strdup(g_value_get_string(val))); // Update the file name
|
||||
break;
|
||||
case PROP_PARSED_NAME:
|
||||
koto_indexed_file_set_parsed_name(self, g_strdup(g_value_get_string(val)));
|
||||
break;
|
||||
case PROP_POSITION:
|
||||
self->position = g_value_get_uint(val);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void koto_indexed_file_set_file_name(KotoIndexedFile *self, gchar *new_file_name) {
|
||||
if (new_file_name == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((self->file_name != NULL) && (strcmp(self->file_name, new_file_name) == 0)) { // Not null and the same
|
||||
return; // Don't do anything
|
||||
}
|
||||
|
||||
if (self->file_name != NULL) { // If it is defined
|
||||
g_free(self->file_name);
|
||||
}
|
||||
|
||||
self->file_name = g_strdup(new_file_name);
|
||||
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_FILE_NAME]);
|
||||
|
||||
if (!self->acquired_metadata_from_id3) { // Haven't acquired our information from ID3
|
||||
koto_indexed_file_parse_name(self); // Update our parsed name
|
||||
}
|
||||
}
|
||||
|
||||
void koto_indexed_file_set_parsed_name(KotoIndexedFile *self, gchar *new_parsed_name) {
|
||||
if (new_parsed_name == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((self->parsed_name != NULL) && (strcmp(self->parsed_name, new_parsed_name) == 0)) { // Not null and the same
|
||||
return; // Don't do anything
|
||||
}
|
||||
|
||||
if (self->parsed_name != NULL) {
|
||||
g_free(self->parsed_name);
|
||||
}
|
||||
|
||||
self->parsed_name = g_strdup(new_parsed_name);
|
||||
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_PARSED_NAME]);
|
||||
}
|
||||
|
||||
void koto_indexed_file_parse_name(KotoIndexedFile *self) {
|
||||
gchar *copied_file_name = g_strdelimit(g_strdup(self->file_name), "_", ' '); // Replace _ with whitespace for starters
|
||||
|
||||
if (self->artist != NULL && strcmp(self->artist, "") != 0) { // If we have artist set
|
||||
gchar **split = g_strsplit(copied_file_name, self->artist, -1); // Split whenever we encounter the artist
|
||||
copied_file_name = g_strjoinv("", split); // Remove the artist
|
||||
g_strfreev(split);
|
||||
}
|
||||
|
||||
if (self->artist != NULL && strcmp(self->album, "") != 0) { // If we have album set
|
||||
gchar **split = g_strsplit(copied_file_name, self->album, -1); // Split whenever we encounter the album
|
||||
copied_file_name = g_strjoinv("", split); // Remove the album
|
||||
g_strfreev(split);
|
||||
|
||||
split = g_strsplit(copied_file_name, g_utf8_strdown(self->album, g_utf8_strlen(self->album, -1)), -1); // Split whenever we encounter the album lowercased
|
||||
copied_file_name = g_strjoin("", split, NULL); // Remove the lowercased album
|
||||
g_strfreev(split);
|
||||
}
|
||||
|
||||
if (g_str_match_string(copied_file_name, "-", FALSE)) { // Contains - like a heathen
|
||||
gchar **split = g_strsplit(copied_file_name, " - ", -1); // Split whenever we encounter " - "
|
||||
copied_file_name = g_strjoin("", split, NULL); // Remove entirely
|
||||
g_strfreev(split);
|
||||
|
||||
if (g_str_match_string(copied_file_name, "-", FALSE)) { // If we have any stragglers
|
||||
split = g_strsplit(copied_file_name, "-", -1); // Split whenever we encounter -
|
||||
copied_file_name = g_strjoin("", split, NULL); // Remove entirely
|
||||
g_strfreev(split);
|
||||
}
|
||||
}
|
||||
|
||||
gchar **split = g_strsplit(copied_file_name, ".", -1); // Split every time we see .
|
||||
g_free(copied_file_name);
|
||||
guint len_of_extension_split = g_strv_length(split);
|
||||
|
||||
if (len_of_extension_split == 2) { // Only have two elements
|
||||
copied_file_name = g_strdup(split[0]); // Get the first element
|
||||
} else {
|
||||
gchar *new_parsed_name = "";
|
||||
for (guint i = 0; i < len_of_extension_split - 1; i++) { // Iterate over everything except the last item
|
||||
if (g_strcmp0(new_parsed_name, "") == 0) { // Currently empty
|
||||
new_parsed_name = g_strdup(split[i]); // Just duplicate this string
|
||||
} else {
|
||||
gchar *tmp_copy = g_strdup(new_parsed_name);
|
||||
g_free(new_parsed_name); // Free the old
|
||||
new_parsed_name = g_strdup(g_strjoin(".", tmp_copy, split[i], NULL)); // Join the two strings with a . again and duplicate it, setting it to our new_parsed_name
|
||||
g_free(tmp_copy); // Free our temporary copy
|
||||
}
|
||||
}
|
||||
|
||||
copied_file_name = g_strdup(new_parsed_name);
|
||||
g_free(new_parsed_name);
|
||||
}
|
||||
|
||||
g_strfreev(split);
|
||||
|
||||
koto_indexed_file_set_parsed_name(self, copied_file_name);
|
||||
g_free(copied_file_name);
|
||||
}
|
||||
|
||||
KotoIndexedFile* koto_indexed_file_new(const gchar *path) {
|
||||
return g_object_new(KOTO_TYPE_INDEXED_FILE,
|
||||
"path", path,
|
||||
NULL
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue