changeset 236:4d461ef7d424

HUGE UPDATE: convert build system to autotools why? because cmake sucks :)
author Paper <mrpapersonic@gmail.com>
date Fri, 19 Jan 2024 00:24:02 -0500
parents 593108b3d555
children a7d0d543b334 1ae4d8b28a5c
files .builds/linux.yml .builds/windows.yml Makefile.am configure.ac dep/animia/CMakeLists.txt dep/animia/Makefile.am dep/animia/configure.ac dep/animia/src/animia.cc dep/animia/src/strategist.cc dep/animia/src/win/x11.cc dep/anitomy/CMakeLists.txt dep/anitomy/Makefile.am dep/anitomy/configure.ac dep/pugixml/CMakeLists.txt dep/pugixml/Makefile.am dep/pugixml/configure.ac include/core/http.h include/core/session.h include/core/torrent.h include/gui/dialog/settings.h include/gui/pages/now_playing.h include/gui/pages/torrents.h include/gui/window.h m4/libcurl.m4 m4/m4_ax_cxx_compile_stdcxx.m4 m4/m4_ax_have_qt.m4 rc/win32/version.rc.in src/core/anime_db.cc src/core/http.cc src/gui/dialog/about.cc src/gui/dialog/information.cc src/gui/dialog/settings.cc src/gui/dialog/settings/library.cc src/gui/pages/anime_list.cc src/gui/pages/history.cc src/gui/pages/now_playing.cc src/gui/pages/search.cc src/gui/pages/seasons.cc src/gui/pages/statistics.cc src/gui/pages/torrents.cc src/gui/theme.cc src/gui/widgets/anime_info.cc src/gui/widgets/clickable_label.cc src/gui/widgets/optional_date.cc src/gui/widgets/poster.cc src/gui/widgets/sidebar.cc src/gui/widgets/text.cc src/gui/window.cc src/main.cc src/sys/glib/dark_theme.cc src/track/media.cc
diffstat 51 files changed, 2229 insertions(+), 713 deletions(-) [+]
line wrap: on
line diff
--- a/.builds/linux.yml	Tue Jan 16 15:22:29 2024 -0500
+++ b/.builds/linux.yml	Fri Jan 19 00:24:02 2024 -0500
@@ -18,14 +18,22 @@
 tasks:
   - build: |
       cd minori
+      autoreconf -i
+      cd dep/animia
+      autoreconf -i
+      cd ../anitomy
+      autoreconf -i
+      cd ../pugixml
+      autoreconf -i
+      cd ../..
       mkdir build
       cd build
-      cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
+      ../configure
       make
 
       wget -O linuxdeploy "https://github.com/linuxdeploy/linuxdeploy/releases/download/1-alpha-20231026-1/linuxdeploy-x86_64.AppImage"
       chmod +x linuxdeploy
-      ./linuxdeploy --appdir Minori --executable minori -l libanimia.so -l libanitomy.so -l libpugixml.so -d rc/Minori.desktop -i rc/Minori.png --output appimage
+      ./linuxdeploy --appdir Minori --executable minori -d rc/Minori.desktop -i rc/Minori.png --output appimage
 artifacts:
   - minori/build/Minori-x86_64.AppImage
 triggers:
--- a/.builds/windows.yml	Tue Jan 16 15:22:29 2024 -0500
+++ b/.builds/windows.yml	Fri Jan 19 00:24:02 2024 -0500
@@ -22,12 +22,10 @@
       git clone https://github.com/holyblackcat/quasi-msys2 quasi-msys2-win64
       cd quasi-msys2-win64
       echo MINGW64 >msystem.txt
-      make install _gcc _qt5-base _qt5-tools _curl
+      make install _gcc _qt5-base _qt5-tools _curl _autotools
       cd ../minori
-      mkdir build64
-      cd build64
       sudo bash -c 'echo -n 1 >/proc/sys/fs/binfmt_misc/status'
-      bash -c 'source ../../quasi-msys2-win64/env/all.src && cmake .. -G "Unix Makefiles" -DCMAKE_AUTOMOC_EXECUTABLE="$(which moc)" -DCMAKE_AUTORCC_EXECUTABLE="$(which rcc)" && make'
+      bash -c 'source ../../quasi-msys2-win64/env/all.src && autoreconf -i && cd dep/animia && autoreconf -i && cd ../anitomy && autoreconf -i && cd ../pugixml && autoreconf -i && ../.. && mkdir build64 && cd build64 && ../configure && make'
   - get-wine32: |
       sudo dpkg --add-architecture i386
       sudo apt-get update
@@ -43,7 +41,7 @@
       mkdir build32
       cd build32
       sudo bash -c 'echo -n 1 >/proc/sys/fs/binfmt_misc/status'
-      bash -c 'source ../../quasi-msys2-win32/env/all.src && cmake .. -G "Unix Makefiles" -DCMAKE_AUTOMOC_EXECUTABLE="$(which moc)" -DCMAKE_AUTORCC_EXECUTABLE="$(which rcc)" && make'
+      bash -c 'source ../../quasi-msys2-win32/env/all.src && autoreconf -i && cd dep/animia && autoreconf -i && cd ../anitomy && autoreconf -i && cd ../pugixml && autoreconf -i && ../.. && mkdir build32 && cd build32 && ../configure && make'
 triggers:
   - action: email
     condition: failure
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile.am	Fri Jan 19 00:24:02 2024 -0500
@@ -0,0 +1,157 @@
+bin_PROGRAMS = minori
+
+minori_qtrc = \
+	$(top_srcdir)/rc/dark.qrc	\
+	$(top_srcdir)/rc/icons.qrc	\
+	$(top_srcdir)/rc/player_data.qrc
+
+rc/final_qrc.cc: $(minori_qtrc)
+	@QT_RCC@ -o $@ $(minori_qtrc)
+
+minori_qtheaders = \
+	include/core/http.h			\
+	include/gui/dialog/about.h		\
+	include/gui/dialog/information.h		\
+	include/gui/dialog/settings.h			\
+	include/gui/pages/anime_list.h			\
+	include/gui/pages/history.h			\
+	include/gui/pages/now_playing.h		\
+	include/gui/pages/search.h			\
+	include/gui/pages/seasons.h		\
+	include/gui/pages/statistics.h		\
+	include/gui/pages/torrents.h		\
+	include/gui/translate/anilist.h		\
+	include/gui/translate/anime.h			\
+	include/gui/translate/config.h		\
+	include/gui/widgets/anime_info.h		\
+	include/gui/widgets/clickable_label.h		\
+	include/gui/widgets/graph.h			\
+	include/gui/widgets/optional_date.h		\
+	include/gui/widgets/poster.h			\
+	include/gui/widgets/sidebar.h			\
+	include/gui/widgets/text.h		\
+	include/gui/locale.h	\
+	include/gui/theme.h			\
+	include/gui/window.h
+
+noinst_HEADERS = \
+	include/core/anime_db.h		\
+	include/core/anime.h		\
+	include/core/config.h		\
+	include/core/date.h		\
+	include/core/filesystem.h			\
+	include/core/ini.h		\
+	include/core/json.h			\
+	include/core/session.h			\
+	include/core/strings.h			\
+	include/core/time.h			\
+	include/core/torrent.h		\
+	include/library/library.h		\
+	include/services/anilist.h		\
+	include/services/services.h		\
+	include/sys/glib/dark_theme.h	\
+	include/sys/osx/dark_theme.h	\
+	include/sys/osx/filesystem.h	\
+	include/sys/win32/dark_theme.h	\
+	include/track/media.h			\
+	$(minori_qtheaders)
+
+minori_moc_sources = $(minori_qtheaders:.h=_moc.cc)
+
+if BUILD_GLIB
+files_glib = src/sys/glib/dark_theme.cc
+cflags_glib = @GIO_CFLAGS@
+libs_glib = @GIO_LIBS@
+endif
+
+if BUILD_WIN
+files_win = src/sys/win32/dark_theme.cc
+
+if BUILD_WINDRES
+# Untested...
+wrcflags_version = -DWRC_VERSION=0,`echo '$(PACKAGE_VERSION)' | sed 's/(\d+)\.(\d+)\.(\d+)/\1,\2,\3/'`
+
+WRCFLAGS = --use-temp-file -I. -I$(srcdir) $(wrcflags_version)
+.rc.$(OBJEXT):
+	$(WINDRES) $(WRCFLAGS) -i $< -o $@
+files_windres=rc/win32/version.rc
+endif
+endif
+
+if BUILD_OSX
+files_osx = src/sys/osx/dark_theme.cc src/sys/osx/filesystem.cc
+libs_osx = Foundation AppKit
+endif
+
+minori_SOURCES = \
+	src/core/anime_db.cc		\
+	src/core/anime.cc		\
+	src/core/config.cc		\
+	src/core/date.cc		\
+	src/core/filesystem.cc		\
+	src/core/http.cc		\
+	src/core/json.cc		\
+	src/core/strings.cc		\
+	src/core/time.cc		\
+	src/gui/dialog/settings/application.cc		\
+	src/gui/dialog/settings/library.cc		\
+	src/gui/dialog/settings/recognition.cc		\
+	src/gui/dialog/settings/services.cc		\
+	src/gui/dialog/settings/torrents.cc		\
+	src/gui/dialog/about.cc		\
+	src/gui/dialog/information.cc		\
+	src/gui/dialog/settings.cc		\
+	src/gui/pages/anime_list.cc		\
+	src/gui/pages/history.cc		\
+	src/gui/pages/now_playing.cc		\
+	src/gui/pages/search.cc		\
+	src/gui/pages/seasons.cc		\
+	src/gui/pages/statistics.cc		\
+	src/gui/pages/torrents.cc		\
+	src/gui/translate/anilist.cc		\
+	src/gui/translate/anime.cc		\
+	src/gui/translate/config.cc		\
+	src/gui/widgets/anime_info.cc		\
+	src/gui/widgets/clickable_label.cc		\
+	src/gui/widgets/optional_date.cc		\
+	src/gui/widgets/poster.cc		\
+	src/gui/widgets/sidebar.cc		\
+	src/gui/widgets/text.cc		\
+	src/gui/locale.cc		\
+	src/gui/theme.cc		\
+	src/gui/window.cc		\
+	src/library/library.cc		\
+	src/services/anilist.cc		\
+	src/services/services.cc		\
+	src/track/media.cc		\
+	src/main.cc		\
+	$(files_osx)			\
+	$(files_glib)			\
+	$(files_win)			\
+	$(minori_moc_sources)	\
+	rc/final_qrc.cc		\
+	$(files_windres)
+
+minori_includes = \
+	-I$(top_srcdir)/include \
+	-I$(top_srcdir)/dep/animia/include \
+	-I$(top_srcdir)/dep/pugixml/src \
+	-I$(top_srcdir)/dep/anitomy \
+	-I$(top_srcdir)/dep
+
+minori_CPPFLAGS = $(minori_includes) @QT_CXXFLAGS@ @LIBCURL_CPPFLAGS@
+minori_CXXFLAGS = $(cflags_glib) $(cflags_win) $(cflags_osx)
+
+minori_DEPENDENCIES = dep/pugixml/libpugixml.la dep/animia/libanimia.la dep/anitomy/libanitomy.la
+minori_LDADD = $(libs_glib) $(libs_osx) @LIBCURL@ @QT_LIBS@ dep/pugixml/libpugixml.la dep/animia/libanimia.la dep/anitomy/libanitomy.la
+
+.qrc_qrc.cc:
+	
+
+.h_moc.cc:
+	@MKDIR_P@ -- `dirname $@`
+	@QT_MOC@ -o $@ $(minori_includes) $<
+
+SUFFIXES = .h _moc.cc .qrc _qrc.cc
+SUBDIRS = $(subdirs)
+ACLOCAL_AMFLAGS = -I m4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/configure.ac	Fri Jan 19 00:24:02 2024 -0500
@@ -0,0 +1,71 @@
+AC_INIT([minori], [0.1.0-alpha.1])
+
+AC_CANONICAL_HOST
+
+AC_CONFIG_SRCDIR([src/main.cc])
+AC_CONFIG_AUX_DIR([build-aux])
+AC_CONFIG_MACRO_DIRS([m4])
+
+AM_INIT_AUTOMAKE([-Wall -Wportability foreign subdir-objects])
+
+# Do we have a C++17 compiler
+AC_PROG_CXX
+AX_CXX_COMPILE_STDCXX(17, noext, mandatory)
+
+AM_PROG_AR
+LT_INIT
+
+# Qt?
+AX_HAVE_QT
+
+if test "x$have_qt" = "xno"; then
+	AC_MSG_ERROR([*** Qt not found.])
+fi
+
+# need this for moc
+AC_PROG_MKDIR_P
+
+# libcurl?
+LIBCURL_CHECK_CONFIG(yes, 7.7.2, [have_libcurl=yes], [have_libcurl=no])
+
+if test "x$have_libcurl" = "xno"; then
+	AC_MSG_ERROR([*** libcurl not found.])
+fi
+
+build_windows=no
+build_osx=no
+build_glib=no
+
+case "${host_os}" in
+	cygwin*|mingw*)
+		# Windows
+		build_windows=yes
+		AC_CHECK_TOOL([WINDRES], [windres])
+		AC_SUBST(WINDRES)
+		AC_DEFINE(WIN32)
+		;;
+	darwin*)
+		# Mac OS X
+		build_osx=yes
+		AC_DEFINE(MACOSX)
+		;;
+	*)
+		if test "x$host_os" = "xlinux"; then
+			AC_DEFINE(LINUX)
+		fi
+		# Everything else
+		AC_SUBST([GIO_CFLAGS])
+		AC_SUBST([GIO_LIBS])
+		PKG_CHECK_MODULES(GIO, gio-2.0, [build_glib=yes], [])
+		;;
+esac
+
+AM_CONDITIONAL([BUILD_WIN], [test "x$build_windows" = "xyes"])
+AM_CONDITIONAL([BUILD_OSX], [test "x$build_osx" = "xyes"])
+AM_CONDITIONAL([BUILD_GLIB], [test "x$build_glib" = "xyes"])
+AM_CONDITIONAL([BUILD_WINDRES], [test "x$WINDRES" != "x"])
+
+AC_CONFIG_SUBDIRS([dep/pugixml dep/animia dep/anitomy])
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
--- a/dep/animia/CMakeLists.txt	Tue Jan 16 15:22:29 2024 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-cmake_minimum_required(VERSION 3.16)
-project(animia LANGUAGES CXX)
-set(SRC_FILES
-	# any non-platform-specific files go here
-	src/animia.cc
-	src/player.cc
-	src/util.cc
-	src/strategist.cc
-	src/fd.cc
-	src/win.cc
-)
-
-include(CheckLanguage)
-
-set(LIBRARIES)
-set(INCLUDE_DIRS)
-set(DEFINES)
-
-if(APPLE)
-	list(APPEND DEFINES MACOSX)
-	list(APPEND SRC_FILES
-		# xnu stuff
-		src/fd/xnu.cc
-		src/util/osx.cc
-	)
-
-	include(CheckIncludeFile)
-	check_include_file("CoreFoundation/CoreFoundation.h" HAVE_COREFOUNDATION)
-	# If you're building on OS X, you most likely do have this file, but we
-	# check anyway.
-	if(HAVE_COREFOUNDATION)
-		list(APPEND DEFINES HAVE_COREFOUNDATION)
-		find_library(OBJC_LIBRARY objc)
-
-		if(NOT OBJC_LIBRARY)
-			message(STATUS "Found CoreFoundation/CoreFoundation.h, but not the Objective-C runtime. How?")
-		endif()
-
-		list(APPEND SRC_FILES src/win/quartz.cc)
-
-		find_library(FOUNDATION_LIBRARY Foundation)
-		find_library(COREGRAPHICS_LIBRARY CoreGraphics)
-		find_library(APPKIT_LIBRARY AppKit)
-		list(APPEND LIBRARIES ${FOUNDATION_LIBRARY} ${COREGRAPHICS_LIBRARY} ${APPKIT_LIBRARY} ${OBJC_LIBRARY})
-	else() # NOT HAVE_COREFOUNDATION
-		message(STATUS "You don't have Core Foundation. How? What kind of voodoo magic did you do to cause this?")
-		message(WARNING "LaunchServices support will not be compiled.")
-	endif() # HAVE_COREFOUNDATION
-elseif(WIN32)
-	list(APPEND DEFINES WIN32)
-	list(APPEND SRC_FILES
-		# win32
-		src/fd/win32.cc
-		src/win/win32.cc
-		src/util/win32.cc
-	)
-else() # NOT WIN32 AND NOT APPLE
-	find_library(LIBUTIL_LIBRARY util)
-	find_library(LIBKVM_LIBRARY kvm)
-
-	if(LINUX)
-		list(APPEND DEFINES LINUX)
-		list(APPEND SRC_FILES src/fd/proc.cc)
-	elseif(LIBUTIL_LIBRARY) # FreeBSD's libutil
-		get_filename_component(LIBUTIL_DIR ${LIBUTIL_LIBRARY} DIRECTORY)
-
-		include(CheckLibraryExists)
-		check_library_exists(util kinfo_getfile ${LIBUTIL_DIR} LIBUTIL_GOOD)
-
-		if(LIBUTIL_GOOD)
-			list(APPEND LIBRARIES ${LIBUTIL_LIBRARY})
-			list(APPEND DEFINES LIBUTIL)
-			list(APPEND SRC_FILES src/fd/libutil.cc)
-		endif() # LIBUTIL_GOOD
-	elseif(LIBKVM_LIBRARY) # OpenBSD kvm
-		list(APPEND LIBRARIES ${LIBKVM_LIBRARY})
-		list(APPEND DEFINES LIBKVM)
-		list(APPEND SRC_FILES src/fd/kvm.cc)
-
-		get_filename_component(LIBKVM_DIR ${LIBKVM_LIBRARY} DIRECTORY)
-
-		include(CheckLibraryExists)
-		check_library_exists(kvm kvm_getfiles ${LIBKVM_DIR} LIBKVM_HAS_GETFILES)
-
-		if(LIBKVM_HAS_GETFILES)
-			list(APPEND DEFINES HAVE_KVM_GETFILES)
-		endif() # LIBKVM_HAS_GETFILES
-	endif() # LINUX
-endif() # WIN32 AND APPLE
-
-# X11
-find_package(PkgConfig)
-if(PKG_CONFIG_FOUND)
-	pkg_check_modules(XCB xcb xcb-res)
-	if (XCB_FOUND)
-		list(APPEND DEFINES X11)
-		list(APPEND LIBRARIES ${XCB_LINK_LIBRARIES})
-		list(APPEND INCLUDE_DIRS ${XCB_INCLUDE_DIRS})
-		list(APPEND SRC_FILES src/win/x11.cc)
-	endif() # XCB_FOUND
-
-	# Wayland
-	pkg_check_modules(WAYLAND wayland-client)
-	if(WAYLAND_FOUND)
-		enable_language(C)
-		list(APPEND DEFINES WAYLAND)
-		list(APPEND SRC_FILES
-			src/win/wayland.cc
-			src/win/wayland/ext-foreign-toplevel-list-v1.c
-			src/win/wayland/wlr-foreign-toplevel-management-unstable-v1.c
-		)
-		list(APPEND INCLUDE_DIRS ${WAYLAND_INCLUDE_DIRS})
-		list(APPEND LIBRARIES ${WAYLAND_LINK_LIBRARIES})
-	endif() # WAYLAND_FOUND
-endif() # PKG_CONFIG_FOUND
-
-add_library(animia SHARED ${SRC_FILES})
-set_target_properties(animia PROPERTIES
-	PUBLIC_HEADER include/animia.h
-	CXX_STANDARD 17
-)
-
-target_compile_definitions(animia PRIVATE ${DEFINES})
-target_include_directories(animia PUBLIC include PRIVATE ${INCLUDE_DIRS})
-target_link_libraries(animia PUBLIC ${LIBRARIES})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/animia/Makefile.am	Fri Jan 19 00:24:02 2024 -0500
@@ -0,0 +1,66 @@
+lib_LTLIBRARIES = libanimia.la
+include_HEADERS = include/animia.h
+
+if BUILD_WIN
+files_win = src/fd/win32.cc src/win/win32.cc src/util/win32.cc
+endif
+
+if BUILD_OSX
+files_osx = src/fd/xnu.cc src/win/quartz.cc src/util/osx.cc
+cflags_osx =
+libs_osx = Foundation CoreGraphics AppKit objc
+endif
+
+if BUILD_LINUX
+files_linux = src/fd/proc.cc
+endif
+
+if BUILD_LIBUTIL
+files_libutil = src/fd/libutil.cc
+libs_libutil = -lutil
+endif
+
+if BUILD_LIBKVM
+files_libkvm = src/fd/kvm.cc
+libs_libkvm = -lkvm
+endif
+
+if BUILD_XCB
+files_x11 = src/win/x11.cc
+cflags_x11 = @XCB_CFLAGS@
+libs_x11 = @XCB_LIBS@
+endif
+
+if BUILD_WAYLAND
+files_wayland = \
+	src/win/wayland.cc \
+	src/win/wayland/ext-foreign-toplevel-list-v1.c \
+	src/win/wayland/wlr-foreign-toplevel-management-unstable-v1.c
+cflags_wayland = @WAYLAND_CFLAGS@
+libs_wayland = @WAYLAND_LIBS@
+endif
+
+libanimia_la_SOURCES = \
+	src/animia.cc \
+	src/fd.cc \
+	src/player.cc \
+	src/strategist.cc \
+	src/util.cc \
+	src/win.cc \
+	$(files_win) \
+	$(files_osx) \
+	$(files_linux) \
+	$(files_libutil) \
+	$(files_libkvm) \
+	$(files_x11) \
+	$(files_wayland)
+
+libanimia_la_CPPFLAGS = -I$(top_srcdir)/include @DEFS@
+
+libanimia_la_LDFLAGS = -version-info 0:0:0
+
+libanimia_la_CXXFLAGS = $(cflags_osx) $(cflags_x11) $(cflags_wayland)
+
+libanimia_la_LIBADD = $(libs_wayland) $(libs_x11) $(libs_osx) $(libs_libutil) $(libs_libkvm)
+
+ACLOCAL_AMFLAGS = -I m4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/animia/configure.ac	Fri Jan 19 00:24:02 2024 -0500
@@ -0,0 +1,79 @@
+AC_INIT([animia], [0.1.0-alpha.1])
+
+AC_CANONICAL_HOST
+
+AC_CONFIG_SRCDIR([src/animia.cc])
+AC_CONFIG_AUX_DIR([build-aux])
+AC_CONFIG_MACRO_DIRS([m4])
+
+AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
+
+# Do we have a C++17 compiler
+AC_PROG_CXX
+
+AM_PROG_AR
+LT_INIT
+
+build_win32=no
+build_osx=no
+build_linux=no
+build_libutil=no
+build_kvm=no
+
+build_x11=no
+build_wayland=no
+
+case "${host_os}" in
+	cygwin*|mingw*)
+		# Windows
+		build_windows=yes
+		AC_CHECK_TOOL([WINDRES], [windres])
+		AC_SUBST(WINDRES)
+		AC_DEFINE([WIN32])
+		;;
+	darwin*)
+		# Mac OS X
+		build_osx=yes
+		AC_DEFINE([MACOSX])
+		;;
+	linux*)
+		build_linux=yes
+		AC_DEFINE([LINUX])
+		;;
+	*)
+		# FreeBSD
+		AC_CHECK_LIB([util], [kinfo_getfile], [build_libutil=yes], [build_libutil=no])
+		if test "x$build_libutil" = "xyes"; then
+			AC_DEFINE([LIBUTIL])
+		else
+			# OpenBSD
+			AC_CHECK_LIB([kvm], [kvm_getfiles], [build_kvm=yes], [build_kvm=no])
+			if test "x$build_kvm" = "xyes"; then
+				AC_DEFINE([LIBKVM])
+			fi
+		fi
+		;;
+esac
+
+if ! test "x$build_osx" = "xyes" && ! test "x$build_windows" = "xyes"; then
+	PKG_CHECK_MODULES(XCB, [xcb xcb-res], [build_x11=yes], [build_x11=no])
+	if test "x$build_x11" = "xyes"; then
+		AC_DEFINE([X11])
+	fi
+	PKG_CHECK_MODULES(WAYLAND, [wayland-client], [build_wayland=yes], [build_wayland=no])
+	if test "x$build_wayland" = "xyes"; then
+		AC_DEFINE([WAYLAND])
+	fi
+fi
+
+AM_CONDITIONAL([BUILD_WIN], [test "x$build_windows" = "xyes"])
+AM_CONDITIONAL([BUILD_OSX], [test "x$build_osx" = "xyes"])
+AM_CONDITIONAL([BUILD_LINUX], [test "x$build_linux" = "xyes"])
+AM_CONDITIONAL([BUILD_LIBUTIL], [test "x$build_libutil" = "xyes"])
+AM_CONDITIONAL([BUILD_LIBKVM], [test "x$build_kvm" = "xyes"])
+
+AM_CONDITIONAL([BUILD_XCB], [test "x$build_x11" = "xyes"])
+AM_CONDITIONAL([BUILD_WAYLAND], [test "x$build_wayland" = "xyes"])
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
--- a/dep/animia/src/animia.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/dep/animia/src/animia.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -27,9 +27,12 @@
 	return false;
 }
 
-static bool IsWindowInList(const Player& player, const std::string& name) {
+static bool IsWindowInList(const Player& player, const Window& window) {
+//	if (util::CheckPattern(player.window_title_format, window.text))
+//		return true;
+
 	for (const auto& pattern : player.windows)
-		if (util::CheckPattern(pattern, name))
+		if (util::CheckPattern(pattern, window.class_name))
 			return true;
 
 	return false;
@@ -65,22 +68,12 @@
 	if (!internal::EnumerateOpenProcesses(process_proc))
 		return false;
 
-	/* Then add our cool windows.
-	   Note: X11 is stupid and there's no reliable way to get a PID from a given window.
-	         This is because some windows might not even have a process attached to them.
-	         We should set the PID of the process if we can get it, but that'll be for when
-	         I can actually be arsed to implement the X11 backend. */
 	auto window_proc = [&](const Process& process, const Window& window) -> bool {
 		for (const auto& player : players) {
-			if (!internal::PlayerHasStrategy(player, Strategy::WindowTitle))
-				continue;
+			if (internal::IsWindowInList(player, window))
+				results.push_back({ResultType::Window, player, process, window, {}});
+		}
 
-			if (!internal::IsWindowInList(player, window.class_name))
-				continue;
-
-			results.push_back({ResultType::Window, player, process, window, {}});
-			break;
-		}
 		return true;
 	};
 
--- a/dep/animia/src/strategist.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/dep/animia/src/strategist.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -5,6 +5,8 @@
 #include "animia/strategies.h"
 #include "animia/util.h"
 
+#include <iostream>
+
 namespace animia::internal {
 
 class Strategist {
--- a/dep/animia/src/win/x11.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/dep/animia/src/win/x11.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -1,11 +1,3 @@
-/*
- * win/x11.cc: provides support for X11 clients via XCB
- *
- * This code is fairly fast (I think...). As a result,
- * a lot of it is hard to read if you're unfamiliar with
- * asynchronous programming, but it works much better than
- * Xlib (which can take much longer).
-*/
 #include "animia/win/x11.h"
 #include "animia/win.h"
 #include "animia.h"
@@ -19,6 +11,10 @@
 #include <string>
 #include <set>
 
+#include <chrono>
+
+#include <iostream>
+
 static size_t str_nlen(const char* s, size_t len) {
     size_t i = 0;
     for (; i < len && s[i]; i++);
@@ -27,6 +23,32 @@
 
 namespace animia::internal::x11 {
 
+static void GetWindowPID(xcb_connection_t* connection, const std::vector<xcb_window_t>& windows, std::unordered_map<xcb_window_t, pid_t>& result) {
+	std::vector<xcb_res_query_client_ids_cookie_t> cookies;
+	cookies.reserve(windows.size());
+
+	for (const auto& window : windows) {
+		xcb_res_client_id_spec_t spec = {
+			.client = window,
+			.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID
+		};
+
+		cookies.push_back(::xcb_res_query_client_ids(connection, 1, &spec));
+	}
+
+	for (size_t i = 0; i < cookies.size(); i++) {
+		xcb_res_query_client_ids_reply_t* reply = ::xcb_res_query_client_ids_reply(connection, cookies.at(i), NULL);
+
+		xcb_res_client_id_value_iterator_t it = xcb_res_query_client_ids_ids_iterator(reply);
+		for (; it.rem; xcb_res_client_id_value_next(&it)) {
+			if (it.data->spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
+				result[windows.at(i)] = *::xcb_res_client_id_value_value(it.data);
+				continue;
+			}
+		}
+	}
+}
+
 static bool GetAllTopLevelWindowsEWMH(xcb_connection_t* connection, const std::vector<xcb_window_t>& roots, std::set<xcb_window_t>& result) {
 	const xcb_atom_t Atom__NET_CLIENT_LIST = [connection]{
 		static constexpr std::string_view name = "_NET_CLIENT_LIST";
@@ -50,25 +72,23 @@
 
 	for (const auto& cookie : cookies) {
 		xcb_get_property_reply_t* reply = ::xcb_get_property_reply(connection, cookie, NULL);
-
-		if (reply && reply->length == 32) {
+		if (reply) {
 			xcb_window_t* value = reinterpret_cast<xcb_window_t*>(::xcb_get_property_value(reply));
 			int len = ::xcb_get_property_value_length(reply);
 
 			for (size_t i = 0; i < len; i++)
 				result.insert(value[i]);
-
 			success = true;
 		}
-
 		free(reply);
 	}
 
 	return success;
 }
 
+/* I have no idea why this works. */
 static bool WalkWindows(xcb_connection_t* connection, const std::vector<xcb_window_t>& roots, std::set<xcb_window_t>& result) {
-	/* move this somewhere else pl0x */
+	/* move this somewhere */
 	xcb_atom_t Atom_WM_STATE = [connection]{
 		static constexpr std::string_view name = "WM_STATE";
 		xcb_intern_atom_cookie_t cookie = ::xcb_intern_atom(connection, true, name.size(), name.data());
@@ -81,98 +101,49 @@
 	if (Atom_WM_STATE == XCB_ATOM_NONE)
 		return false;
 
-	/* for each toplevel: search recursively for */
-	std::function<bool(const xcb_window_t*, const int, xcb_window_t&)> find_wm_state_window = [&](const xcb_window_t* wins, const int wins_len, xcb_window_t& out) {
-		/* Check for wm_state */
-		{
-			std::vector<xcb_get_property_cookie_t> property_cookies;
-			property_cookies.reserve(wins_len);
-
-			for (size_t j = 0; j < wins_len; j++)
-				property_cookies.push_back(::xcb_get_property(connection, 0, wins[j], Atom_WM_STATE, Atom_WM_STATE, 0, 0));
-
-			for (size_t j = 0; j < property_cookies.size(); j++) {
-				xcb_generic_error_t* err = NULL;
-				xcb_get_property_reply_t* reply = ::xcb_get_property_reply(connection, property_cookies.at(j), &err);
-
-				if (reply->format || reply->type || reply->length) {
-					out = wins[j];
-					free(reply);
-					return true;
-				}
-
-				free(reply);
-			}
-		}
-
-		/* Query tree for recursion */
-		{
-			std::vector<xcb_query_tree_cookie_t> cookies;
-			cookies.reserve(wins_len);
-
-			for (size_t j = 0; j < wins_len; j++)
-				cookies.push_back(::xcb_query_tree(connection, wins[j]));
-
-			for (const auto& cookie : cookies) {
-				xcb_query_tree_reply_t* reply = ::xcb_query_tree_reply(connection, cookie, NULL);
-
-				xcb_window_t* windows = ::xcb_query_tree_children(reply);
-				int len = ::xcb_query_tree_children_length(reply);
-
-				if (find_wm_state_window(windows, len, out)) {
-					free(reply);
-					return true;
-				}
-
-				free(reply);
-			}
-		}
-
-		return false;
-	};
-
-	/* Get the tree for each root */
 	std::vector<xcb_query_tree_cookie_t> cookies;
 	cookies.reserve(roots.size());
 
 	for (const auto& root : roots)
 		cookies.push_back(::xcb_query_tree(connection, root));
 
-	for (size_t i = 0; i < cookies.size(); i++) {
-		xcb_query_tree_reply_t* reply = ::xcb_query_tree_reply(connection, cookies.at(i), NULL);
+	for (const auto& cookie : cookies) {
+		xcb_query_tree_reply_t* reply = ::xcb_query_tree_reply(connection, cookie, NULL);
 
-		xcb_window_t* windows = ::xcb_query_tree_children(reply);
-		int len = ::xcb_query_tree_children_length(reply);
-		if (len < 1)
-			continue;
+		std::vector<xcb_window_t> windows = [reply]{
+			xcb_window_t* windows = ::xcb_query_tree_children(reply);
+			int len = ::xcb_query_tree_children_length(reply);
 
-		/* Then get the tree of each child window. */
-		std::vector<xcb_query_tree_cookie_t> cookies;
-		cookies.reserve(len);
+			std::vector<xcb_window_t> w;
+			w.reserve(len);
+
+			for (int i = 0; i < len; i++)
+				w.push_back(windows[i]);
 
-		for (size_t j = 0; j < len; j++)
-			cookies.push_back(::xcb_query_tree(connection, windows[j]));
+			return w;
+		}();
+
+		std::vector<xcb_get_property_cookie_t> state_property_cookies;
+		state_property_cookies.reserve(windows.size());
 
-		/* For each child window... */
-		for (size_t j = 0; j < cookies.size(); j++) {
-			xcb_query_tree_reply_t* reply = ::xcb_query_tree_reply(connection, cookies.at(j), NULL);
+		for (int i = 0; i < windows.size(); i++)
+			state_property_cookies.push_back(::xcb_get_property(connection, 0, windows[i], Atom_WM_STATE, Atom_WM_STATE, 0, 0));
 
-			xcb_window_t* children = ::xcb_query_tree_children(reply);
-			int children_len = ::xcb_query_tree_children_length(reply);
-			if (children_len < 1) {
-				result.insert(windows[j]);
+		for (size_t i = 0; i < state_property_cookies.size(); i++) {
+			xcb_generic_error_t* err = NULL;
+			xcb_get_property_reply_t* reply = ::xcb_get_property_reply(connection, state_property_cookies.at(i), &err);
+
+			if (reply->format || reply->type || reply->length) {
+				result.insert(windows[i]);
+				free(reply);
 				continue;
 			}
 
-			xcb_window_t out = windows[j];
-			/* Search recursively for a window with WM_STATE. If we don't,
-			 * just add the toplevel.
-			*/
-			find_wm_state_window(children, children_len, out);
-			result.insert(out);
+			free(reply);
 		}
 
-		free(reply);
+		if (WalkWindows(connection, windows, result))
+			continue;
 	}
 
 	return false;
@@ -186,27 +157,23 @@
 	if (!connection)
 		return false;
 
-	std::vector<xcb_screen_t> screens;
-
+	std::set<xcb_window_t> windows;
 	{
-		xcb_screen_iterator_t iter = ::xcb_setup_roots_iterator(xcb_get_setup(connection));
-		for (; iter.rem; ::xcb_screen_next(&iter))
-			screens.push_back(*iter.data);
-	}
+		std::vector<xcb_window_t> roots;
+		{
+			xcb_screen_iterator_t iter = ::xcb_setup_roots_iterator(xcb_get_setup(connection));
+			for (; iter.rem; ::xcb_screen_next(&iter))
+				roots.push_back(iter.data->root);
+		}
 
-	std::vector<xcb_window_t> roots;
-	roots.reserve(screens.size());
-
-	for (const auto& screen : screens)
-		roots.push_back(screen.root);
-
-	std::set<xcb_window_t> windows;
-	if (!GetAllTopLevelWindowsEWMH(connection, roots, windows))
-		WalkWindows(connection, roots, windows);
+		
+		if (!GetAllTopLevelWindowsEWMH(connection, roots, windows))
+			WalkWindows(connection, roots, windows);
+	}
 
 	std::vector<xcb_get_property_cookie_t> class_property_cookies;
 	std::vector<xcb_get_property_cookie_t> name_property_cookies;
-	std::vector<xcb_res_query_client_ids_cookie_t> pid_property_cookies;
+	std::vector<xcb_get_property_cookie_t> pid_property_cookies;
 	class_property_cookies.reserve(windows.size());
 	name_property_cookies.reserve(windows.size());
 	pid_property_cookies.reserve(windows.size());
@@ -214,13 +181,7 @@
 	for (const auto& window : windows) {
 		class_property_cookies.push_back(::xcb_get_property(connection, 0, window, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 0L, 2048L));
 		name_property_cookies.push_back(::xcb_get_property(connection, 0, window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0L, UINT_MAX));
-
-		xcb_res_client_id_spec_t spec = {
-			.client = window,
-			.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID
-		};
-
-		pid_property_cookies.push_back(::xcb_res_query_client_ids(connection, 1, &spec));
+		pid_property_cookies.push_back(::xcb_get_property(connection, 0, window, XCB_ATOM_WM_NAME, XCB_ATOM_CARDINAL, 0L, 1L));
 	}
 
 	size_t i = 0;
@@ -229,7 +190,6 @@
 		win.id = window;
 		{
 			xcb_get_property_reply_t* reply = ::xcb_get_property_reply(connection, class_property_cookies.at(i), NULL);
-
 			if (reply && reply->format == 8) {
 				const char* data = reinterpret_cast<char*>(::xcb_get_property_value(reply));
 				const int data_len = ::xcb_get_property_value_length(reply);
@@ -239,38 +199,26 @@
 
 				win.class_name = std::string(class_name, str_nlen(class_name, data_len - (instance_len + 1)));
 			}
-
 			free(reply);
 		}
 		{
 			xcb_get_property_reply_t* reply = ::xcb_get_property_reply(connection, name_property_cookies.at(i), NULL);
-
-			if (reply && reply->format == 8) {
+			if (reply) {
 				const char* data = reinterpret_cast<char*>(::xcb_get_property_value(reply));
 				int len = ::xcb_get_property_value_length(reply);
 
-				win.text = std::string(data, len);
+				win.text = std::string((char*)data, len);
 			}
-
 			free(reply);
 		}
 		Process proc = {0};
 		{
-			xcb_res_query_client_ids_reply_t* reply = ::xcb_res_query_client_ids_reply(connection, pid_property_cookies.at(i), NULL);
-
-			if (reply->length) {
-				xcb_res_client_id_value_iterator_t it = ::xcb_res_query_client_ids_ids_iterator(reply);
-				for (; it.rem; ::xcb_res_client_id_value_next(&it)) {
-					if (it.data->spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
-						proc.pid = *::xcb_res_client_id_value_value(it.data);
-						break;
-					}
-				}
-			}
+			xcb_get_property_reply_t* reply = ::xcb_get_property_reply(connection, pid_property_cookies.at(i), NULL);
+			if (reply)
+				proc.pid = *reinterpret_cast<uint32_t*>(::xcb_get_property_value(reply));
 
 			free(reply);
 		}
-
 		if (!window_proc(proc, win)) {
 			::xcb_disconnect(connection);
 			return false;
--- a/dep/anitomy/CMakeLists.txt	Tue Jan 16 15:22:29 2024 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-cmake_minimum_required(VERSION 3.9)
-project(anitomy)
-add_library(anitomy SHARED
-	anitomy/anitomy.cpp
-	anitomy/element.cpp
-	anitomy/keyword.cpp
-	anitomy/parser.cpp
-	anitomy/parser_helper.cpp
-	anitomy/parser_number.cpp
-	anitomy/string.cpp
-	anitomy/token.cpp
-	anitomy/tokenizer.cpp
-)
-set_target_properties(anitomy PROPERTIES
-    PUBLIC_HEADER anitomy/anitomy.h CXX_STANDARD 17)
-target_include_directories(anitomy PRIVATE src)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/anitomy/Makefile.am	Fri Jan 19 00:24:02 2024 -0500
@@ -0,0 +1,22 @@
+lib_LTLIBRARIES = libanitomy.la
+libanitomy_la_SOURCES = \
+	anitomy/anitomy.cpp	\
+	anitomy/element.cpp	\
+	anitomy/keyword.cpp	\
+	anitomy/parser.cpp	\
+	anitomy/parser_helper.cpp	\
+	anitomy/parser_number.cpp	\
+	anitomy/string.cpp	\
+	anitomy/token.cpp	\
+	anitomy/tokenizer.cpp
+
+include_HEADERS = \
+	anitomy/anitomy.h	\
+	anitomy/element.h	\
+	anitomy/keyword.h	\
+	anitomy/parser.h	\
+	anitomy/string.h	\
+	anitomy/token.h	\
+	anitomy/tokenizer.h
+
+ACLOCAL_AMFLAGS = -I m4
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/anitomy/configure.ac	Fri Jan 19 00:24:02 2024 -0500
@@ -0,0 +1,18 @@
+AC_INIT([anitomy], [1.0])
+
+AC_CONFIG_SRCDIR([anitomy/anitomy.cpp])
+AC_CONFIG_AUX_DIR([build-aux])
+AC_CONFIG_MACRO_DIRS([m4])
+
+AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
+
+# Check for a C compiler
+AC_PROG_CXX
+
+# Need this because libtool is weird
+AM_PROG_AR
+
+LT_INIT
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
\ No newline at end of file
--- a/dep/pugixml/CMakeLists.txt	Tue Jan 16 15:22:29 2024 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,264 +0,0 @@
-cmake_minimum_required(VERSION 3.5)
-
-# Policy configuration; this *MUST* be specified before project is defined
-if(POLICY CMP0091)
-    cmake_policy(SET CMP0091 NEW) # Enables use of MSVC_RUNTIME_LIBRARY
-endif()
-
-project(pugixml VERSION 1.14 LANGUAGES CXX)
-
-include(CMakePackageConfigHelpers)
-include(CMakeDependentOption)
-include(GNUInstallDirs)
-include(CTest)
-
-cmake_dependent_option(PUGIXML_USE_VERSIONED_LIBDIR
-  "Use a private subdirectory to install the headers and libraries" OFF
-  "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
-
-cmake_dependent_option(PUGIXML_USE_POSTFIX
-  "Use separate postfix for each configuration to make sure you can install multiple build outputs" OFF
-  "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
-
-cmake_dependent_option(PUGIXML_STATIC_CRT
-  "Use static MSVC RT libraries" OFF
-  "MSVC" OFF)
-
-cmake_dependent_option(PUGIXML_BUILD_TESTS
-  "Build pugixml tests" OFF
-  "BUILD_TESTING;CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
-
-# Custom build defines
-set(PUGIXML_BUILD_DEFINES CACHE STRING "Build defines for custom options")
-separate_arguments(PUGIXML_BUILD_DEFINES)
-
-# Technically not needed for this file. This is builtin CMAKE global variable.
-option(BUILD_SHARED_LIBS "Build shared instead of static library" OFF) 
-
-# Expose option to build PUGIXML as static as well when the global BUILD_SHARED_LIBS variable is set
-cmake_dependent_option(PUGIXML_BUILD_SHARED_AND_STATIC_LIBS
-  "Build both shared and static libraries" OFF
-  "BUILD_SHARED_LIBS" OFF)
-
-# Expose options from the pugiconfig.hpp
-option(PUGIXML_WCHAR_MODE "Enable wchar_t mode" OFF)
-option(PUGIXML_COMPACT "Enable compact mode" OFF)
-
-# Advanced options from pugiconfig.hpp
-option(PUGIXML_NO_XPATH "Disable XPath" OFF)
-option(PUGIXML_NO_STL "Disable STL" OFF)
-option(PUGIXML_NO_EXCEPTIONS "Disable Exceptions" OFF)
-mark_as_advanced(PUGIXML_NO_XPATH PUGIXML_NO_STL PUGIXML_NO_EXCEPTIONS)
-
-set(PUGIXML_PUBLIC_DEFINITIONS
-  $<$<BOOL:${PUGIXML_WCHAR_MODE}>:PUGIXML_WCHAR_MODE>
-  $<$<BOOL:${PUGIXML_COMPACT}>:PUGIXML_COMPACT>
-  $<$<BOOL:${PUGIXML_NO_XPATH}>:PUGIXML_NO_XPATH>
-  $<$<BOOL:${PUGIXML_NO_STL}>:PUGIXML_NO_STL>
-  $<$<BOOL:${PUGIXML_NO_EXCEPTIONS}>:PUGIXML_NO_EXCEPTIONS>)
-
-# This is used to backport a CMake 3.15 feature, but is also forwards compatible
-if (NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
-  set(CMAKE_MSVC_RUNTIME_LIBRARY
-    MultiThreaded$<$<CONFIG:Debug>:Debug>$<$<NOT:$<BOOL:${PUGIXML_STATIC_CRT}>>:DLL>)
-endif()
-
-if (NOT DEFINED CMAKE_CXX_STANDARD_REQUIRED)
-  set(CMAKE_CXX_STANDARD_REQUIRED ON)
-endif()
-
-if (NOT DEFINED CMAKE_CXX_STANDARD)
-  set(CMAKE_CXX_STANDARD 11)
-endif()
-
-if (PUGIXML_USE_POSTFIX)
-  set(CMAKE_RELWITHDEBINFO_POSTFIX _r)
-  set(CMAKE_MINSIZEREL_POSTFIX _m)
-  set(CMAKE_DEBUG_POSTFIX _d)
-endif()
-
-if (CMAKE_VERSION VERSION_LESS 3.15)
-  set(msvc-rt $<TARGET_PROPERTY:MSVC_RUNTIME_LIBRARY>)
-
-  set(msvc-rt-mtd-shared $<STREQUAL:${msvc-rt},MultiThreadedDebugDLL>)
-  set(msvc-rt-mtd-static $<STREQUAL:${msvc-rt},MultiThreadedDebug>)
-  set(msvc-rt-mt-shared $<STREQUAL:${msvc-rt},MultiThreadedDLL>)
-  set(msvc-rt-mt-static $<STREQUAL:${msvc-rt},MultiThreaded>)
-  unset(msvc-rt)
-
-  set(msvc-rt-mtd-shared $<${msvc-rt-mtd-shared}:-MDd>)
-  set(msvc-rt-mtd-static $<${msvc-rt-mtd-static}:-MTd>)
-  set(msvc-rt-mt-shared $<${msvc-rt-mt-shared}:-MD>)
-  set(msvc-rt-mt-static $<${msvc-rt-mt-static}:-MT>)
-endif()
-
-set(versioned-dir $<$<BOOL:${PUGIXML_USE_VERSIONED_LIBDIR}>:/pugixml-${PROJECT_VERSION}>)
-
-set(libs)
-
-if (BUILD_SHARED_LIBS)
-  add_library(pugixml-shared SHARED
-    ${PROJECT_SOURCE_DIR}/scripts/pugixml_dll.rc
-    ${PROJECT_SOURCE_DIR}/src/pugixml.cpp)
-  add_library(pugixml::shared ALIAS pugixml-shared)
-  list(APPEND libs pugixml-shared)
-  string(CONCAT pugixml.msvc $<OR:
-    $<STREQUAL:${CMAKE_CXX_COMPILER_FRONTEND_VARIANT},MSVC>,
-    $<CXX_COMPILER_ID:MSVC>
-  >)
-
-  set_property(TARGET pugixml-shared PROPERTY EXPORT_NAME shared)
-  target_include_directories(pugixml-shared
-    PUBLIC
-      $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>)
-  target_compile_definitions(pugixml-shared
-    PUBLIC
-      ${PUGIXML_BUILD_DEFINES}
-      ${PUGIXML_PUBLIC_DEFINITIONS}
-    PRIVATE
-      PUGIXML_API=$<IF:${pugixml.msvc},__declspec\(dllexport\),__attribute__\(\(visibility\("default"\)\)\)>
-    )
-  target_compile_options(pugixml-shared
-    PRIVATE
-      ${msvc-rt-mtd-shared}
-      ${msvc-rt-mtd-static}
-      ${msvc-rt-mt-shared}
-      ${msvc-rt-mt-static})
-endif()
-
-if (NOT BUILD_SHARED_LIBS OR PUGIXML_BUILD_SHARED_AND_STATIC_LIBS)
-  add_library(pugixml-static STATIC
-    ${PROJECT_SOURCE_DIR}/src/pugixml.cpp)
-  add_library(pugixml::static ALIAS pugixml-static)
-  list(APPEND libs pugixml-static)
-
-  set_property(TARGET pugixml-static PROPERTY EXPORT_NAME static)
-  target_include_directories(pugixml-static
-    PUBLIC
-      $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>)
-  target_compile_definitions(pugixml-static
-    PUBLIC
-      ${PUGIXML_BUILD_DEFINES}
-      ${PUGIXML_PUBLIC_DEFINITIONS})
-  target_compile_options(pugixml-static
-    PRIVATE
-      ${msvc-rt-mtd-shared}
-      ${msvc-rt-mtd-static}
-      ${msvc-rt-mt-shared}
-      ${msvc-rt-mt-static})
-endif()
-
-if (BUILD_SHARED_LIBS)
-  set(pugixml-alias pugixml-shared)
-else()
-  set(pugixml-alias pugixml-static)
-endif()
-add_library(pugixml INTERFACE)
-target_link_libraries(pugixml INTERFACE ${pugixml-alias})
-add_library(pugixml::pugixml ALIAS pugixml)
-
-set_target_properties(${libs}
-  PROPERTIES
-    MSVC_RUNTIME_LIBRARY ${CMAKE_MSVC_RUNTIME_LIBRARY}
-    EXCLUDE_FROM_ALL ON
-    POSITION_INDEPENDENT_CODE ON
-    SOVERSION ${PROJECT_VERSION_MAJOR}
-    VERSION ${PROJECT_VERSION}
-    OUTPUT_NAME pugixml)
-
-set_target_properties(${libs}
-  PROPERTIES
-    EXCLUDE_FROM_ALL OFF)
-set(install-targets pugixml ${libs})
-
-configure_package_config_file(
-  "${PROJECT_SOURCE_DIR}/scripts/pugixml-config.cmake.in"
-  "${PROJECT_BINARY_DIR}/pugixml-config.cmake"
-  INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}
-  NO_CHECK_REQUIRED_COMPONENTS_MACRO
-  NO_SET_AND_CHECK_MACRO)
-
-write_basic_package_version_file(
-  "${PROJECT_BINARY_DIR}/pugixml-config-version.cmake"
-  COMPATIBILITY SameMajorVersion)
-
-if (PUGIXML_USE_POSTFIX)
-  if(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)
-    set(LIB_POSTFIX ${CMAKE_RELWITHDEBINFO_POSTFIX})
-  elseif(CMAKE_BUILD_TYPE MATCHES MinSizeRel)
-    set(LIB_POSTFIX ${CMAKE_MINSIZEREL_POSTFIX})
-  elseif(CMAKE_BUILD_TYPE MATCHES Debug)
-    set(LIB_POSTFIX ${CMAKE_DEBUG_POSTFIX})
-  endif()
-endif()
-
-configure_file(scripts/pugixml.pc.in pugixml.pc @ONLY)
-
-if (NOT DEFINED PUGIXML_RUNTIME_COMPONENT)
-  set(PUGIXML_RUNTIME_COMPONENT Runtime)
-endif()
-
-if (NOT DEFINED PUGIXML_LIBRARY_COMPONENT)
-  set(PUGIXML_LIBRARY_COMPONENT Library)
-endif()
-
-if (NOT DEFINED PUGIXML_DEVELOPMENT_COMPONENT)
-  set(PUGIXML_DEVELOPMENT_COMPONENT Development)
-endif()
-
-set(namelink-component)
-if (NOT CMAKE_VERSION VERSION_LESS 3.12)
-  set(namelink-component NAMELINK_COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT})
-endif()
-install(TARGETS ${install-targets}
-  EXPORT pugixml-targets
-  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${PUGIXML_RUNTIME_COMPONENT}
-  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${PUGIXML_LIBRARY_COMPONENT} ${namelink-component}
-  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT}
-  INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}${versioned-dir})
-
-install(EXPORT pugixml-targets
-  NAMESPACE pugixml::
-  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pugixml COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT})
-
-export(EXPORT pugixml-targets
-  NAMESPACE pugixml::)
-
-install(FILES
-  "${PROJECT_BINARY_DIR}/pugixml-config-version.cmake"
-  "${PROJECT_BINARY_DIR}/pugixml-config.cmake"
-  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pugixml COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT})
-
-install(FILES ${PROJECT_BINARY_DIR}/pugixml.pc
-  DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT})
-
-install(
-  FILES
-    "${PROJECT_SOURCE_DIR}/src/pugiconfig.hpp"
-    "${PROJECT_SOURCE_DIR}/src/pugixml.hpp"
-  DESTINATION
-    ${CMAKE_INSTALL_INCLUDEDIR}${versioned-dir} COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT})
-
-if (PUGIXML_BUILD_TESTS)
-  set(fuzz-pattern "tests/fuzz_*.cpp")
-  set(test-pattern "tests/*.cpp")
-  if (CMAKE_VERSION VERSION_GREATER 3.11)
-    list(INSERT fuzz-pattern 0 CONFIGURE_DEPENDS)
-    list(INSERT test-pattern 0 CONFIGURE_DEPENDS)
-  endif()
-  file(GLOB test-sources ${test-pattern})
-  file(GLOB fuzz-sources ${fuzz-pattern})
-  list(REMOVE_ITEM test-sources ${fuzz-sources})
-
-  add_custom_target(check
-    COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure)
-
-  add_executable(pugixml-check ${test-sources})
-  add_test(NAME pugixml::test
-    COMMAND pugixml-check
-    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
-  add_dependencies(check pugixml-check)
-  target_link_libraries(pugixml-check
-    PRIVATE
-      pugixml::pugixml)
-endif()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/pugixml/Makefile.am	Fri Jan 19 00:24:02 2024 -0500
@@ -0,0 +1,5 @@
+lib_LTLIBRARIES = libpugixml.la
+libpugixml_la_SOURCES = src/pugixml.cpp
+include_HEADERS = src/pugixml.hpp
+
+ACLOCAL_AMFLAGS = -I m4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/pugixml/configure.ac	Fri Jan 19 00:24:02 2024 -0500
@@ -0,0 +1,18 @@
+AC_INIT([pugixml], [1.14])
+
+AC_CONFIG_SRCDIR([src/pugixml.cpp])
+AC_CONFIG_AUX_DIR([build-aux])
+AC_CONFIG_MACRO_DIRS([m4])
+
+AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
+
+# Check for a C compiler
+AC_PROG_CXX
+
+# Need this because libtool is weird
+AM_PROG_AR
+
+LT_INIT
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
--- a/include/core/http.h	Tue Jan 16 15:22:29 2024 -0500
+++ b/include/core/http.h	Fri Jan 19 00:24:02 2024 -0500
@@ -15,7 +15,7 @@
 	Q_OBJECT
 
 public:
-	GetThread(const std::string& u, const std::vector<std::string>& h = {}) {
+	GetThread(const std::string& u, const std::vector<std::string>& h = {}, QObject* parent = nullptr) : QThread(parent) {
 		url = u;
 		headers = h;
 	}
@@ -36,7 +36,7 @@
 	Q_OBJECT
 
 public:
-	PostThread(const std::string& u, const std::string& d, const std::vector<std::string>& h = {}) {
+	PostThread(const std::string& u, const std::string& d, const std::vector<std::string>& h = {}, QObject* parent = nullptr) : QThread(parent) {
 		url = u;
 		data = d;
 		headers = h;
--- a/include/core/session.h	Tue Jan 16 15:22:29 2024 -0500
+++ b/include/core/session.h	Fri Jan 19 00:24:02 2024 -0500
@@ -16,7 +16,7 @@
 		int uptime() { return timer.elapsed(); }
 
 		Config config;
-		static constexpr semver::version version{0, 1, 0, semver::prerelease::alpha, 1};
+		static constexpr semver::version version{PACKAGE_VERSION};
 
 	private:
 		unsigned int requests = 0;
--- a/include/core/torrent.h	Tue Jan 16 15:22:29 2024 -0500
+++ b/include/core/torrent.h	Fri Jan 19 00:24:02 2024 -0500
@@ -5,9 +5,10 @@
 #include <QDateTime>
 
 /* this is really just a fancy struct...
-
-   this will be moved into its own namespace if
-   it's deemed necessary */
+ *
+ * this will be moved into its own namespace if
+ * it's deemed necessary
+*/
 class Torrent {
 	public:
 		std::string GetTitle() const { return _title; };
@@ -18,7 +19,7 @@
 		std::string GetResolution() const { return _resolution; };
 		int GetSeeders() const { return _seeders; };
 		int GetLeechers() const { return _leechers; };
-		int GetDownloaders() const { return _downloaders; };
+		int GetDownloads() const { return _downloads; };
 		std::string GetDescription() const { return _description; };
 		std::string GetFilename() const { return _filename; };
 		std::string GetLink() const { return _link; };
@@ -33,7 +34,7 @@
 		void SetResolution(const std::string& resolution) { _resolution = resolution; };
 		void SetSeeders(const int seeders) { _seeders = seeders; };
 		void SetLeechers(const int leechers) { _leechers = leechers; };
-		void SetDownloaders(const int downloaders) { _downloaders = downloaders; };
+		void SetDownloads(const int downloads) { _downloads = downloads; };
 		void SetDescription(const std::string& description) { _description = description; };
 		void SetFilename(const std::string& filename) { _filename = filename; };
 		void SetLink(const std::string& link) { _link = link; };
@@ -50,7 +51,7 @@
 		                            but std::string is more useful */
 		int _seeders = 0;
 		int _leechers = 0;
-		int _downloaders = 0;
+		int _downloads = 0;
 		std::string _description;
 		std::string _filename;
 		std::string _link;
--- a/include/gui/dialog/settings.h	Tue Jan 16 15:22:29 2024 -0500
+++ b/include/gui/dialog/settings.h	Fri Jan 19 00:24:02 2024 -0500
@@ -7,12 +7,29 @@
 #include <QDialog>
 #include <QWidget>
 #include <QLocale>
+#include <QListWidget>
 
 class QLabel;
 class QTabWidget;
 class QStackedWidget;
 class SideBar;
 
+/* !!! MOVE THIS ELSEWHERE! */
+class DroppableListWidget : public QListWidget {
+	Q_OBJECT
+
+public:
+	explicit DroppableListWidget(QWidget* parent);
+
+signals:
+	void FilesDropped(QStringList list);
+
+protected:
+	void dragEnterEvent(QDragEnterEvent* event) override;
+	void dragMoveEvent(QDragMoveEvent* event) override;
+	void dropEvent(QDropEvent* event) override;
+};
+
 class SettingsPage : public QWidget {
 		Q_OBJECT
 
--- a/include/gui/pages/now_playing.h	Tue Jan 16 15:22:29 2024 -0500
+++ b/include/gui/pages/now_playing.h	Fri Jan 19 00:24:02 2024 -0500
@@ -1,8 +1,13 @@
 #ifndef __gui__pages__now_playing_h
 #define __gui__pages__now_playing_h
 
+#include "gui/widgets/anime_info.h"
+#include "gui/widgets/poster.h"
+#include "gui/widgets/text.h"
+
 #include <QFrame>
 #include <unordered_map>
+#include <memory>
 
 class QStackedWidget;
 
@@ -14,6 +19,35 @@
 class Elements;
 }
 
+namespace NowPlayingPages {
+
+class Default : public QWidget {
+		Q_OBJECT
+
+	public:
+		Default(QWidget* parent = nullptr);
+};
+
+class Playing : public QWidget {
+		Q_OBJECT
+
+	public:
+		Playing(QWidget* parent = nullptr);
+		void SetPlayingAnime(const Anime::Anime& anime, const anitomy::Elements& info);
+		int GetPlayingAnime();
+
+	private:
+		int _id = 0;
+		int _episode = 0;
+		std::unique_ptr<QWidget> _main = nullptr;
+		std::unique_ptr<TextWidgets::Title> _title = nullptr;
+		std::unique_ptr<AnimeInfoWidget> _info = nullptr;
+		std::unique_ptr<QWidget> _sidebar = nullptr;
+		std::unique_ptr<Poster> _poster = nullptr;
+};
+
+}
+
 class NowPlayingPage final : public QFrame {
 		Q_OBJECT
 
--- a/include/gui/pages/torrents.h	Tue Jan 16 15:22:29 2024 -0500
+++ b/include/gui/pages/torrents.h	Fri Jan 19 00:24:02 2024 -0500
@@ -31,7 +31,7 @@
 			TL_RESOLUTION,
 			TL_SEEDERS, 
 			TL_LEECHERS,
-			TL_DOWNLOADERS,
+			TL_DOWNLOADS,
 			TL_DESCRIPTION,
 			TL_FILENAME,
 			TL_RELEASEDATE,
--- a/include/gui/window.h	Tue Jan 16 15:22:29 2024 -0500
+++ b/include/gui/window.h	Fri Jan 19 00:24:02 2024 -0500
@@ -37,7 +37,7 @@
 		void CreateBars();
 		void AddMainWidgets();
 		void RetranslateUI();
-		void AsyncSynchronize(QStackedWidget* stack);
+		void AsyncSynchronize(QAction* action, QStackedWidget* stack);
 		void changeEvent(QEvent* event) override;
 		void showEvent(QShowEvent* event) override;
 		void closeEvent(QCloseEvent* event) override;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m4/libcurl.m4	Fri Jan 19 00:24:02 2024 -0500
@@ -0,0 +1,274 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) David Shaw <dshaw@jabberwocky.com>
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION],
+#                       [ACTION-IF-YES], [ACTION-IF-NO])
+# ----------------------------------------------------------
+#      David Shaw <dshaw@jabberwocky.com>   May-09-2006
+#
+# Checks for libcurl.  DEFAULT-ACTION is the string yes or no to
+# specify whether to default to --with-libcurl or --without-libcurl.
+# If not supplied, DEFAULT-ACTION is yes.  MINIMUM-VERSION is the
+# minimum version of libcurl to accept.  Pass the version as a regular
+# version number like 7.10.1. If not supplied, any version is
+# accepted.  ACTION-IF-YES is a list of shell commands to run if
+# libcurl was successfully found and passed the various tests.
+# ACTION-IF-NO is a list of shell commands that are run otherwise.
+# Note that using --without-libcurl does run ACTION-IF-NO.
+#
+# This macro #defines HAVE_LIBCURL if a working libcurl setup is
+# found, and sets @LIBCURL@ and @LIBCURL_CPPFLAGS@ to the necessary
+# values.  Other useful defines are LIBCURL_FEATURE_xxx where xxx are
+# the various features supported by libcurl, and LIBCURL_PROTOCOL_yyy
+# where yyy are the various protocols supported by libcurl.  Both xxx
+# and yyy are capitalized.  See the list of AH_TEMPLATEs at the top of
+# the macro for the complete list of possible defines.  Shell
+# variables $libcurl_feature_xxx and $libcurl_protocol_yyy are also
+# defined to 'yes' for those features and protocols that were found.
+# Note that xxx and yyy keep the same capitalization as in the
+# curl-config list (e.g. it's "HTTP" and not "http").
+#
+# Users may override the detected values by doing something like:
+# LIBCURL="-lcurl" LIBCURL_CPPFLAGS="-I/usr/myinclude" ./configure
+#
+# For the sake of sanity, this macro assumes that any libcurl that is found is
+# after version 7.7.2, the first version that included the curl-config script.
+# Note that it is important for people packaging binary versions of libcurl to
+# include this script!  Without curl-config, we can only guess what protocols
+# are available, or use curl_version_info to figure it out at runtime.
+
+AC_DEFUN([LIBCURL_CHECK_CONFIG],
+[
+  AH_TEMPLATE([LIBCURL_FEATURE_SSL],[Defined if libcurl supports SSL])
+  AH_TEMPLATE([LIBCURL_FEATURE_KRB4],[Defined if libcurl supports KRB4])
+  AH_TEMPLATE([LIBCURL_FEATURE_IPV6],[Defined if libcurl supports IPv6])
+  AH_TEMPLATE([LIBCURL_FEATURE_LIBZ],[Defined if libcurl supports libz])
+  AH_TEMPLATE([LIBCURL_FEATURE_ASYNCHDNS],[Defined if libcurl supports AsynchDNS])
+  AH_TEMPLATE([LIBCURL_FEATURE_IDN],[Defined if libcurl supports IDN])
+  AH_TEMPLATE([LIBCURL_FEATURE_SSPI],[Defined if libcurl supports SSPI])
+  AH_TEMPLATE([LIBCURL_FEATURE_NTLM],[Defined if libcurl supports NTLM])
+
+  AH_TEMPLATE([LIBCURL_PROTOCOL_HTTP],[Defined if libcurl supports HTTP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_HTTPS],[Defined if libcurl supports HTTPS])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_FTP],[Defined if libcurl supports FTP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_FTPS],[Defined if libcurl supports FTPS])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_FILE],[Defined if libcurl supports FILE])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_TELNET],[Defined if libcurl supports TELNET])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_POP3],[Defined if libcurl supports POP3])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_IMAP],[Defined if libcurl supports IMAP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_SMTP],[Defined if libcurl supports SMTP])
+
+  AC_ARG_WITH(libcurl,
+     AS_HELP_STRING([--with-libcurl=PREFIX],[look for the curl library in PREFIX/lib and headers in PREFIX/include]),
+     [_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])])
+
+  if test "$_libcurl_with" != "no" ; then
+
+     AC_PROG_AWK
+
+     _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'"
+
+     _libcurl_try_link=yes
+
+     if test -d "$_libcurl_with" ; then
+        LIBCURL_CPPFLAGS="-I$withval/include"
+        _libcurl_ldflags="-L$withval/lib"
+        AC_PATH_PROG([_libcurl_config],[curl-config],[],
+                     ["$withval/bin"])
+     else
+        AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH])
+     fi
+
+     if test x$_libcurl_config != "x" ; then
+        AC_CACHE_CHECK([for the version of libcurl],
+           [libcurl_cv_lib_curl_version],
+           [libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`])
+
+        _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse`
+        _libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse`
+
+        if test $_libcurl_wanted -gt 0 ; then
+           AC_CACHE_CHECK([for libcurl >= version $2],
+              [libcurl_cv_lib_version_ok],
+              [
+              if test $_libcurl_version -ge $_libcurl_wanted ; then
+                 libcurl_cv_lib_version_ok=yes
+              else
+                 libcurl_cv_lib_version_ok=no
+              fi
+              ])
+        fi
+
+        if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then
+           if test x"$LIBCURL_CPPFLAGS" = "x" ; then
+              LIBCURL_CPPFLAGS=`$_libcurl_config --cflags`
+           fi
+           if test x"$LIBCURL" = "x" ; then
+              LIBCURL=`$_libcurl_config --libs`
+
+              # This is so silly, but Apple actually has a bug in their
+              # curl-config script.  Fixed in Tiger, but there are still
+              # lots of Panther installs around.
+              case "${host}" in
+                 powerpc-apple-darwin7*)
+                    LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'`
+                 ;;
+              esac
+           fi
+
+           # All curl-config scripts support --feature
+           _libcurl_features=`$_libcurl_config --feature`
+
+           # Is it modern enough to have --protocols? (7.12.4)
+           if test $_libcurl_version -ge 461828 ; then
+              _libcurl_protocols=`$_libcurl_config --protocols`
+           fi
+        else
+           _libcurl_try_link=no
+        fi
+
+        unset _libcurl_wanted
+     fi
+
+     if test $_libcurl_try_link = yes ; then
+
+        # we did not find curl-config, so let's see if the user-supplied
+        # link line (or failing that, "-lcurl") is enough.
+        LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"}
+
+        AC_CACHE_CHECK([whether libcurl is usable],
+           [libcurl_cv_lib_curl_usable],
+           [
+           _libcurl_save_cppflags=$CPPFLAGS
+           CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS"
+           _libcurl_save_libs=$LIBS
+           LIBS="$LIBCURL $LIBS"
+
+           AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <curl/curl.h>]],[[
+/* Try and use a few common options to force a failure if we are
+   missing symbols or cannot link. */
+int x;
+curl_easy_setopt(NULL,CURLOPT_URL,NULL);
+x=CURL_ERROR_SIZE;
+x=CURLOPT_WRITEFUNCTION;
+x=CURLOPT_WRITEDATA;
+x=CURLOPT_ERRORBUFFER;
+x=CURLOPT_STDERR;
+x=CURLOPT_VERBOSE;
+if (x) {;}
+]])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no)
+
+           CPPFLAGS=$_libcurl_save_cppflags
+           LIBS=$_libcurl_save_libs
+           unset _libcurl_save_cppflags
+           unset _libcurl_save_libs
+           ])
+
+        if test $libcurl_cv_lib_curl_usable = yes ; then
+
+           # Does curl_free() exist in this version of libcurl?
+           # If not, fake it with free()
+
+           _libcurl_save_cppflags=$CPPFLAGS
+           CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
+           _libcurl_save_libs=$LIBS
+           LIBS="$LIBS $LIBCURL"
+
+           AC_CHECK_DECL([curl_free],[],
+              [AC_DEFINE([curl_free],[free],
+                [Define curl_free() as free() if our version of curl lacks curl_free.])],
+              [[#include <curl/curl.h>]])
+
+           CPPFLAGS=$_libcurl_save_cppflags
+           LIBS=$_libcurl_save_libs
+           unset _libcurl_save_cppflags
+           unset _libcurl_save_libs
+
+           AC_DEFINE(HAVE_LIBCURL,1,
+             [Define to 1 if you have a functional curl library.])
+           AC_SUBST(LIBCURL_CPPFLAGS)
+           AC_SUBST(LIBCURL)
+
+           for _libcurl_feature in $_libcurl_features ; do
+              AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1])
+              eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes
+           done
+
+           if test "x$_libcurl_protocols" = "x" ; then
+
+              # We do not have --protocols, so just assume that all
+              # protocols are available
+              _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP"
+
+              if test x$libcurl_feature_SSL = xyes ; then
+                 _libcurl_protocols="$_libcurl_protocols HTTPS"
+
+                 # FTPS was not standards-compliant until version
+                 # 7.11.0 (0x070b00 == 461568)
+                 if test $_libcurl_version -ge 461568; then
+                    _libcurl_protocols="$_libcurl_protocols FTPS"
+                 fi
+              fi
+
+              # RTSP, IMAP, POP3 and SMTP were added in
+              # 7.20.0 (0x071400 == 463872)
+              if test $_libcurl_version -ge 463872; then
+                 _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP"
+              fi
+           fi
+
+           for _libcurl_protocol in $_libcurl_protocols ; do
+              AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1])
+              eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes
+           done
+        else
+           unset LIBCURL
+           unset LIBCURL_CPPFLAGS
+        fi
+     fi
+
+     unset _libcurl_try_link
+     unset _libcurl_version_parse
+     unset _libcurl_config
+     unset _libcurl_feature
+     unset _libcurl_features
+     unset _libcurl_protocol
+     unset _libcurl_protocols
+     unset _libcurl_version
+     unset _libcurl_ldflags
+  fi
+
+  if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then
+     # This is the IF-NO path
+     ifelse([$4],,:,[$4])
+  else
+     # This is the IF-YES path
+     ifelse([$3],,:,[$3])
+  fi
+
+  unset _libcurl_with
+])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m4/m4_ax_cxx_compile_stdcxx.m4	Fri Jan 19 00:24:02 2024 -0500
@@ -0,0 +1,1018 @@
+# ===========================================================================
+#  https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+#   Check for baseline language coverage in the compiler for the specified
+#   version of the C++ standard.  If necessary, add switches to CXX and
+#   CXXCPP to enable support.  VERSION may be '11', '14', '17', or '20' for
+#   the respective C++ standard version.
+#
+#   The second argument, if specified, indicates whether you insist on an
+#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+#   -std=c++11).  If neither is specified, you get whatever works, with
+#   preference for no added switch, and then for an extended mode.
+#
+#   The third argument, if specified 'mandatory' or if left unspecified,
+#   indicates that baseline support for the specified C++ standard is
+#   required and that the macro should error out if no mode with that
+#   support is found.  If specified 'optional', then configuration proceeds
+#   regardless, after defining HAVE_CXX${VERSION} if and only if a
+#   supporting mode is found.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+#   Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+#   Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
+#   Copyright (c) 2015 Paul Norman <penorman@mac.com>
+#   Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
+#   Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
+#   Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
+#   Copyright (c) 2020 Jason Merrill <jason@redhat.com>
+#   Copyright (c) 2021 Jörn Heusipp <osmanx@problemloesungsmaschine.de>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved.  This file is offered as-is, without any
+#   warranty.
+
+#serial 18
+
+dnl  This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
+dnl  (serial version number 13).
+
+AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
+  m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
+        [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
+        [$1], [17], [ax_cxx_compile_alternatives="17 1z"],
+        [$1], [20], [ax_cxx_compile_alternatives="20"],
+        [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
+  m4_if([$2], [], [],
+        [$2], [ext], [],
+        [$2], [noext], [],
+        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
+  m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
+        [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
+        [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
+        [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
+  AC_LANG_PUSH([C++])dnl
+  ac_success=no
+
+  m4_if([$2], [], [dnl
+    AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
+		   ax_cv_cxx_compile_cxx$1,
+      [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+        [ax_cv_cxx_compile_cxx$1=yes],
+        [ax_cv_cxx_compile_cxx$1=no])])
+    if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
+      ac_success=yes
+    fi])
+
+  m4_if([$2], [noext], [], [dnl
+  if test x$ac_success = xno; then
+    for alternative in ${ax_cxx_compile_alternatives}; do
+      switch="-std=gnu++${alternative}"
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+                     $cachevar,
+        [ac_save_CXX="$CXX"
+         CXX="$CXX $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXX="$ac_save_CXX"])
+      if eval test x\$$cachevar = xyes; then
+        CXX="$CXX $switch"
+        if test -n "$CXXCPP" ; then
+          CXXCPP="$CXXCPP $switch"
+        fi
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+
+  m4_if([$2], [ext], [], [dnl
+  if test x$ac_success = xno; then
+    dnl HP's aCC needs +std=c++11 according to:
+    dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
+    dnl Cray's crayCC needs "-h std=c++11"
+    dnl MSVC needs -std:c++NN for C++17 and later (default is C++14)
+    for alternative in ${ax_cxx_compile_alternatives}; do
+      for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do
+        if test x"$switch" = xMSVC; then
+          dnl AS_TR_SH maps both `:` and `=` to `_` so -std:c++17 would collide
+          dnl with -std=c++17.  We suffix the cache variable name with _MSVC to
+          dnl avoid this.
+          switch=-std:c++${alternative}
+          cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_${switch}_MSVC])
+        else
+          cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+        fi
+        AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+                       $cachevar,
+          [ac_save_CXX="$CXX"
+           CXX="$CXX $switch"
+           AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+            [eval $cachevar=yes],
+            [eval $cachevar=no])
+           CXX="$ac_save_CXX"])
+        if eval test x\$$cachevar = xyes; then
+          CXX="$CXX $switch"
+          if test -n "$CXXCPP" ; then
+            CXXCPP="$CXXCPP $switch"
+          fi
+          ac_success=yes
+          break
+        fi
+      done
+      if test x$ac_success = xyes; then
+        break
+      fi
+    done
+  fi])
+  AC_LANG_POP([C++])
+  if test x$ax_cxx_compile_cxx$1_required = xtrue; then
+    if test x$ac_success = xno; then
+      AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
+    fi
+  fi
+  if test x$ac_success = xno; then
+    HAVE_CXX$1=0
+    AC_MSG_NOTICE([No compiler with C++$1 support was found])
+  else
+    HAVE_CXX$1=1
+    AC_DEFINE(HAVE_CXX$1,1,
+              [define if the compiler supports basic C++$1 syntax])
+  fi
+  AC_SUBST(HAVE_CXX$1)
+])
+
+
+dnl  Test body for checking C++11 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+)
+
+dnl  Test body for checking C++14 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+)
+
+dnl  Test body for checking C++17 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
+)
+
+dnl  Test body for checking C++20 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_20
+)
+
+
+dnl  Tests for new features in C++11
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+// MSVC always sets __cplusplus to 199711L in older versions; newer versions
+// only set it correctly if /Zc:__cplusplus is specified as well as a
+// /std:c++NN switch:
+// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
+#elif __cplusplus < 201103L && !defined _MSC_VER
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual ~Base() {}
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual ~Derived() override {}
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+]])
+
+
+dnl  Tests for new features in C++14
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
+
+// If the compiler admits that it is not ready for C++14, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201402L && !defined _MSC_VER
+
+#error "This is not a C++14 compiler"
+
+#else
+
+namespace cxx14
+{
+
+  namespace test_polymorphic_lambdas
+  {
+
+    int
+    test()
+    {
+      const auto lambda = [](auto&&... args){
+        const auto istiny = [](auto x){
+          return (sizeof(x) == 1UL) ? 1 : 0;
+        };
+        const int aretiny[] = { istiny(args)... };
+        return aretiny[0];
+      };
+      return lambda(1, 1L, 1.0f, '1');
+    }
+
+  }
+
+  namespace test_binary_literals
+  {
+
+    constexpr auto ivii = 0b0000000000101010;
+    static_assert(ivii == 42, "wrong value");
+
+  }
+
+  namespace test_generalized_constexpr
+  {
+
+    template < typename CharT >
+    constexpr unsigned long
+    strlen_c(const CharT *const s) noexcept
+    {
+      auto length = 0UL;
+      for (auto p = s; *p; ++p)
+        ++length;
+      return length;
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("x") == 1UL, "");
+    static_assert(strlen_c("test") == 4UL, "");
+    static_assert(strlen_c("another\0test") == 7UL, "");
+
+  }
+
+  namespace test_lambda_init_capture
+  {
+
+    int
+    test()
+    {
+      auto x = 0;
+      const auto lambda1 = [a = x](int b){ return a + b; };
+      const auto lambda2 = [a = lambda1(x)](){ return a; };
+      return lambda2();
+    }
+
+  }
+
+  namespace test_digit_separators
+  {
+
+    constexpr auto ten_million = 100'000'000;
+    static_assert(ten_million == 100000000, "");
+
+  }
+
+  namespace test_return_type_deduction
+  {
+
+    auto f(int& x) { return x; }
+    decltype(auto) g(int& x) { return x; }
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static constexpr auto value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static constexpr auto value = true;
+    };
+
+    int
+    test()
+    {
+      auto x = 0;
+      static_assert(is_same<int, decltype(f(x))>::value, "");
+      static_assert(is_same<int&, decltype(g(x))>::value, "");
+      return x;
+    }
+
+  }
+
+}  // namespace cxx14
+
+#endif  // __cplusplus >= 201402L
+
+]])
+
+
+dnl  Tests for new features in C++17
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
+
+// If the compiler admits that it is not ready for C++17, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201703L && !defined _MSC_VER
+
+#error "This is not a C++17 compiler"
+
+#else
+
+#include <initializer_list>
+#include <utility>
+#include <type_traits>
+
+namespace cxx17
+{
+
+  namespace test_constexpr_lambdas
+  {
+
+    constexpr int foo = [](){return 42;}();
+
+  }
+
+  namespace test::nested_namespace::definitions
+  {
+
+  }
+
+  namespace test_fold_expression
+  {
+
+    template<typename... Args>
+    int multiply(Args... args)
+    {
+      return (args * ... * 1);
+    }
+
+    template<typename... Args>
+    bool all(Args... args)
+    {
+      return (args && ...);
+    }
+
+  }
+
+  namespace test_extended_static_assert
+  {
+
+    static_assert (true);
+
+  }
+
+  namespace test_auto_brace_init_list
+  {
+
+    auto foo = {5};
+    auto bar {5};
+
+    static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
+    static_assert(std::is_same<int, decltype(bar)>::value);
+  }
+
+  namespace test_typename_in_template_template_parameter
+  {
+
+    template<template<typename> typename X> struct D;
+
+  }
+
+  namespace test_fallthrough_nodiscard_maybe_unused_attributes
+  {
+
+    int f1()
+    {
+      return 42;
+    }
+
+    [[nodiscard]] int f2()
+    {
+      [[maybe_unused]] auto unused = f1();
+
+      switch (f1())
+      {
+      case 17:
+        f1();
+        [[fallthrough]];
+      case 42:
+        f1();
+      }
+      return f1();
+    }
+
+  }
+
+  namespace test_extended_aggregate_initialization
+  {
+
+    struct base1
+    {
+      int b1, b2 = 42;
+    };
+
+    struct base2
+    {
+      base2() {
+        b3 = 42;
+      }
+      int b3;
+    };
+
+    struct derived : base1, base2
+    {
+        int d;
+    };
+
+    derived d1 {{1, 2}, {}, 4};  // full initialization
+    derived d2 {{}, {}, 4};      // value-initialized bases
+
+  }
+
+  namespace test_general_range_based_for_loop
+  {
+
+    struct iter
+    {
+      int i;
+
+      int& operator* ()
+      {
+        return i;
+      }
+
+      const int& operator* () const
+      {
+        return i;
+      }
+
+      iter& operator++()
+      {
+        ++i;
+        return *this;
+      }
+    };
+
+    struct sentinel
+    {
+      int i;
+    };
+
+    bool operator== (const iter& i, const sentinel& s)
+    {
+      return i.i == s.i;
+    }
+
+    bool operator!= (const iter& i, const sentinel& s)
+    {
+      return !(i == s);
+    }
+
+    struct range
+    {
+      iter begin() const
+      {
+        return {0};
+      }
+
+      sentinel end() const
+      {
+        return {5};
+      }
+    };
+
+    void f()
+    {
+      range r {};
+
+      for (auto i : r)
+      {
+        [[maybe_unused]] auto v = i;
+      }
+    }
+
+  }
+
+  namespace test_lambda_capture_asterisk_this_by_value
+  {
+
+    struct t
+    {
+      int i;
+      int foo()
+      {
+        return [*this]()
+        {
+          return i;
+        }();
+      }
+    };
+
+  }
+
+  namespace test_enum_class_construction
+  {
+
+    enum class byte : unsigned char
+    {};
+
+    byte foo {42};
+
+  }
+
+  namespace test_constexpr_if
+  {
+
+    template <bool cond>
+    int f ()
+    {
+      if constexpr(cond)
+      {
+        return 13;
+      }
+      else
+      {
+        return 42;
+      }
+    }
+
+  }
+
+  namespace test_selection_statement_with_initializer
+  {
+
+    int f()
+    {
+      return 13;
+    }
+
+    int f2()
+    {
+      if (auto i = f(); i > 0)
+      {
+        return 3;
+      }
+
+      switch (auto i = f(); i + 4)
+      {
+      case 17:
+        return 2;
+
+      default:
+        return 1;
+      }
+    }
+
+  }
+
+  namespace test_template_argument_deduction_for_class_templates
+  {
+
+    template <typename T1, typename T2>
+    struct pair
+    {
+      pair (T1 p1, T2 p2)
+        : m1 {p1},
+          m2 {p2}
+      {}
+
+      T1 m1;
+      T2 m2;
+    };
+
+    void f()
+    {
+      [[maybe_unused]] auto p = pair{13, 42u};
+    }
+
+  }
+
+  namespace test_non_type_auto_template_parameters
+  {
+
+    template <auto n>
+    struct B
+    {};
+
+    B<5> b1;
+    B<'a'> b2;
+
+  }
+
+  namespace test_structured_bindings
+  {
+
+    int arr[2] = { 1, 2 };
+    std::pair<int, int> pr = { 1, 2 };
+
+    auto f1() -> int(&)[2]
+    {
+      return arr;
+    }
+
+    auto f2() -> std::pair<int, int>&
+    {
+      return pr;
+    }
+
+    struct S
+    {
+      int x1 : 2;
+      volatile double y1;
+    };
+
+    S f3()
+    {
+      return {};
+    }
+
+    auto [ x1, y1 ] = f1();
+    auto& [ xr1, yr1 ] = f1();
+    auto [ x2, y2 ] = f2();
+    auto& [ xr2, yr2 ] = f2();
+    const auto [ x3, y3 ] = f3();
+
+  }
+
+  namespace test_exception_spec_type_system
+  {
+
+    struct Good {};
+    struct Bad {};
+
+    void g1() noexcept;
+    void g2();
+
+    template<typename T>
+    Bad
+    f(T*, T*);
+
+    template<typename T1, typename T2>
+    Good
+    f(T1*, T2*);
+
+    static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
+
+  }
+
+  namespace test_inline_variables
+  {
+
+    template<class T> void f(T)
+    {}
+
+    template<class T> inline T g(T)
+    {
+      return T{};
+    }
+
+    template<> inline void f<>(int)
+    {}
+
+    template<> int g<>(int)
+    {
+      return 5;
+    }
+
+  }
+
+}  // namespace cxx17
+
+#endif  // __cplusplus < 201703L && !defined _MSC_VER
+
+]])
+
+
+dnl  Tests for new features in C++20
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 202002L && !defined _MSC_VER
+
+#error "This is not a C++20 compiler"
+
+#else
+
+#include <version>
+
+namespace cxx20
+{
+
+// As C++20 supports feature test macros in the standard, there is no
+// immediate need to actually test for feature availability on the
+// Autoconf side.
+
+}  // namespace cxx20
+
+#endif  // __cplusplus < 202002L && !defined _MSC_VER
+
+]])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m4/m4_ax_have_qt.m4	Fri Jan 19 00:24:02 2024 -0500
@@ -0,0 +1,246 @@
+# ===========================================================================
+#        https://www.gnu.org/software/autoconf-archive/ax_have_qt.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_HAVE_QT
+#
+# DESCRIPTION
+#
+#   Searches $PATH and queries qmake for Qt include files, libraries and Qt
+#   binary utilities. The macro only supports Qt5 or later.
+#
+#   The following shell variable is set to either "yes" or "no":
+#
+#     have_qt
+#
+#   Additionally, the following variables are exported:
+#
+#     QT_CXXFLAGS
+#     QT_LIBS
+#     QT_MOC
+#     QT_UIC
+#     QT_RCC
+#     QT_LRELEASE
+#     QT_LUPDATE
+#     QT_DIR
+#     QMAKE
+#
+#   which respectively contain an "-I" flag pointing to the Qt include
+#   directory, link flags necessary to link with Qt and X, the full path to
+#   the meta object compiler and the user interface compiler both, and
+#   finally the variable QTDIR as Qt likes to see it defined.
+#
+#   Example lines for Makefile.in:
+#
+#     CXXFLAGS = @QT_CXXFLAGS@
+#     MOC      = @QT_MOC@
+#
+#   After the variables have been set, a trial compile and link is performed
+#   to check the correct functioning of the meta object compiler. This test
+#   may fail when the different detected elements stem from different
+#   releases of the Qt framework. In that case, an error message is emitted
+#   and configure stops.
+#
+#   No common variables such as $LIBS or $CFLAGS are polluted.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Bastiaan Veelo <Bastiaan@Veelo.net>
+#   Copyright (c) 2014 Alex Henrie <alexhenrie24@gmail.com>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 25
+
+AU_ALIAS([BNV_HAVE_QT], [AX_HAVE_QT])
+AC_DEFUN([AX_HAVE_QT],
+[
+  AC_REQUIRE([AC_PROG_CXX])
+  AC_REQUIRE([AC_PATH_X])
+  AC_REQUIRE([AC_PATH_XTRA])
+  # openSUSE leap 15.3 installs qmake-qt5, not qmake, for example.
+  # Store the full name (like qmake-qt5) into QMAKE
+  # and the specifier (like -qt5 or empty) into am_have_qt_qmexe_suff.
+  AC_ARG_VAR([QMAKE],"Qt make tool")
+  AC_CHECK_TOOLS([QMAKE],[qmake qmake-qt6 qmake-qt5],[false])
+
+  AC_MSG_CHECKING(for Qt)
+  am_have_qt_qmexe_suff=`echo $QMAKE | sed 's,^.*qmake,,'`
+  # If we have Qt5 or later in the path, we're golden
+  ver=`$QMAKE --version | grep -o "Qt version ."`
+
+  if test "$ver" ">" "Qt version 4"; then
+    have_qt=yes
+    # This pro file dumps qmake's variables, but it only works on Qt 5 or later
+    am_have_qt_dir=`mktemp -d`
+    am_have_qt_pro="$am_have_qt_dir/test.pro"
+    am_have_qt_stash="$am_have_qt_dir/.qmake.stash"
+    am_have_qt_makefile="$am_have_qt_dir/Makefile"
+    # http://qt-project.org/doc/qt-5/qmake-variable-reference.html#qt
+    cat > $am_have_qt_pro << EOF
+win32 {
+    CONFIG -= debug_and_release
+    CONFIG += release
+}
+qtHaveModule(axcontainer):       QT += axcontainer
+qtHaveModule(axserver):          QT += axserver
+qtHaveModule(concurrent):        QT += concurrent
+qtHaveModule(core):              QT += core
+qtHaveModule(dbus):              QT += dbus
+qtHaveModule(declarative):       QT += declarative
+qtHaveModule(designer):          QT += designer
+qtHaveModule(gui):               QT += gui
+qtHaveModule(help):              QT += help
+qtHaveModule(multimedia):        QT += multimedia
+qtHaveModule(multimediawidgets): QT += multimediawidgets
+qtHaveModule(network):           QT += network
+qtHaveModule(opengl):            QT += opengl
+qtHaveModule(printsupport):      QT += printsupport
+qtHaveModule(qml):               QT += qml
+qtHaveModule(qmltest):           QT += qmltest
+qtHaveModule(x11extras):         QT += x11extras
+qtHaveModule(script):            QT += script
+qtHaveModule(scripttools):       QT += scripttools
+qtHaveModule(sensors):           QT += sensors
+qtHaveModule(serialport):        QT += serialport
+qtHaveModule(sql):               QT += sql
+qtHaveModule(svg):               QT += svg
+qtHaveModule(testlib):           QT += testlib
+qtHaveModule(uitools):           QT += uitools
+qtHaveModule(webkit):            QT += webkit
+qtHaveModule(webkitwidgets):     QT += webkitwidgets
+qtHaveModule(xml):               QT += xml
+qtHaveModule(xmlpatterns):       QT += xmlpatterns
+percent.target = %
+percent.commands = @echo -n "\$(\$(@))\ "
+QMAKE_EXTRA_TARGETS += percent
+EOF
+    $QMAKE $am_have_qt_pro -o $am_have_qt_makefile
+    QT_CXXFLAGS=`cd $am_have_qt_dir; make -s -f $am_have_qt_makefile CXXFLAGS INCPATH`
+    QT_LIBS=`cd $am_have_qt_dir; make -s -f $am_have_qt_makefile LIBS`
+    rm $am_have_qt_pro $am_have_qt_stash $am_have_qt_makefile
+    rmdir $am_have_qt_dir
+
+    # Look for specific tools in $PATH
+    QT_MOC=`which moc$am_have_qt_qmexe_suff`
+    QT_UIC=`which uic$am_have_qt_qmexe_suff`
+    QT_RCC=`which rcc$am_have_qt_qmexe_suff`
+    QT_LRELEASE=`which lrelease$am_have_qt_qmexe_suff`
+    QT_LUPDATE=`which lupdate$am_have_qt_qmexe_suff`
+
+    # Get Qt version from qmake
+    QT_DIR=`$QMAKE --version | grep -o -E /.+`
+
+    # All variables are defined, report the result
+    AC_MSG_RESULT([$have_qt:
+    QT_CXXFLAGS=$QT_CXXFLAGS
+    QT_DIR=$QT_DIR
+    QT_LIBS=$QT_LIBS
+    QT_UIC=$QT_UIC
+    QT_MOC=$QT_MOC
+    QT_RCC=$QT_RCC
+    QT_LRELEASE=$QT_LRELEASE
+    QT_LUPDATE=$QT_LUPDATE])
+  else
+    # Qt was not found
+    have_qt=no
+    QT_CXXFLAGS=
+    QT_DIR=
+    QT_LIBS=
+    QT_UIC=
+    QT_MOC=
+    QT_RCC=
+    QT_LRELEASE=
+    QT_LUPDATE=
+    AC_MSG_RESULT($have_qt)
+  fi
+  AC_SUBST(QT_CXXFLAGS)
+  AC_SUBST(QT_DIR)
+  AC_SUBST(QT_LIBS)
+  AC_SUBST(QT_UIC)
+  AC_SUBST(QT_MOC)
+  AC_SUBST(QT_RCC)
+  AC_SUBST(QT_LRELEASE)
+  AC_SUBST(QT_LUPDATE)
+  AC_SUBST(QMAKE)
+
+  #### Being paranoid:
+  if test x"$have_qt" = xyes; then
+    AC_MSG_CHECKING(correct functioning of Qt installation)
+    AC_CACHE_VAL(ax_cv_qt_test_result,
+    [
+      cat > ax_qt_test.h << EOF
+#include <qobject.h>
+class Test : public QObject
+{
+Q_OBJECT
+public:
+  Test() {}
+  ~Test() {}
+public slots:
+  void receive() {}
+signals:
+  void send();
+};
+EOF
+
+      cat > ax_qt_main.$ac_ext << EOF
+#include "ax_qt_test.h"
+#include <qapplication.h>
+int main( int argc, char **argv )
+{
+  QApplication app( argc, argv );
+  Test t;
+  QObject::connect( &t, SIGNAL(send()), &t, SLOT(receive()) );
+}
+EOF
+
+      ax_cv_qt_test_result="failure"
+      ax_try_1="$QT_MOC ax_qt_test.h -o moc_ax_qt_test.$ac_ext >/dev/null 2>/dev/null"
+      AC_TRY_EVAL(ax_try_1)
+      if test x"$ac_status" != x0; then
+        echo "$ax_err_1" >&AS_MESSAGE_LOG_FD
+        echo "configure: could not run $QT_MOC on:" >&AS_MESSAGE_LOG_FD
+        cat ax_qt_test.h >&AS_MESSAGE_LOG_FD
+      else
+        ax_try_2="$CXX $QT_CXXFLAGS -c $CXXFLAGS -o moc_ax_qt_test.o moc_ax_qt_test.$ac_ext >/dev/null 2>/dev/null"
+        AC_TRY_EVAL(ax_try_2)
+        if test x"$ac_status" != x0; then
+          echo "$ax_err_2" >&AS_MESSAGE_LOG_FD
+          echo "configure: could not compile:" >&AS_MESSAGE_LOG_FD
+          cat moc_ax_qt_test.$ac_ext >&AS_MESSAGE_LOG_FD
+        else
+          ax_try_3="$CXX $QT_CXXFLAGS -c $CXXFLAGS -o ax_qt_main.o ax_qt_main.$ac_ext >/dev/null 2>/dev/null"
+          AC_TRY_EVAL(ax_try_3)
+          if test x"$ac_status" != x0; then
+            echo "$ax_err_3" >&AS_MESSAGE_LOG_FD
+            echo "configure: could not compile:" >&AS_MESSAGE_LOG_FD
+            cat ax_qt_main.$ac_ext >&AS_MESSAGE_LOG_FD
+          else
+            ax_try_4="$CXX -o ax_qt_main ax_qt_main.o moc_ax_qt_test.o $QT_LIBS $LIBS >/dev/null 2>/dev/null"
+            AC_TRY_EVAL(ax_try_4)
+            if test x"$ac_status" != x0; then
+              echo "$ax_err_4" >&AS_MESSAGE_LOG_FD
+            else
+              ax_cv_qt_test_result="success"
+            fi
+          fi
+        fi
+      fi
+    ])dnl AC_CACHE_VAL ax_cv_qt_test_result
+    AC_MSG_RESULT([$ax_cv_qt_test_result])
+    if test x"$ax_cv_qt_test_result" = "xfailure"; then
+      AC_MSG_ERROR([Failed to find matching components of a complete
+                  Qt installation. Try using more options,
+                  see ./configure --help.])
+    fi
+
+    rm -f ax_qt_test.h moc_ax_qt_test.$ac_ext moc_ax_qt_test.o \
+          ax_qt_main.$ac_ext ax_qt_main.o ax_qt_main
+  fi
+])
--- a/rc/win32/version.rc.in	Tue Jan 16 15:22:29 2024 -0500
+++ b/rc/win32/version.rc.in	Fri Jan 19 00:24:02 2024 -0500
@@ -1,16 +1,14 @@
 #include "winver.h"
 
-#define VER_FILEVERSION     @minori_VERSION_MAJOR@,@minori_VERSION_MINOR@,@minori_VERSION_PATCH@,0
-#define VER_FILEVERSION_STR "@minori_VERSION_MAJOR@.@minori_VERSION_MINOR@.@minori_VERSION_PATCH@.0\0"
-
-#define VER_PRODUCTVERSION     @minori_VERSION_MAJOR@,@minori_VERSION_MINOR@,@minori_VERSION_PATCH@,0
-#define VER_PRODUCTVERSION_STR "@minori_VERSION_MAJOR@.@minori_VERSION_MINOR@.@minori_VERSION_PATCH@\0"
+#ifndef WRC_VERSION
+#   define WRC_VERSION 0,0,0,0
+#endif
 
 #define RC_INFO_STRING "@RC_INFO_STRING@\0"
 
 VS_VERSION_INFO VERSIONINFO
-	FILEVERSION VER_FILEVERSION
-	PRODUCTVERSION VER_PRODUCTVERSION
+	FILEVERSION WRC_VERSION
+	PRODUCTVERSION WRC_VERSION
 	FILEFLAGS 0x0L
 	FILEFLAGSMASK 0x3fL
 	FILEOS 0x00040004L
--- a/src/core/anime_db.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/core/anime_db.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -145,7 +145,8 @@
 	std::unordered_map<int, size_t> map;
 
 	static const auto process_title = [&map](const Anime& anime, const std::string& title, const std::string& needle) -> bool {
-		size_t ret = title.find(needle);
+		const std::string title_l = Strings::ToLower(title), needle_l = Strings::ToLower(needle);
+		size_t ret = title_l.find(needle_l);
 		if (ret == std::string::npos)
 			return false;
 
--- a/src/core/http.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/core/http.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -65,5 +65,3 @@
 }
 
 } // namespace HTTP
-
-#include "core/moc_http.cpp"
--- a/src/gui/dialog/about.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/dialog/about.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -107,5 +107,3 @@
 	win32::SetTitleBarsToBlack(session.config.theme.IsInDarkTheme());
 #endif
 }
-
-#include "gui/dialog/moc_about.cpp"
--- a/src/gui/dialog/information.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/dialog/information.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -307,5 +307,3 @@
 	win32::SetTitleBarsToBlack(session.config.theme.IsInDarkTheme());
 #endif
 }
-
-#include "gui/dialog/moc_information.cpp"
--- a/src/gui/dialog/settings.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/dialog/settings.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -131,5 +131,3 @@
 		full_layout->addWidget(button_box);
 	}
 }
-
-#include "gui/dialog/moc_settings.cpp"
--- a/src/gui/dialog/settings/library.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/dialog/settings/library.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -19,21 +19,6 @@
 #include <algorithm>
 #include <iostream>
 
-class DroppableListWidget : public QListWidget {
-	Q_OBJECT
-
-public:
-	explicit DroppableListWidget(QWidget* parent);
-
-signals:
-	void FilesDropped(QStringList list);
-
-protected:
-	void dragEnterEvent(QDragEnterEvent* event) override;
-	void dragMoveEvent(QDragMoveEvent* event) override;
-	void dropEvent(QDropEvent* event) override;
-};
-
 DroppableListWidget::DroppableListWidget(QWidget* parent) : QListWidget(parent) {
 	setAcceptDrops(true);
 }
@@ -129,9 +114,11 @@
 																			QDir::homePath(),
 																			QFileDialog::ShowDirsOnly
 																			| QFileDialog::DontResolveSymlinks);
-						if (dir.isEmpty())
+						const std::string s_dir = Strings::ToUtf8String(dir);
+						if (dir.isEmpty() || paths.count(s_dir))
 							return;
-						paths.insert(Strings::ToUtf8String(dir));
+
+						paths.insert(s_dir);
 						QListWidgetItem* item = new QListWidgetItem(listwidget);
 						item->setText(dir);
 					});
@@ -202,5 +189,3 @@
 	real_time_monitor = session.config.library.real_time_monitor;
 	AddTab(CreateFoldersWidget(), tr("Folder"));
 }
-
-#include "gui/dialog/settings/library.moc"
--- a/src/gui/pages/anime_list.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/pages/anime_list.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -455,8 +455,21 @@
 		sort_models[i]->setSortRole(Qt::UserRole);
 		sort_models[i]->setSortCaseSensitivity(Qt::CaseInsensitive);
 	}
+
 	tree_view->setModel(sort_models[0]);
 
+	/* Set column widths */
+	tree_view->setColumnWidth(AnimeListPageModel::AL_TITLE, 300);
+	tree_view->setColumnWidth(AnimeListPageModel::AL_PROGRESS, 200);
+	tree_view->setColumnWidth(AnimeListPageModel::AL_SCORE, 50);
+	tree_view->setColumnWidth(AnimeListPageModel::AL_AVG_SCORE, 55);
+	tree_view->setColumnWidth(AnimeListPageModel::AL_TYPE, 65);
+	tree_view->setColumnWidth(AnimeListPageModel::AL_SEASON, 95);
+	tree_view->setColumnWidth(AnimeListPageModel::AL_STARTED, 90);
+	tree_view->setColumnWidth(AnimeListPageModel::AL_COMPLETED, 90);
+	tree_view->setColumnWidth(AnimeListPageModel::AL_UPDATED, 100);
+	tree_view->setColumnWidth(AnimeListPageModel::AL_NOTES, 100);
+
 	QHBoxLayout* layout = new QHBoxLayout(tree_widget);
 	layout->addWidget(tree_view);
 	layout->setContentsMargins(0, 0, 0, 0);
@@ -487,5 +500,3 @@
 
 	Refresh();
 }
-
-#include "gui/pages/moc_anime_list.cpp"
--- a/src/gui/pages/history.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/pages/history.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -2,5 +2,3 @@
 
 HistoryPage::HistoryPage(QWidget* parent) : QWidget(parent) {
 }
-
-#include "gui/pages/moc_history.cpp"
--- a/src/gui/pages/now_playing.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/pages/now_playing.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -15,31 +15,6 @@
 
 namespace NowPlayingPages {
 
-class Default : public QWidget {
-		Q_OBJECT
-
-	public:
-		Default(QWidget* parent = nullptr);
-};
-
-class Playing : public QWidget {
-		Q_OBJECT
-
-	public:
-		Playing(QWidget* parent = nullptr);
-		void SetPlayingAnime(const Anime::Anime& anime, const anitomy::Elements& info);
-		int GetPlayingAnime();
-
-	private:
-		int _id = 0;
-		int _episode = 0;
-		std::unique_ptr<QWidget> _main = nullptr;
-		std::unique_ptr<TextWidgets::Title> _title = nullptr;
-		std::unique_ptr<AnimeInfoWidget> _info = nullptr;
-		std::unique_ptr<QWidget> _sidebar = nullptr;
-		std::unique_ptr<Poster> _poster = nullptr;
-};
-
 Default::Default(QWidget* parent) : QWidget(parent) {
 	QVBoxLayout* layout = new QVBoxLayout(this);
 	layout->setContentsMargins(0, 0, 0, 0);
@@ -129,6 +104,3 @@
 	stack->setCurrentIndex(1);
 	updateGeometry();
 }
-
-#include "gui/pages/moc_now_playing.cpp"
-#include "now_playing.moc"
--- a/src/gui/pages/search.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/pages/search.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -2,5 +2,3 @@
 
 SearchPage::SearchPage(QWidget* parent) : QWidget(parent) {
 }
-
-#include "gui/pages/moc_search.cpp"
--- a/src/gui/pages/seasons.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/pages/seasons.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -2,5 +2,3 @@
 
 SeasonsPage::SeasonsPage(QWidget* parent) : QWidget(parent) {
 }
-
-#include "gui/pages/moc_seasons.cpp"
--- a/src/gui/pages/statistics.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/pages/statistics.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -148,5 +148,3 @@
 	// UiUtils::SetPlainTextEditData(application_data, QString::number(session.uptime() / 1000));
 	_application->GetParagraph()->SetText(string);
 }
-
-#include "gui/pages/moc_statistics.cpp"
--- a/src/gui/pages/torrents.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/pages/torrents.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -63,14 +63,19 @@
 		const std::filesystem::path torrents_dir = Filesystem::GetTorrentsPath();
 		std::filesystem::create_directories(torrents_dir);
 
-		std::ofstream file(torrents_dir / filename, std::ofstream::out | std::ofstream::trunc);
-		if (!file)
-			return; // wat
+		HTTP::GetThread* thread = new HTTP::GetThread(link, {}, this);
+
+		connect(thread, &HTTP::GetThread::ReceivedData, this, [this, torrents_dir, filename](const QByteArray& data) {
+			std::ofstream file(torrents_dir / filename, std::ofstream::out | std::ofstream::trunc);
+			if (!file)
+				return; // wat
 
-		const QByteArray data = HTTP::Get(link);
-		file.write(data.data(), data.size());
+			file.write(data.data(), data.size());
+			file.close();
+		});
+		connect(thread, &HTTP::GetThread::finished, thread, &HTTP::GetThread::deleteLater);
 
-		file.close();
+		thread->start();
 	}
 }
 
@@ -186,10 +191,10 @@
 				case TL_EPISODE: return tr("Episode");
 				case TL_GROUP: return tr("Group");
 				case TL_SIZE: return tr("Size");
-				case TL_RESOLUTION: return tr("Resolution"); /* this is named "Video" in Taiga */
-				case TL_SEEDERS: return tr("Seeding"); /* named "S" in Taiga */
-				case TL_LEECHERS: return tr("Leeching"); /* named "L" in Taiga */
-				case TL_DOWNLOADERS: return tr("Downloading"); /* named "D" in Taiga */
+				case TL_RESOLUTION: return tr("Resolution"); /* "Video" in Taiga */
+				case TL_SEEDERS: return tr("S");
+				case TL_LEECHERS: return tr("L");
+				case TL_DOWNLOADS: return tr("D");
 				case TL_DESCRIPTION: return tr("Description");
 				case TL_FILENAME: return tr("Filename");
 				case TL_RELEASEDATE: return tr("Release date");
@@ -206,7 +211,7 @@
 				case TL_TITLE: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
 				case TL_SEEDERS:
 				case TL_LEECHERS:
-				case TL_DOWNLOADERS:
+				case TL_DOWNLOADS:
 				case TL_SIZE:
 				case TL_EPISODE:
 				case TL_RELEASEDATE: return QVariant(Qt::AlignRight | Qt::AlignVCenter);
@@ -251,7 +256,7 @@
 				case TL_RESOLUTION: return Strings::ToQString(item.GetResolution());
 				case TL_SEEDERS: return item.GetSeeders();
 				case TL_LEECHERS: return item.GetLeechers();
-				case TL_DOWNLOADERS: return item.GetDownloaders();
+				case TL_DOWNLOADS: return item.GetDownloads();
 				case TL_DESCRIPTION: return Strings::ToQString(item.GetDescription());
 				case TL_FILENAME: return Strings::ToQString(item.GetFilename());
 				case TL_RELEASEDATE: return item.GetDate();
@@ -289,7 +294,7 @@
 				case TL_TITLE: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
 				case TL_SEEDERS:
 				case TL_LEECHERS:
-				case TL_DOWNLOADERS:
+				case TL_DOWNLOADS:
 				case TL_SIZE:
 				case TL_EPISODE:
 				case TL_RELEASEDATE: return QVariant(Qt::AlignRight | Qt::AlignVCenter);
@@ -380,29 +385,30 @@
 			treeview->setModel(sort_model);
 		}
 
+		// set column sizes
+		treeview->setColumnWidth(TorrentsPageListModel::TL_TITLE,       240);
+		treeview->setColumnWidth(TorrentsPageListModel::TL_EPISODE,     60);
+		treeview->setColumnWidth(TorrentsPageListModel::TL_GROUP,       100);
+		treeview->setColumnWidth(TorrentsPageListModel::TL_SIZE,        70);
+		treeview->setColumnWidth(TorrentsPageListModel::TL_RESOLUTION,  100);
+		treeview->setColumnWidth(TorrentsPageListModel::TL_SEEDERS,     20);
+		treeview->setColumnWidth(TorrentsPageListModel::TL_LEECHERS,    20);
+		treeview->setColumnWidth(TorrentsPageListModel::TL_DOWNLOADS,   20);
+		treeview->setColumnWidth(TorrentsPageListModel::TL_DESCRIPTION, 200);
+		treeview->setColumnWidth(TorrentsPageListModel::TL_FILENAME,    200);
+		treeview->setColumnWidth(TorrentsPageListModel::TL_RELEASEDATE, 190);
+
 		layout->addWidget(treeview);
 	}
 }
 
 void TorrentsPage::DownloadSelection() {
-	/* we only want one of these at a time, because if we don't
-	 * we have the possibility of going into Multithreading Hell
-	*/
-	static QThread* thread = nullptr;
-
-	if (!model || thread)
+	if (!model)
 		return;
 
 	const QItemSelection selection = sort_model->mapSelectionToSource(treeview->selectionModel()->selection());
 
-	thread = QThread::create([this, selection] {
-		model->DownloadTorrents(selection);
-	});
-
-	connect(thread, &QThread::finished, thread, &QThread::deleteLater);
-	connect(thread, &QThread::finished, this, [&] { thread = nullptr; });
-
-	thread->start();
+	model->DownloadTorrents(selection);
 }
 
 void TorrentsPage::Refresh() {
@@ -423,5 +429,3 @@
 
 	thread->start();
 }
-
-#include "gui/pages/moc_torrents.cpp"
--- a/src/gui/theme.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/theme.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -133,10 +133,6 @@
 #ifdef WIN32 /* fuck you Qt 6 */
 			pal.setColor(QPalette::Window, QColor(0xF0, 0xF0, 0xF0));
 #endif
-			pal.setColor(QPalette::WindowText, Qt::black);
-			pal.setColor(QPalette::ToolTipText, Qt::black);
-			pal.setColor(QPalette::Text, Qt::black);
-			pal.setColor(QPalette::ButtonText, Qt::black);
 			qApp->setPalette(pal);
 
 			qApp->setStyleSheet("");
--- a/src/gui/widgets/anime_info.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/widgets/anime_info.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -48,5 +48,3 @@
 
 	updateGeometry();
 }
-
-#include "gui/widgets/moc_anime_info.cpp"
--- a/src/gui/widgets/clickable_label.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/widgets/clickable_label.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -12,5 +12,3 @@
 void ClickableLabel::mousePressEvent(QMouseEvent*) {
 	emit clicked();
 }
-
-#include "gui/widgets/moc_clickable_label.cpp"
--- a/src/gui/widgets/optional_date.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/widgets/optional_date.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -62,5 +62,3 @@
 QCheckBox* OptionalDate::GetCheckBox() {
 	return _checkbox;
 }
-
-#include "gui/widgets/moc_optional_date.cpp"
--- a/src/gui/widgets/poster.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/widgets/poster.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -36,16 +36,10 @@
 
 void Poster::SetAnime(const Anime::Anime& anime) {
 	{
-		QByteArray* ba = new QByteArray;
+		HTTP::GetThread* thread = new HTTP::GetThread(anime.GetPosterUrl(), {}, this);
 
-		QThread* thread = QThread::create([ba, anime] {
-			*ba = HTTP::Get(anime.GetPosterUrl(), {});
-		});
-
-		connect(thread, &QThread::finished, this, [this, ba] {
-			ImageDownloadFinished(*ba);
-			delete ba;
-		});
+		connect(thread, &HTTP::GetThread::ReceivedData, this, &Poster::ImageDownloadFinished);
+		connect(thread, &HTTP::GetThread::finished, thread, &HTTP::GetThread::deleteLater);
 
 		thread->start();
 	}
@@ -70,5 +64,3 @@
 void Poster::resizeEvent(QResizeEvent*) {
 	RenderToLabel();
 }
-
-#include "gui/widgets/moc_poster.cpp"
--- a/src/gui/widgets/sidebar.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/widgets/sidebar.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -101,5 +101,3 @@
 		unsetCursor();
 	QListView::mouseMoveEvent(event);
 }
-
-#include "gui/widgets/moc_sidebar.cpp"
--- a/src/gui/widgets/text.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/widgets/text.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -248,5 +248,3 @@
 }
 
 } // namespace TextWidgets
-
-#include "gui/widgets/moc_text.cpp"
--- a/src/gui/window.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/gui/window.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -93,8 +93,10 @@
 			anitomy.Parse(Strings::ToWstring(file));
 
 			const auto& elements = anitomy.elements();
+			const std::string title = Strings::ToUtf8String(elements.get(anitomy::kElementAnimeTitle));
+			std::cout << title << std::endl;
 
-			int id = Anime::db.GetAnimeFromTitle(Strings::ToUtf8String(elements.get(anitomy::kElementAnimeTitle)));
+			int id = Anime::db.GetAnimeFromTitle(title);
 			if (id <= 0)
 				continue;
 
@@ -160,6 +162,7 @@
 void MainWindow::CreateBars() {
 	QMenuBar* menubar = new QMenuBar(this);
 	QMenu* folder_menu; /* this is used twice, so we declare it here */
+	QAction* sync_action;
 
 	{
 		/* File */
@@ -231,8 +234,14 @@
 		QMenu* menu = menubar->addMenu(tr("&Services"));
 		{
 			{
-				QAction* action = menu->addAction(tr("Synchronize &list"), [this] { AsyncSynchronize(stack.get()); });
-				action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S));
+				sync_action = menu->addAction(tr("Synchronize &list"));
+
+				connect(sync_action, &QAction::triggered, this, [this, sync_action]{
+					AsyncSynchronize(sync_action, stack.get());
+				});
+
+				sync_action->setIcon(QIcon(":/icons/24x24/arrow-circle-double-135.png"));
+				sync_action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S));
 			}
 
 //			menu->addSeparator();
@@ -300,6 +309,7 @@
 			QAction* action = menu->addAction(tr("&Settings"), [this] {
 				SettingsDialog dialog(this);
 				dialog.exec();
+				CreateBars();
 			});
 			action->setMenuRole(QAction::PreferencesRole);
 		}
@@ -408,8 +418,7 @@
 	{
 		/* Toolbar */
 		QToolBar* toolbar = new QToolBar(this);
-		toolbar->addAction(QIcon(":/icons/24x24/arrow-circle-double-135.png"), tr("&Synchronize"),
-						   [this] { AsyncSynchronize(stack.get()); });
+		toolbar->addAction(sync_action);
 
 		toolbar->addSeparator();
 
@@ -465,6 +474,7 @@
 		toolbar->addAction(QIcon(":/icons/24x24/gear.png"), tr("S&ettings"), [this] {
 			SettingsDialog dialog(this);
 			dialog.exec();
+			CreateBars();
 		});
 		addToolBar(toolbar);
 	}
@@ -474,7 +484,7 @@
 	this->setCentralWidget(page);
 }
 
-void MainWindow::AsyncSynchronize(QStackedWidget* stack) {
+void MainWindow::AsyncSynchronize(QAction* action, QStackedWidget* stack) {
 	if (session.config.service == Anime::Services::NONE) {
 		QMessageBox msg;
 		msg.setWindowTitle(tr("Error synchronizing with service!"));
@@ -488,9 +498,12 @@
 			dialog.exec();
 		}
 	}
-	QThreadPool::globalInstance()->start([stack] {
+
+	QThreadPool::globalInstance()->start([stack, action] {
+		action->setEnabled(false);
 		Services::Synchronize();
 		reinterpret_cast<AnimeListPage*>(stack->widget(static_cast<int>(Pages::ANIME_LIST)))->Refresh();
+		action->setEnabled(true);
 	});
 }
 
@@ -534,5 +547,3 @@
 	Anime::db.SaveDatabaseToDisk();
 	event->accept();
 }
-
-#include "gui/moc_window.cpp"
--- a/src/main.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/main.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -1,19 +1,19 @@
 #include "core/session.h"
 #include "core/anime_db.h"
+#include "core/strings.h"
 #include "gui/window.h"
 #include <QApplication>
 #include <QStyleFactory>
 #include <QTranslator>
 #include <QLocale>
 
+#include <iostream>
+
 Session session;
 
 int main(int argc, char** argv) {
 	QApplication app(argc, argv);
-#if !(defined(WIN32) || defined(MACOSX))
-	/* force Fusion */
-	app.setStyle("Fusion");
-#endif
+	app.setAttribute(Qt::AA_DontShowIconsInMenus, true);
 
 	session.config.Load();
 	session.config.locale.RefreshAvailableLocales();
--- a/src/sys/glib/dark_theme.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/sys/glib/dark_theme.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -6,24 +6,24 @@
 namespace glib {
 
 bool IsInDarkTheme() {
-	GSettings* settings = g_settings_new("org.gnome.desktop.interface");
+	GSettings* settings = ::g_settings_new("org.gnome.desktop.interface");
 	if (!settings)
 		return false;
 
-	GVariant* val = g_settings_get_value(settings, "color-scheme");
+	GVariant* val = ::g_settings_get_value(settings, "color-scheme");
 	if (!val)
 		return false;
 
 	const gchar* str;
-	g_variant_get(val, "&s", &str); /* should not be freed */
+	::g_variant_get(val, "&s", &str); /* should not be freed */
 	if (!str) /* how */
 		return false;
 
 	bool success = !std::strcmp(str, "prefer-dark");
 
 	/* unref these */
-	g_variant_unref(val);
-	g_object_unref(settings);
+	::g_variant_unref(val);
+	::g_object_unref(settings);
 
 	return success;
 }
--- a/src/track/media.cc	Tue Jan 16 15:22:29 2024 -0500
+++ b/src/track/media.cc	Fri Jan 19 00:24:02 2024 -0500
@@ -11,6 +11,8 @@
 #include <vector>
 #include <filesystem>
 
+#include <iostream>
+
 #include "animia.h"
 
 namespace Track {