Upgraded code to switch to C++17. Tested on Debian Buster

This commit is contained in:
emeric
2019-09-10 13:07:06 +02:00
parent 178c400067
commit 2c5917235a
82 changed files with 723 additions and 755 deletions
+157 -159
View File
@@ -1,8 +1,8 @@
Installation Instructions Installation Instructions
************************* *************************
Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software
Inc. Foundation, Inc.
Copying and distribution of this file, with or without modification, Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright are permitted in any medium without royalty provided the copyright
@@ -12,97 +12,96 @@ without warranty of any kind.
Basic Installation Basic Installation
================== ==================
Briefly, the shell command `./configure && make && make install' Briefly, the shell command './configure && make && make install'
should configure, build, and install this package. The following should configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for more-detailed instructions are generic; see the 'README' file for
instructions specific to this package. Some packages provide this instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented 'INSTALL' file but do not implement all of the features documented
below. The lack of an optional feature in a given package is not below. The lack of an optional feature in a given package is not
necessarily a bug. More recommendations for GNU packages can be found necessarily a bug. More recommendations for GNU packages can be found
in *note Makefile Conventions: (standards)Makefile Conventions. in *note Makefile Conventions: (standards)Makefile Conventions.
The `configure' shell script attempts to guess correct values for The 'configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package. those values to create a 'Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent It may also create one or more '.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that definitions. Finally, it creates a shell script 'config.status' that
you can run in the future to recreate the current configuration, and a you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for file 'config.log' containing compiler output (useful mainly for
debugging `configure'). debugging 'configure').
It can also use an optional file (typically called `config.cache' It can also use an optional file (typically called 'config.cache' and
and enabled with `--cache-file=config.cache' or simply `-C') that saves enabled with '--cache-file=config.cache' or simply '-C') that saves the
the results of its tests to speed up reconfiguring. Caching is results of its tests to speed up reconfiguring. Caching is disabled by
disabled by default to prevent problems with accidental use of stale default to prevent problems with accidental use of stale cache files.
cache files.
If you need to do unusual things to compile the package, please try If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail to figure out how 'configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can diffs or instructions to the address given in the 'README' so they can
be considered for the next release. If you are using the cache, and at be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you some point 'config.cache' contains results you don't want to keep, you
may remove or edit it. may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create The file 'configure.ac' (or 'configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if 'configure' by a program called 'autoconf'. You need 'configure.ac' if
you want to change it or regenerate `configure' using a newer version you want to change it or regenerate 'configure' using a newer version of
of `autoconf'. 'autoconf'.
The simplest way to compile this package is: The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type 1. 'cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. './configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints Running 'configure' might take a while. While running, it prints
some messages telling which features it is checking for. some messages telling which features it is checking for.
2. Type `make' to compile the package. 2. Type 'make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with 3. Optionally, type 'make check' to run any self-tests that come with
the package, generally using the just-built uninstalled binaries. the package, generally using the just-built uninstalled binaries.
4. Type `make install' to install the programs and any data files and 4. Type 'make install' to install the programs and any data files and
documentation. When installing into a prefix owned by root, it is documentation. When installing into a prefix owned by root, it is
recommended that the package be configured and built as a regular recommended that the package be configured and built as a regular
user, and only the `make install' phase executed with root user, and only the 'make install' phase executed with root
privileges. privileges.
5. Optionally, type `make installcheck' to repeat any self-tests, but 5. Optionally, type 'make installcheck' to repeat any self-tests, but
this time using the binaries in their final installed location. this time using the binaries in their final installed location.
This target does not install anything. Running this target as a This target does not install anything. Running this target as a
regular user, particularly if the prior `make install' required regular user, particularly if the prior 'make install' required
root privileges, verifies that the installation completed root privileges, verifies that the installation completed
correctly. correctly.
6. You can remove the program binaries and object files from the 6. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the source code directory by typing 'make clean'. To also remove the
files that `configure' created (so you can compile the package for files that 'configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is a different kind of computer), type 'make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly also a 'make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came all sorts of other programs in order to regenerate files that came
with the distribution. with the distribution.
7. Often, you can also type `make uninstall' to remove the installed 7. Often, you can also type 'make uninstall' to remove the installed
files again. In practice, not all packages have tested that files again. In practice, not all packages have tested that
uninstallation works correctly, even though it is required by the uninstallation works correctly, even though it is required by the
GNU Coding Standards. GNU Coding Standards.
8. Some packages, particularly those that use Automake, provide `make 8. Some packages, particularly those that use Automake, provide 'make
distcheck', which can by used by developers to test that all other distcheck', which can by used by developers to test that all other
targets like `make install' and `make uninstall' work correctly. targets like 'make install' and 'make uninstall' work correctly.
This target is generally not run by end users. This target is generally not run by end users.
Compilers and Options Compilers and Options
===================== =====================
Some systems require unusual options for compilation or linking that Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help' the 'configure' script does not know about. Run './configure --help'
for details on some of the pertinent environment variables. for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters You can give 'configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here by setting variables in the command line or in the environment. Here is
is an example: an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix ./configure CC=c99 CFLAGS=-g LIBS=-lposix
@@ -113,21 +112,21 @@ Compiling For Multiple Architectures
You can compile the package for more than one kind of computer at the You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the own directory. To do this, you can use GNU 'make'. 'cd' to the
directory where you want the object files and executables to go and run directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the the 'configure' script. 'configure' automatically checks for the source
source code in the directory that `configure' is in and in `..'. This code in the directory that 'configure' is in and in '..'. This is known
is known as a "VPATH" build. as a "VPATH" build.
With a non-GNU `make', it is safer to compile the package for one With a non-GNU 'make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before installed the package for one architecture, use 'make distclean' before
reconfiguring for another architecture. reconfiguring for another architecture.
On MacOS X 10.5 and later systems, you can create libraries and On MacOS X 10.5 and later systems, you can create libraries and
executables that work on multiple system types--known as "fat" or executables that work on multiple system types--known as "fat" or
"universal" binaries--by specifying multiple `-arch' options to the "universal" binaries--by specifying multiple '-arch' options to the
compiler but only a single `-arch' option to the preprocessor. Like compiler but only a single '-arch' option to the preprocessor. Like
this: this:
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
@@ -136,105 +135,104 @@ this:
This is not guaranteed to produce working output in all cases, you This is not guaranteed to produce working output in all cases, you
may have to build one architecture at a time and combine the results may have to build one architecture at a time and combine the results
using the `lipo' tool if you have problems. using the 'lipo' tool if you have problems.
Installation Names Installation Names
================== ==================
By default, `make install' installs the package's commands under By default, 'make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You '/usr/local/bin', include files under '/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving can specify an installation prefix other than '/usr/local' by giving
`configure' the option `--prefix=PREFIX', where PREFIX must be an 'configure' the option '--prefix=PREFIX', where PREFIX must be an
absolute file name. absolute file name.
You can specify separate installation prefixes for You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses pass the option '--exec-prefix=PREFIX' to 'configure', the package uses
PREFIX as the prefix for installing programs and libraries. PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix. Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular options like '--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories kinds of files. Run 'configure --help' for a list of the directories
you can set and what kinds of files go in them. In general, the you can set and what kinds of files go in them. In general, the default
default for these options is expressed in terms of `${prefix}', so that for these options is expressed in terms of '${prefix}', so that
specifying just `--prefix' will affect all of the other directory specifying just '--prefix' will affect all of the other directory
specifications that were not explicitly provided. specifications that were not explicitly provided.
The most portable way to affect installation locations is to pass the The most portable way to affect installation locations is to pass the
correct locations to `configure'; however, many packages provide one or correct locations to 'configure'; however, many packages provide one or
both of the following shortcuts of passing variable assignments to the both of the following shortcuts of passing variable assignments to the
`make install' command line to change installation locations without 'make install' command line to change installation locations without
having to reconfigure or recompile. having to reconfigure or recompile.
The first method involves providing an override variable for each The first method involves providing an override variable for each
affected directory. For example, `make install affected directory. For example, 'make install
prefix=/alternate/directory' will choose an alternate location for all prefix=/alternate/directory' will choose an alternate location for all
directory configuration variables that were expressed in terms of directory configuration variables that were expressed in terms of
`${prefix}'. Any directories that were specified during `configure', '${prefix}'. Any directories that were specified during 'configure',
but not in terms of `${prefix}', must each be overridden at install but not in terms of '${prefix}', must each be overridden at install time
time for the entire installation to be relocated. The approach of for the entire installation to be relocated. The approach of makefile
makefile variable overrides for each directory variable is required by variable overrides for each directory variable is required by the GNU
the GNU Coding Standards, and ideally causes no recompilation. Coding Standards, and ideally causes no recompilation. However, some
However, some platforms have known limitations with the semantics of platforms have known limitations with the semantics of shared libraries
shared libraries that end up requiring recompilation when using this that end up requiring recompilation when using this method, particularly
method, particularly noticeable in packages that use GNU Libtool. noticeable in packages that use GNU Libtool.
The second method involves providing the `DESTDIR' variable. For The second method involves providing the 'DESTDIR' variable. For
example, `make install DESTDIR=/alternate/directory' will prepend example, 'make install DESTDIR=/alternate/directory' will prepend
`/alternate/directory' before all installation names. The approach of '/alternate/directory' before all installation names. The approach of
`DESTDIR' overrides is not required by the GNU Coding Standards, and 'DESTDIR' overrides is not required by the GNU Coding Standards, and
does not work on platforms that have drive letters. On the other hand, does not work on platforms that have drive letters. On the other hand,
it does better at avoiding recompilation issues, and works well even it does better at avoiding recompilation issues, and works well even
when some directory options were not specified in terms of `${prefix}' when some directory options were not specified in terms of '${prefix}'
at `configure' time. at 'configure' time.
Optional Features Optional Features
================= =================
If the package supports it, you can cause programs to be installed If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the with an extra prefix or suffix on their names by giving 'configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'.
Some packages pay attention to `--enable-FEATURE' options to Some packages pay attention to '--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package. 'configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE They may also pay attention to '--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The is something like 'gnu-as' or 'x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the 'README' should mention any '--enable-' and '--with-' options that the
package recognizes. package recognizes.
For packages that use the X Window System, `configure' can usually For packages that use the X Window System, 'configure' can usually
find the X include and library files automatically, but if it doesn't, find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and you can use the 'configure' options '--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations. '--x-libraries=DIR' to specify their locations.
Some packages offer the ability to configure how verbose the Some packages offer the ability to configure how verbose the
execution of `make' will be. For these packages, running `./configure execution of 'make' will be. For these packages, running './configure
--enable-silent-rules' sets the default to minimal output, which can be --enable-silent-rules' sets the default to minimal output, which can be
overridden with `make V=1'; while running `./configure overridden with 'make V=1'; while running './configure
--disable-silent-rules' sets the default to verbose, which can be --disable-silent-rules' sets the default to verbose, which can be
overridden with `make V=0'. overridden with 'make V=0'.
Particular systems Particular systems
================== ==================
On HP-UX, the default C compiler is not ANSI C compatible. If GNU On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC
CC is not installed, it is recommended to use the following options in is not installed, it is recommended to use the following options in
order to use an ANSI C compiler: order to use an ANSI C compiler:
./configure CC="cc -Ae -D_XOPEN_SOURCE=500" ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
and if that doesn't work, install pre-built binaries of GCC for HP-UX. and if that doesn't work, install pre-built binaries of GCC for HP-UX.
HP-UX `make' updates targets which have the same time stamps as HP-UX 'make' updates targets which have the same time stamps as their
their prerequisites, which makes it generally unusable when shipped prerequisites, which makes it generally unusable when shipped generated
generated files such as `configure' are involved. Use GNU `make' files such as 'configure' are involved. Use GNU 'make' instead.
instead.
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
parse its `<wchar.h>' header file. The option `-nodtk' can be used as parse its '<wchar.h>' header file. The option '-nodtk' can be used as a
a workaround. If GNU CC is not installed, it is therefore recommended workaround. If GNU CC is not installed, it is therefore recommended to
to try try
./configure CC="cc" ./configure CC="cc"
@@ -242,26 +240,26 @@ and if that doesn't work, try
./configure CC="cc -nodtk" ./configure CC="cc -nodtk"
On Solaris, don't put `/usr/ucb' early in your `PATH'. This On Solaris, don't put '/usr/ucb' early in your 'PATH'. This
directory contains several dysfunctional programs; working variants of directory contains several dysfunctional programs; working variants of
these programs are available in `/usr/bin'. So, if you need `/usr/ucb' these programs are available in '/usr/bin'. So, if you need '/usr/ucb'
in your `PATH', put it _after_ `/usr/bin'. in your 'PATH', put it _after_ '/usr/bin'.
On Haiku, software installed for all users goes in `/boot/common', On Haiku, software installed for all users goes in '/boot/common',
not `/usr/local'. It is recommended to use the following options: not '/usr/local'. It is recommended to use the following options:
./configure --prefix=/boot/common ./configure --prefix=/boot/common
Specifying the System Type Specifying the System Type
========================== ==========================
There may be some features `configure' cannot figure out There may be some features 'configure' cannot figure out
automatically, but needs to determine by the type of machine the package automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints _same_ architectures, 'configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system '--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form: type, such as 'sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM CPU-COMPANY-SYSTEM
@@ -270,101 +268,101 @@ where SYSTEM can have one of these forms:
OS OS
KERNEL-OS KERNEL-OS
See the file `config.sub' for the possible values of each field. If See the file 'config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't 'config.sub' isn't included in this package, then this package doesn't
need to know the machine type. need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will use the option '--target=TYPE' to select the type of system they will
produce code for. produce code for.
If you want to _use_ a cross compiler, that generates code for a If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will "host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'. eventually be run) with '--host=TYPE'.
Sharing Defaults Sharing Defaults
================ ================
If you want to set default values for `configure' scripts to share, If you want to set default values for 'configure' scripts to share,
you can create a site shell script called `config.site' that gives you can create a site shell script called 'config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'. default values for variables like 'CC', 'cache_file', and 'prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then 'configure' looks for 'PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the 'PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script. 'CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script. A warning: not all 'configure' scripts look for a site script.
Defining Variables Defining Variables
================== ==================
Variables not defined in a site shell script can be set in the Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run environment passed to 'configure'. However, some packages may run
configure again during the build, and the customized values of these configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example: them in the 'configure' command line, using 'VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc ./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is causes the specified 'gcc' to be used as the C compiler (unless it is
overridden in the site shell script). overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an
an Autoconf limitation. Until the limitation is lifted, you can use Autoconf limitation. Until the limitation is lifted, you can use this
this workaround: workaround:
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation 'configure' Invocation
====================== ======================
`configure' recognizes the following options to control how it 'configure' recognizes the following options to control how it
operates. operates.
`--help' '--help'
`-h' '-h'
Print a summary of all of the options to `configure', and exit. Print a summary of all of the options to 'configure', and exit.
`--help=short' '--help=short'
`--help=recursive' '--help=recursive'
Print a summary of the options unique to this package's Print a summary of the options unique to this package's
`configure', and exit. The `short' variant lists options used 'configure', and exit. The 'short' variant lists options used only
only in the top level, while the `recursive' variant lists options in the top level, while the 'recursive' variant lists options also
also present in any nested packages. present in any nested packages.
`--version' '--version'
`-V' '-V'
Print the version of Autoconf used to generate the `configure' Print the version of Autoconf used to generate the 'configure'
script, and exit. script, and exit.
`--cache-file=FILE' '--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE, Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to traditionally 'config.cache'. FILE defaults to '/dev/null' to
disable caching. disable caching.
`--config-cache' '--config-cache'
`-C' '-C'
Alias for `--cache-file=config.cache'. Alias for '--cache-file=config.cache'.
`--quiet' '--quiet'
`--silent' '--silent'
`-q' '-q'
Do not print messages saying which checks are being made. To Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error suppress all normal output, redirect it to '/dev/null' (any error
messages will still be shown). messages will still be shown).
`--srcdir=DIR' '--srcdir=DIR'
Look for the package's source code in directory DIR. Usually Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically. 'configure' can determine that directory automatically.
`--prefix=DIR' '--prefix=DIR'
Use DIR as the installation prefix. *note Installation Names:: Use DIR as the installation prefix. *note Installation Names:: for
for more details, including other options available for fine-tuning more details, including other options available for fine-tuning the
the installation locations. installation locations.
`--no-create' '--no-create'
`-n' '-n'
Run the configure checks, but stop before creating any output Run the configure checks, but stop before creating any output
files. files.
`configure' also accepts some other, not widely useful, options. Run 'configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details. 'configure --help' for more details.
+3 -1
View File
@@ -48,9 +48,11 @@ __Note__: since _LMS_ stores hashed and salted passwords, it cannot handle the _
## Installation ## Installation
__Note__: this installation process and the default values of the configuration file and the _systemd_ service file have been written for _Debian Stretch_. Therefore, you may have to adapt commands and/or paths in order to fit to your distribution. __Note__: this installation process and the default values of the configuration file and the _systemd_ service file have been written for _Debian Buster_. Therefore, you may have to adapt commands and/or paths in order to fit to your distribution.
### Build dependencies ### Build dependencies
__Note__: a C++17 compiler is needed to compile _LMS_
```sh ```sh
apt-get install g++ autoconf automake libboost-filesystem-dev libboost-system-dev libavcodec-dev libavutil-dev libavformat-dev libav-tools libmagick++-dev libpstreams-dev libconfig++-dev libpstreams-dev ffmpeg libtag1-dev apt-get install g++ autoconf automake libboost-filesystem-dev libboost-system-dev libavcodec-dev libavutil-dev libavformat-dev libav-tools libmagick++-dev libpstreams-dev libconfig++-dev libpstreams-dev ffmpeg libtag1-dev
``` ```
+5 -6
View File
@@ -5,7 +5,6 @@ AC_CONFIG_HEADER(src/config/config.h)
AC_LANG_CPLUSPLUS AC_LANG_CPLUSPLUS
# Checks for programs
AC_PROG_CXX AC_PROG_CXX
PKG_CHECK_MODULES(IMAGEMAGICKXX, "ImageMagick++", [ HAVE_IMAGEMAGICKXX=yes ], [ ]) PKG_CHECK_MODULES(IMAGEMAGICKXX, "ImageMagick++", [ HAVE_IMAGEMAGICKXX=yes ], [ ])
@@ -20,6 +19,11 @@ AC_CHECK_HEADERS([Wt/WApplication.h pstreams/pstream.h],
[], [],
[AC_MSG_ERROR([Header not found or unusable !])]) [AC_MSG_ERROR([Header not found or unusable !])])
AC_CHECK_LIB([stdc++fs],
[main],
,
[AC_MSG_ERROR([lib filesystem not found!])])
AC_CHECK_LIB([pthread], AC_CHECK_LIB([pthread],
[pthread_rwlock_unlock], [pthread_rwlock_unlock],
, ,
@@ -66,11 +70,6 @@ AC_CHECK_LIB([boost_system],
, ,
[AC_MSG_ERROR([libboost_system not found!])]) [AC_MSG_ERROR([libboost_system not found!])])
AC_CHECK_LIB( [boost_filesystem],
[main],
,
[AC_MSG_ERROR([libboost_filesystem not found!])])
AC_CHECK_LIB( [tag], AC_CHECK_LIB( [tag],
[main], [main],
, ,
+3 -3
View File
@@ -25,8 +25,8 @@ lms_SOURCES = \
$(srcdir)/database/Artist.hpp \ $(srcdir)/database/Artist.hpp \
$(srcdir)/database/Cluster.cpp \ $(srcdir)/database/Cluster.cpp \
$(srcdir)/database/Cluster.hpp \ $(srcdir)/database/Cluster.hpp \
$(srcdir)/database/Database.cpp \ $(srcdir)/database/Db.cpp \
$(srcdir)/database/Database.hpp \ $(srcdir)/database/Db.hpp \
$(srcdir)/database/TrackArtistLink.cpp \ $(srcdir)/database/TrackArtistLink.cpp \
$(srcdir)/database/TrackArtistLink.hpp \ $(srcdir)/database/TrackArtistLink.hpp \
$(srcdir)/database/TrackFeatures.cpp \ $(srcdir)/database/TrackFeatures.cpp \
@@ -147,6 +147,6 @@ lms_SOURCES = \
$(srcdir)/utils/Utils.cpp \ $(srcdir)/utils/Utils.cpp \
$(srcdir)/utils/Utils.hpp $(srcdir)/utils/Utils.hpp
lms_CXXFLAGS=-std=c++14 -Wall -I$(srcdir)/ui $(MAGICKXX_CFLAGS) -D_REENTRANT lms_CXXFLAGS=-std=c++17 -I$(srcdir)/ui $(MAGICKXX_CFLAGS) -D_REENTRANT
lms_LDADD=$(MAGICKXX_LIBS) lms_LDADD=$(MAGICKXX_LIBS)
+4 -4
View File
@@ -27,7 +27,7 @@
namespace API::Subsonic namespace API::Subsonic
{ {
boost::optional<Id> std::optional<Id>
IdFromString(const std::string& id) IdFromString(const std::string& id)
{ {
if (id == "root") if (id == "root")
@@ -35,7 +35,7 @@ IdFromString(const std::string& id)
std::vector<std::string> values {splitString(id, "-")}; std::vector<std::string> values {splitString(id, "-")};
if (values.size() != 2) if (values.size() != 2)
return boost::none; return std::nullopt;
Id res; Id res;
@@ -49,11 +49,11 @@ IdFromString(const std::string& id)
else if (type == "pl") else if (type == "pl")
res.type = Id::Type::Playlist; res.type = Id::Type::Playlist;
else else
return boost::none; return std::nullopt;
auto optId {readAs<Database::IdType>(values[1])}; auto optId {readAs<Database::IdType>(values[1])};
if (!optId) if (!optId)
return boost::none; return std::nullopt;
res.value = *optId; res.value = *optId;
+2 -2
View File
@@ -17,7 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <boost/optional.hpp> #include <optional>
#include "database/Types.hpp" #include "database/Types.hpp"
@@ -39,7 +39,7 @@ struct Id
Database::IdType value {}; Database::IdType value {};
}; };
boost::optional<Id> IdFromString(const std::string& id); std::optional<Id> IdFromString(const std::string& id);
std::string IdToString(const Id& id); std::string IdToString(const Id& id);
} // namespace API::Subsonic } // namespace API::Subsonic
+38 -37
View File
@@ -31,6 +31,7 @@
#include "cover/CoverArtGrabber.hpp" #include "cover/CoverArtGrabber.hpp"
#include "database/Artist.hpp" #include "database/Artist.hpp"
#include "database/Cluster.hpp" #include "database/Cluster.hpp"
#include "database/Db.hpp"
#include "database/Release.hpp" #include "database/Release.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
#include "database/TrackList.hpp" #include "database/TrackList.hpp"
@@ -53,14 +54,14 @@ static const Av::Encoding transcodeEncoding {Av::Encoding::MP3};
static const std::string reportedStarredDate {"2000-01-01T00:00:00"}; static const std::string reportedStarredDate {"2000-01-01T00:00:00"};
template<> template<>
boost::optional<API::Subsonic::Id> std::optional<API::Subsonic::Id>
readAs(const std::string& str) readAs(const std::string& str)
{ {
return API::Subsonic::IdFromString(str); return API::Subsonic::IdFromString(str);
} }
template<> template<>
boost::optional<bool> std::optional<bool>
readAs(const std::string& str) readAs(const std::string& str)
{ {
if (str == "true") if (str == "true")
@@ -82,31 +83,31 @@ struct ClientVersion
} }
template<> template<>
boost::optional<API::Subsonic::ClientVersion> std::optional<API::Subsonic::ClientVersion>
readAs(const std::string& str) readAs(const std::string& str)
{ {
// Expects "X.Y.Z" // Expects "X.Y.Z"
const auto numbers {splitString(str, ".")}; const auto numbers {splitString(str, ".")};
if (numbers.size() < 2 || numbers.size() > 3) if (numbers.size() < 2 || numbers.size() > 3)
return boost::none; return std::nullopt;
API::Subsonic::ClientVersion version; API::Subsonic::ClientVersion version;
auto number {readAs<unsigned>(numbers[0])}; auto number {readAs<unsigned>(numbers[0])};
if (!number) if (!number)
return boost::none; return std::nullopt;
version.major = *number; version.major = *number;
number = {readAs<unsigned>(numbers[1])}; number = {readAs<unsigned>(numbers[1])};
if (!number) if (!number)
return boost::none; return std::nullopt;
version.minor = *number; version.minor = *number;
if (numbers.size() == 3) if (numbers.size() == 3)
{ {
number = {readAs<unsigned>(numbers[2])}; number = {readAs<unsigned>(numbers[2])};
if (!number) if (!number)
return boost::none; return std::nullopt;
version.patch = *number; version.patch = *number;
} }
@@ -132,12 +133,12 @@ struct RequestContext
std::string userName; std::string userName;
}; };
using SessionMap = std::map<Database::Database*, std::unique_ptr<Session>>; using SessionMap = std::map<Db*, std::unique_ptr<Session>>;
static std::map<std::thread::id, SessionMap> dbSessions; static std::map<std::thread::id, SessionMap> dbSessions;
static static
Session& Session&
getOrCreateDbSession(Database::Database& db) getOrCreateDbSession(Db& db)
{ {
static std::mutex mutex; static std::mutex mutex;
@@ -152,12 +153,12 @@ getOrCreateDbSession(Database::Database& db)
if (it != std::end(*sessionMap)) if (it != std::end(*sessionMap))
return *it->second; return *it->second;
auto res {sessionMap->emplace(&db, db.createSession())}; auto res { sessionMap->try_emplace(&db, db.createSession())};
assert(res.second); assert(res.second);
LMS_LOG(API_SUBSONIC, DEBUG) << "Created db session"; LMS_LOG(API_SUBSONIC, DEBUG) << "Created db session";
return *(res.first->second); return *res.first->second;
} }
static static
@@ -209,7 +210,7 @@ getMandatoryMultiParametersAs(const Wt::Http::ParameterMap& parameterMap, const
} }
template<typename T> template<typename T>
boost::optional<T> std::optional<T>
getParameterAs(const Wt::Http::ParameterMap& parameterMap, const std::string& param) getParameterAs(const Wt::Http::ParameterMap& parameterMap, const std::string& param)
{ {
std::vector<T> params {getMultiParametersAs<T>(parameterMap, param)}; std::vector<T> params {getMultiParametersAs<T>(parameterMap, param)};
@@ -277,7 +278,7 @@ struct MediaRetrievalResult
Wt::cpp17::any continuationData; Wt::cpp17::any continuationData;
}; };
SubsonicResource::SubsonicResource(Database::Database& db) SubsonicResource::SubsonicResource(Db& db)
: _db {db} : _db {db}
{ {
} }
@@ -571,7 +572,7 @@ userToResponseNode(const User::pointer& user)
static static
Response Response
handlePingRequest(RequestContext& context) handlePingRequest(RequestContext&)
{ {
return Response::createOkResponse(); return Response::createOkResponse();
} }
@@ -731,12 +732,12 @@ handleDeleteUserRequest(RequestContext& context)
static static
Response Response
handleGetLicenseRequest(RequestContext& context) handleGetLicenseRequest(RequestContext&)
{ {
Response response {Response::createOkResponse()}; Response response {Response::createOkResponse()};
Response::Node& licenseNode {response.createNode("license")}; Response::Node& licenseNode {response.createNode("license")};
licenseNode.setAttribute("licenseExpires", "2019-09-03T14:46:43"); licenseNode.setAttribute("licenseExpires", "2025-09-03T14:46:43");
licenseNode.setAttribute("email", "foo@bar.com"); licenseNode.setAttribute("email", "foo@bar.com");
licenseNode.setAttribute("valid", "true"); licenseNode.setAttribute("valid", "true");
@@ -748,7 +749,7 @@ Response
handleGetRandomSongsRequest(RequestContext& context) handleGetRandomSongsRequest(RequestContext& context)
{ {
// Optional params // Optional params
std::size_t size {getParameterAs<std::size_t>(context.parameters, "size").get_value_or(50)}; std::size_t size {getParameterAs<std::size_t>(context.parameters, "size").value_or(50)};
size = std::min(size, std::size_t {500}); size = std::min(size, std::size_t {500});
auto transaction {context.dbSession.createSharedTransaction()}; auto transaction {context.dbSession.createSharedTransaction()};
@@ -776,8 +777,8 @@ handleGetAlbumListRequestCommon(const RequestContext& context, bool id3)
std::string type {getMandatoryParameterAs<std::string>(context.parameters, "type")}; std::string type {getMandatoryParameterAs<std::string>(context.parameters, "type")};
// Optional params // Optional params
std::size_t size {getParameterAs<std::size_t>(context.parameters, "size").get_value_or(10)}; std::size_t size {getParameterAs<std::size_t>(context.parameters, "size").value_or(10)};
std::size_t offset {getParameterAs<std::size_t>(context.parameters, "offset").get_value_or(0)}; std::size_t offset {getParameterAs<std::size_t>(context.parameters, "offset").value_or(0)};
std::vector<Release::pointer> releases; std::vector<Release::pointer> releases;
@@ -932,7 +933,7 @@ handleGetArtistInfoRequestCommon(RequestContext& context, bool id3)
throw BadParameterGenericError {"id"}; throw BadParameterGenericError {"id"};
// Optional params // Optional params
std::size_t count {getParameterAs<std::size_t>(context.parameters, "count").get_value_or(20)}; std::size_t count {getParameterAs<std::size_t>(context.parameters, "count").value_or(20)};
Response response {Response::createOkResponse()}; Response response {Response::createOkResponse()};
Response::Node& artistInfoNode {response.createNode(id3 ? "artistInfo2" : "artistInfo")}; Response::Node& artistInfoNode {response.createNode(id3 ? "artistInfo2" : "artistInfo")};
@@ -1075,7 +1076,7 @@ handleGetMusicDirectoryRequest(RequestContext& context)
static static
Response Response
handleGetMusicFoldersRequest(RequestContext& context) handleGetMusicFoldersRequest(RequestContext&)
{ {
Response response {Response::createOkResponse()}; Response response {Response::createOkResponse()};
Response::Node& musicFoldersNode {response.createNode("musicFolders")}; Response::Node& musicFoldersNode {response.createNode("musicFolders")};
@@ -1142,7 +1143,7 @@ handleGetSimilarSongsRequestCommon(RequestContext& context, bool id3)
throw BadParameterGenericError {"id"}; throw BadParameterGenericError {"id"};
// Optional params // Optional params
std::size_t count {getParameterAs<std::size_t>(context.parameters, "count").get_value_or(50)}; std::size_t count {getParameterAs<std::size_t>(context.parameters, "count").value_or(50)};
auto similarArtistsId {getService<Similarity::Searcher>()->getSimilarArtists(context.dbSession, id.value, 5)}; auto similarArtistsId {getService<Similarity::Searcher>()->getSimilarArtists(context.dbSession, id.value, 5)};
@@ -1248,7 +1249,7 @@ handleGetStarred2Request(RequestContext& context)
static static
Response::Node Response::Node
tracklistToResponseNode(const TrackList::pointer& tracklist, Session& dbSession) tracklistToResponseNode(const TrackList::pointer& tracklist, Session&)
{ {
Response::Node playlistNode; Response::Node playlistNode;
@@ -1322,10 +1323,10 @@ handleGetSongsByGenreRequest(RequestContext& context)
std::string genre {getMandatoryParameterAs<std::string>(context.parameters, "genre")}; std::string genre {getMandatoryParameterAs<std::string>(context.parameters, "genre")};
// Optional params // Optional params
std::size_t size {getParameterAs<std::size_t>(context.parameters, "count").get_value_or(10)}; std::size_t size {getParameterAs<std::size_t>(context.parameters, "count").value_or(10)};
size = std::min(size, std::size_t {500}); size = std::min(size, std::size_t {500});
std::size_t offset {getParameterAs<std::size_t>(context.parameters, "offset").get_value_or(0)}; std::size_t offset {getParameterAs<std::size_t>(context.parameters, "offset").value_or(0)};
auto transaction {context.dbSession.createSharedTransaction()}; auto transaction {context.dbSession.createSharedTransaction()};
@@ -1398,12 +1399,12 @@ handleSearchRequestCommon(RequestContext& context, bool id3)
std::vector<std::string> keywords {splitString(query, " ")}; std::vector<std::string> keywords {splitString(query, " ")};
// Optional params // Optional params
std::size_t artistCount {getParameterAs<std::size_t>(context.parameters, "artistCount").get_value_or(20)}; std::size_t artistCount {getParameterAs<std::size_t>(context.parameters, "artistCount").value_or(20)};
std::size_t artistOffset {getParameterAs<std::size_t>(context.parameters, "artistOffset").get_value_or(0)}; std::size_t artistOffset {getParameterAs<std::size_t>(context.parameters, "artistOffset").value_or(0)};
std::size_t albumCount {getParameterAs<std::size_t>(context.parameters, "albumCount").get_value_or(20)}; std::size_t albumCount {getParameterAs<std::size_t>(context.parameters, "albumCount").value_or(20)};
std::size_t albumOffset {getParameterAs<std::size_t>(context.parameters, "albumOffset").get_value_or(0)}; std::size_t albumOffset {getParameterAs<std::size_t>(context.parameters, "albumOffset").value_or(0)};
std::size_t songCount {getParameterAs<std::size_t>(context.parameters, "songCount").get_value_or(20)}; std::size_t songCount {getParameterAs<std::size_t>(context.parameters, "songCount").value_or(20)};
std::size_t songOffset {getParameterAs<std::size_t>(context.parameters, "songOffset").get_value_or(0)}; std::size_t songOffset {getParameterAs<std::size_t>(context.parameters, "songOffset").value_or(0)};
auto transaction {context.dbSession.createSharedTransaction()}; auto transaction {context.dbSession.createSharedTransaction()};
@@ -1585,8 +1586,8 @@ Response
handleUpdateUserRequest(RequestContext& context) handleUpdateUserRequest(RequestContext& context)
{ {
std::string username {getMandatoryParameterAs<std::string>(context.parameters, "username")}; std::string username {getMandatoryParameterAs<std::string>(context.parameters, "username")};
boost::optional<std::string> password {getParameterAs<std::string>(context.parameters, "password")}; std::optional<std::string> password {getParameterAs<std::string>(context.parameters, "password")};
boost::optional<Bitrate> maxBitRate {getParameterAs<Bitrate>(context.parameters, "maxBitRate")}; std::optional<Bitrate> maxBitRate {getParameterAs<Bitrate>(context.parameters, "maxBitRate")};
User::PasswordHash hash; User::PasswordHash hash;
if (password) if (password)
@@ -1693,9 +1694,9 @@ createTranscoder(RequestContext& context)
Id id {getMandatoryParameterAs<Id>(context.parameters, "id")}; Id id {getMandatoryParameterAs<Id>(context.parameters, "id")};
// Optional params // Optional params
boost::optional<std::size_t> maxBitRate {getParameterAs<std::size_t>(context.parameters, "maxBitRate")}; std::optional<std::size_t> maxBitRate {getParameterAs<std::size_t>(context.parameters, "maxBitRate")};
boost::filesystem::path trackPath; std::filesystem::path trackPath;
{ {
auto transaction {context.dbSession.createSharedTransaction()}; auto transaction {context.dbSession.createSharedTransaction()};
@@ -1771,7 +1772,7 @@ handleGetCoverArt(RequestContext& context, Wt::Http::ResponseContinuation*)
// Mandatory params // Mandatory params
Id id {getMandatoryParameterAs<Id>(context.parameters, "id")}; Id id {getMandatoryParameterAs<Id>(context.parameters, "id")};
std::size_t size {getParameterAs<std::size_t>(context.parameters, "size").get_value_or(256)}; std::size_t size {getParameterAs<std::size_t>(context.parameters, "size").value_or(256)};
size = clamp(size, std::size_t {32}, std::size_t {1024}); size = clamp(size, std::size_t {32}, std::size_t {1024});
MediaRetrievalResult res; MediaRetrievalResult res;
@@ -1861,7 +1862,7 @@ SubsonicResource::handleRequest(const Wt::Http::Request &request, Wt::Http::Resp
const Wt::Http::ParameterMap& parameters {request.getParameterMap()}; const Wt::Http::ParameterMap& parameters {request.getParameterMap()};
// Optional parameters // Optional parameters
ResponseFormat format {getParameterAs<std::string>(parameters, "f").get_value_or("xml") == "json" ? ResponseFormat::json : ResponseFormat::xml}; const ResponseFormat format {getParameterAs<std::string>(parameters, "f").value_or("xml") == "json" ? ResponseFormat::json : ResponseFormat::xml};
try try
{ {
+6 -5
View File
@@ -18,12 +18,13 @@
*/ */
#pragma once #pragma once
#include <boost/optional.hpp>
#include <Wt/WResource.h> #include <Wt/WResource.h>
#include <Wt/Http/Response.h> #include <Wt/Http/Response.h>
#include "database/Database.hpp" namespace Database
{
class Db;
}
namespace API::Subsonic namespace API::Subsonic
{ {
@@ -31,7 +32,7 @@ namespace API::Subsonic
class SubsonicResource final : public Wt::WResource class SubsonicResource final : public Wt::WResource
{ {
public: public:
SubsonicResource(Database::Database& db); SubsonicResource(Database::Db& db);
~SubsonicResource(); ~SubsonicResource();
static std::string getPath() { return "/rest/"; } static std::string getPath() { return "/rest/"; }
@@ -39,7 +40,7 @@ class SubsonicResource final : public Wt::WResource
void handleRequest(const Wt::Http::Request &request, Wt::Http::Response &response) override; void handleRequest(const Wt::Http::Request &request, Wt::Http::Response &response) override;
Database::Database& _db; Database::Db& _db;
}; };
} // namespace } // namespace
+3 -3
View File
@@ -62,7 +62,7 @@ AuthTokenService::createAuthToken(Database::Session& session, Database::IdType u
} }
static static
boost::optional<AuthTokenService::AuthTokenProcessResult::AuthTokenInfo> std::optional<AuthTokenService::AuthTokenProcessResult::AuthTokenInfo>
processAuthToken(Database::Session& session, const std::string& secret) processAuthToken(Database::Session& session, const std::string& secret)
{ {
const std::string secretHash {sha1Function.compute(secret, {})}; const std::string secretHash {sha1Function.compute(secret, {})};
@@ -71,12 +71,12 @@ processAuthToken(Database::Session& session, const std::string& secret)
Database::AuthToken::pointer authToken {Database::AuthToken::getByValue(session, secretHash)}; Database::AuthToken::pointer authToken {Database::AuthToken::getByValue(session, secretHash)};
if (!authToken) if (!authToken)
return boost::none; return std::nullopt;
if (authToken->getExpiry() < Wt::WDateTime::currentDateTime()) if (authToken->getExpiry() < Wt::WDateTime::currentDateTime())
{ {
authToken.remove(); authToken.remove();
return boost::none; return std::nullopt;
} }
LMS_LOG(UI, DEBUG) << "Found auth token for user '" << authToken->getUser()->getLoginName() << "'!"; LMS_LOG(UI, DEBUG) << "Found auth token for user '" << authToken->getUser()->getLoginName() << "'!";
+3 -3
View File
@@ -21,9 +21,9 @@
#pragma once #pragma once
#include <optional>
#include <string> #include <string>
#include <boost/optional.hpp>
#include <boost/asio/ip/address.hpp> #include <boost/asio/ip/address.hpp>
#include "LoginThrottler.hpp" #include "LoginThrottler.hpp"
@@ -69,8 +69,8 @@ namespace Auth {
Wt::WDateTime expiry; Wt::WDateTime expiry;
}; };
State state; State state {State::NotFound};
boost::optional<AuthTokenInfo> authTokenInfo; std::optional<AuthTokenInfo> authTokenInfo {};
}; };
// Removed if found // Removed if found
+2 -2
View File
@@ -83,7 +83,7 @@ LoginThrottler::onGoodClientAttempt(const boost::asio::ip::address& address)
{ {
const boost::asio::ip::address clientAddress {getAddressToThrottle(address)}; const boost::asio::ip::address clientAddress {getAddressToThrottle(address)};
_attemptsInfo.erase(address); _attemptsInfo.erase(clientAddress);
} }
bool bool
@@ -91,7 +91,7 @@ LoginThrottler::isClientThrottled(const boost::asio::ip::address& address) const
{ {
const boost::asio::ip::address clientAddress {getAddressToThrottle(address)}; const boost::asio::ip::address clientAddress {getAddressToThrottle(address)};
auto it {_attemptsInfo.find(address)}; auto it {_attemptsInfo.find(clientAddress)};
if (it == _attemptsInfo.end()) if (it == _attemptsInfo.end())
return false; return false;
+1 -2
View File
@@ -23,7 +23,6 @@
#include <string> #include <string>
#include <boost/optional.hpp>
#include <boost/asio/ip/address.hpp> #include <boost/asio/ip/address.hpp>
#include "LoginThrottler.hpp" #include "LoginThrottler.hpp"
@@ -81,7 +80,7 @@ namespace Auth {
}; };
State state; State state;
boost::optional<AuthTokenInfo> authTokenInfo; std::optional<AuthTokenInfo> authTokenInfo;
}; };
// Removed if found // Removed if found
+4 -12
View File
@@ -43,16 +43,8 @@ MediaFileException::MediaFileException(int avError)
{ {
} }
void AvInit()
{
/* register all the codecs */
avcodec_register_all();
av_register_all();
LMS_LOG(AV, INFO) << "avcodec version = " << avcodec_version();
}
MediaFile::MediaFile(const std::filesystem::path& p)
MediaFile::MediaFile(const boost::filesystem::path& p)
: _p {p} : _p {p}
{ {
int error = avformat_open_input(&_context, _p.string().c_str(), nullptr, nullptr); int error = avformat_open_input(&_context, _p.string().c_str(), nullptr, nullptr);
@@ -155,7 +147,7 @@ MediaFile::getStreamInfo() const
return res; return res;
} }
boost::optional<std::size_t> std::optional<std::size_t>
MediaFile::getBestStream() const MediaFile::getBestStream() const
{ {
int res = av_find_best_stream(_context, int res = av_find_best_stream(_context,
@@ -166,7 +158,7 @@ MediaFile::getBestStream() const
0); 0);
if (res < 0) if (res < 0)
return boost::none; return std::nullopt;
return res; return res;
} }
@@ -238,7 +230,7 @@ MediaFile::getAttachedPictures(std::size_t nbMaxPictures) const
return pictures; return pictures;
} }
boost::optional<MediaFileFormat> guessMediaFileFormat(const boost::filesystem::path& file) std::optional<MediaFileFormat> guessMediaFileFormat(const std::filesystem::path& file)
{ {
AVOutputFormat* format {av_guess_format(NULL,file.string().c_str(),NULL)}; AVOutputFormat* format {av_guess_format(NULL,file.string().c_str(),NULL)};
if (!format || !format->name) if (!format || !format->name)
+10 -12
View File
@@ -29,14 +29,12 @@ extern "C"
#include <libavutil/error.h> #include <libavutil/error.h>
} }
#include <vector>
#include <string>
#include <cstdint>
#include <map>
#include <chrono> #include <chrono>
#include <filesystem>
#include <boost/optional.hpp> #include <map>
#include <boost/filesystem/path.hpp> #include <optional>
#include <string>
#include <vector>
#include "AvTypes.hpp" #include "AvTypes.hpp"
@@ -66,7 +64,7 @@ class MediaFileException : public AvException
class MediaFile class MediaFile
{ {
public: public:
MediaFile(const boost::filesystem::path& p); MediaFile(const std::filesystem::path& p);
~MediaFile(); ~MediaFile();
MediaFile(const MediaFile&) = delete; MediaFile(const MediaFile&) = delete;
@@ -76,19 +74,19 @@ class MediaFile
std::string getFormatName() const; std::string getFormatName() const;
const boost::filesystem::path& getPath() const {return _p;}; const std::filesystem::path& getPath() const {return _p;};
std::chrono::milliseconds getDuration() const; std::chrono::milliseconds getDuration() const;
std::map<std::string, std::string> getMetaData(void); std::map<std::string, std::string> getMetaData(void);
std::vector<StreamInfo> getStreamInfo() const; std::vector<StreamInfo> getStreamInfo() const;
boost::optional<std::size_t> getBestStream() const; // none if failure/unknown std::optional<std::size_t> getBestStream() const; // none if failure/unknown
bool hasAttachedPictures(void) const; bool hasAttachedPictures(void) const;
std::vector<Picture> getAttachedPictures(std::size_t nbMaxPictures) const; std::vector<Picture> getAttachedPictures(std::size_t nbMaxPictures) const;
private: private:
boost::filesystem::path _p; std::filesystem::path _p;
AVFormatContext* _context {}; AVFormatContext* _context {};
}; };
@@ -99,7 +97,7 @@ struct MediaFileFormat
std::string format; std::string format;
}; };
boost::optional<MediaFileFormat> guessMediaFileFormat(const boost::filesystem::path& file); std::optional<MediaFileFormat> guessMediaFileFormat(const std::filesystem::path& file);
} // namespace Av } // namespace Av
+47 -47
View File
@@ -37,16 +37,15 @@ static const std::vector<std::string> execNames =
"ffmpeg", "ffmpeg",
}; };
static std::mutex transcoderMutex; static std::filesystem::path avConvPath = std::filesystem::path();
static boost::filesystem::path avConvPath = boost::filesystem::path();
static std::atomic<size_t> globalId = {0}; static std::atomic<size_t> globalId = {0};
void void
Transcoder::init() Transcoder::init()
{ {
for (std::string execName : execNames) for (const std::string& execName : execNames)
{ {
boost::filesystem::path p = searchExecPath(execName); const std::filesystem::path p {searchExecPath(execName)};
if (!p.empty()) if (!p.empty())
{ {
avConvPath = p; avConvPath = p;
@@ -60,11 +59,10 @@ Transcoder::init()
throw AvException("Cannot find any transcoder binary!"); throw AvException("Cannot find any transcoder binary!");
} }
Transcoder::Transcoder(boost::filesystem::path filePath, TranscodeParameters parameters) Transcoder::Transcoder(const std::filesystem::path& filePath, const TranscodeParameters& parameters)
: _filePath(filePath), : _filePath {filePath},
_parameters(parameters), _parameters {parameters},
_isComplete(false), _id {globalId++}
_id(globalId++)
{ {
} }
@@ -72,84 +70,84 @@ Transcoder::Transcoder(boost::filesystem::path filePath, TranscodeParameters par
bool bool
Transcoder::start() Transcoder::start()
{ {
if (!boost::filesystem::exists(_filePath)) if (!std::filesystem::exists(_filePath))
return false; return false;
else if (!boost::filesystem::is_regular( _filePath) ) else if (!std::filesystem::is_regular_file( _filePath) )
return false; return false;
LMS_LOG_TRANSCODE(INFO) << "Transcoding file '" << _filePath.string() << "'"; LMS_LOG_TRANSCODE(INFO) << "Transcoding file '" << _filePath.string() << "'";
std::vector<std::string> args; std::vector<std::string> args;
args.push_back(avConvPath.string()); args.emplace_back(avConvPath.string());
// Make sure we do not produce anything in the stderr output // Make sure we do not produce anything in the stderr output
// in order not to block the whole forked process // in order not to block the whole forked process
args.push_back("-loglevel"); args.emplace_back("-loglevel");
args.push_back("quiet"); args.emplace_back("quiet");
args.push_back("-nostdin"); args.emplace_back("-nostdin");
// input Offset // input Offset
if (_parameters.offset) if (_parameters.offset)
{ {
args.push_back("-ss"); args.emplace_back("-ss");
args.push_back(std::to_string((*_parameters.offset).count())); args.emplace_back(std::to_string((*_parameters.offset).count()));
} }
// Input file // Input file
args.push_back("-i"); args.emplace_back("-i");
args.push_back(_filePath.string()); args.emplace_back(_filePath.string());
// Stream mapping, if set // Stream mapping, if set
if (_parameters.stream) if (_parameters.stream)
{ {
args.push_back("-map"); args.emplace_back("-map");
args.push_back("0:" + std::to_string(*_parameters.stream)); args.emplace_back("0:" + std::to_string(*_parameters.stream));
} }
if (_parameters.stripMetadata) if (_parameters.stripMetadata)
{ {
// Strip metadata // Strip metadata
args.push_back("-map_metadata"); args.emplace_back("-map_metadata");
args.push_back("-1"); args.emplace_back("-1");
} }
// Skip video flows (including covers) // Skip video flows (including covers)
args.push_back("-vn"); args.emplace_back("-vn");
// Codecs and formats // Codecs and formats
if (_parameters.encoding) if (_parameters.encoding)
{ {
// Output bitrates // Output bitrates
args.push_back("-b:a"); args.emplace_back("-b:a");
args.push_back(std::to_string(_parameters.bitrate)); args.emplace_back(std::to_string(_parameters.bitrate));
switch (*_parameters.encoding) switch (*_parameters.encoding)
{ {
case Encoding::MP3: case Encoding::MP3:
args.push_back("-f"); args.emplace_back("-f");
args.push_back("mp3"); args.emplace_back("mp3");
break; break;
case Encoding::OGG_OPUS: case Encoding::OGG_OPUS:
args.push_back("-acodec"); args.emplace_back("-acodec");
args.push_back("libopus"); args.emplace_back("libopus");
args.push_back("-f"); args.emplace_back("-f");
args.push_back("ogg"); args.emplace_back("ogg");
break; break;
case Encoding::OGG_VORBIS: case Encoding::OGG_VORBIS:
args.push_back("-acodec"); args.emplace_back("-acodec");
args.push_back("libvorbis"); args.emplace_back("libvorbis");
args.push_back("-f"); args.emplace_back("-f");
args.push_back("ogg"); args.emplace_back("ogg");
break; break;
case Encoding::WEBM_VORBIS: case Encoding::WEBM_VORBIS:
args.push_back("-acodec"); args.emplace_back("-acodec");
args.push_back("libvorbis"); args.emplace_back("libvorbis");
args.push_back("-f"); args.emplace_back("-f");
args.push_back("webm"); args.emplace_back("webm");
break; break;
@@ -169,23 +167,25 @@ Transcoder::start()
return false; return false;
} }
args.push_back("-acodec"); args.emplace_back("-acodec");
args.push_back("copy"); args.emplace_back("copy");
args.push_back("-f"); args.emplace_back("-f");
args.push_back(mediaFileFormat->format); args.emplace_back(mediaFileFormat->format);
_outputMimeType = mediaFileFormat->mimeType; _outputMimeType = mediaFileFormat->mimeType;
} }
args.push_back("pipe:1"); args.emplace_back("pipe:1");
LMS_LOG_TRANSCODE(DEBUG) << "Dumping args (" << args.size() << ")"; LMS_LOG_TRANSCODE(DEBUG) << "Dumping args (" << args.size() << ")";
for (std::string arg : args) for (const std::string& arg : args)
LMS_LOG_TRANSCODE(DEBUG) << "Arg = '" << arg << "'"; LMS_LOG_TRANSCODE(DEBUG) << "Arg = '" << arg << "'";
// make sure only one thread is executing this part of code // make sure only one thread is executing this part of code
{ {
std::lock_guard<std::mutex> lock(transcoderMutex); static std::mutex transcoderMutex;
std::lock_guard<std::mutex> lock {transcoderMutex};
_child = std::make_shared<redi::ipstream>(); _child = std::make_shared<redi::ipstream>();
+13 -16
View File
@@ -20,12 +20,11 @@
#pragma once #pragma once
#include <chrono> #include <chrono>
#include <filesystem>
#include <optional>
#include <pstreams/pstream.h> #include <pstreams/pstream.h>
#include <boost/filesystem.hpp>
#include <boost/optional.hpp>
#include "AvTypes.hpp" #include "AvTypes.hpp"
namespace Av { namespace Av {
@@ -34,10 +33,10 @@ namespace Av {
struct TranscodeParameters struct TranscodeParameters
{ {
boost::optional<Encoding> encoding; // If not set, no transcoding is performed std::optional<Encoding> encoding; // If not set, no transcoding is performed
std::size_t bitrate {128000}; std::size_t bitrate {128000};
boost::optional<std::size_t> stream; // Id of the stream to be transcoded (auto detect by default) std::optional<std::size_t> stream; // Id of the stream to be transcoded (auto detect by default)
boost::optional<std::chrono::seconds> offset {}; std::optional<std::chrono::seconds> offset {};
bool stripMetadata {true}; bool stripMetadata {true};
}; };
@@ -46,12 +45,13 @@ class Transcoder
public: public:
static void init(); static void init();
Transcoder(boost::filesystem::path file, TranscodeParameters parameters); Transcoder(const std::filesystem::path& file, const TranscodeParameters& parameters);
~Transcoder(); ~Transcoder();
// non copyable
Transcoder(const Transcoder&) = delete; Transcoder(const Transcoder&) = delete;
Transcoder& operator=(const Transcoder&) = delete; Transcoder& operator=(const Transcoder&) = delete;
Transcoder(Transcoder&&) = delete;
Transcoder& operator=(Transcoder&&) = delete;
bool start(); bool start();
const std::string& getOutputMimeType() const { return _outputMimeType; } const std::string& getOutputMimeType() const { return _outputMimeType; }
@@ -60,18 +60,15 @@ class Transcoder
const TranscodeParameters& getParameters() const { return _parameters; } const TranscodeParameters& getParameters() const { return _parameters; }
private: private:
Transcoder(); const std::filesystem::path _filePath;
const TranscodeParameters _parameters;
boost::filesystem::path _filePath;
TranscodeParameters _parameters;
std::shared_ptr<redi::ipstream> _child; std::shared_ptr<redi::ipstream> _child;
bool _isComplete = false; bool _isComplete {};
std::size_t _total = 0; std::size_t _total {};
std::size_t _id; const std::size_t _id {};
std::string _outputMimeType; std::string _outputMimeType;
}; };
-1
View File
@@ -20,7 +20,6 @@
#pragma once #pragma once
#include <string> #include <string>
#include <boost/filesystem.hpp>
#include "utils/Exception.hpp" #include "utils/Exception.hpp"
+29 -29
View File
@@ -19,8 +19,6 @@
#include "CoverArtGrabber.hpp" #include "CoverArtGrabber.hpp"
#include <boost/filesystem.hpp>
#include "av/AvInfo.hpp" #include "av/AvInfo.hpp"
#include "database/Release.hpp" #include "database/Release.hpp"
@@ -32,9 +30,9 @@
namespace { namespace {
bool bool
isFileSupported(const boost::filesystem::path& file, const std::vector<boost::filesystem::path> extensions) isFileSupported(const std::filesystem::path& file, const std::vector<std::filesystem::path> extensions)
{ {
boost::filesystem::path fileExtension = file.extension(); std::filesystem::path fileExtension = file.extension();
for (auto extension : extensions) for (auto extension : extensions)
{ {
@@ -54,7 +52,7 @@ Grabber::Grabber()
} }
void void
Grabber::setDefaultCover(boost::filesystem::path p) Grabber::setDefaultCover(const std::filesystem::path& p)
{ {
if (!_defaultCover.load(p)) if (!_defaultCover.load(p))
throw LmsException("Cannot read default cover file '" + p.string() + "'"); throw LmsException("Cannot read default cover file '" + p.string() + "'");
@@ -84,7 +82,7 @@ Grabber::getDefaultCover(std::size_t size)
return it->second; return it->second;
} }
static boost::optional<Image::Image> static std::optional<Image::Image>
getFromAvMediaFile(const Av::MediaFile& input) getFromAvMediaFile(const Av::MediaFile& input)
{ {
std::vector<Image::Image> res; std::vector<Image::Image> res;
@@ -100,11 +98,11 @@ getFromAvMediaFile(const Av::MediaFile& input)
} }
LMS_LOG(COVER, DEBUG) << "No cover found in media file '" << input.getPath().string() << "'"; LMS_LOG(COVER, DEBUG) << "No cover found in media file '" << input.getPath().string() << "'";
return boost::none; return std::nullopt;
} }
boost::optional<Image::Image> std::optional<Image::Image>
Grabber::getFromDirectory(const boost::filesystem::path& p) const Grabber::getFromDirectory(const std::filesystem::path& p) const
{ {
for (auto coverPath : getCoverPaths(p)) for (auto coverPath : getCoverPaths(p))
{ {
@@ -117,33 +115,33 @@ Grabber::getFromDirectory(const boost::filesystem::path& p) const
} }
LMS_LOG(COVER, DEBUG) << "No cover found in directory '" << p.string() << "'"; LMS_LOG(COVER, DEBUG) << "No cover found in directory '" << p.string() << "'";
return boost::none; return std::nullopt;
} }
std::vector<boost::filesystem::path> std::vector<std::filesystem::path>
Grabber::getCoverPaths(const boost::filesystem::path& directoryPath) const Grabber::getCoverPaths(const std::filesystem::path& directoryPath) const
{ {
std::vector<boost::filesystem::path> res; std::vector<std::filesystem::path> res;
boost::system::error_code ec; std::error_code ec;
// TODO handle preferred file names // TODO handle preferred file names
boost::filesystem::directory_iterator itPath(directoryPath, ec); std::filesystem::directory_iterator itPath(directoryPath, ec);
boost::filesystem::directory_iterator itEnd; std::filesystem::directory_iterator itEnd;
while (!ec && itPath != itEnd) while (!ec && itPath != itEnd)
{ {
boost::filesystem::path path = *itPath; std::filesystem::path path = *itPath;
itPath.increment(ec); itPath.increment(ec);
if (!boost::filesystem::is_regular(path)) if (!std::filesystem::is_regular_file(path))
continue; continue;
if (!isFileSupported(path, _fileExtensions)) if (!isFileSupported(path, _fileExtensions))
continue; continue;
if (boost::filesystem::file_size(path) > _maxFileSize) if (std::filesystem::file_size(path) > _maxFileSize)
{ {
LMS_LOG(COVER, INFO) << "Cover file '" << path.string() << " is too big (" << boost::filesystem::file_size(path) << "), limit is " << _maxFileSize; LMS_LOG(COVER, INFO) << "Cover file '" << path.string() << " is too big (" << std::filesystem::file_size(path) << "), limit is " << _maxFileSize;
continue; continue;
} }
@@ -153,8 +151,8 @@ Grabber::getCoverPaths(const boost::filesystem::path& directoryPath) const
return res; return res;
} }
boost::optional<Image::Image> std::optional<Image::Image>
Grabber::getFromTrack(const boost::filesystem::path& p) const Grabber::getFromTrack(const std::filesystem::path& p) const
{ {
try try
{ {
@@ -165,7 +163,7 @@ Grabber::getFromTrack(const boost::filesystem::path& p) const
catch (Av::MediaFileException& e) catch (Av::MediaFileException& e)
{ {
LMS_LOG(COVER, ERROR) << "Cannot get covers from track " << p.string() << ": " << e.what(); LMS_LOG(COVER, ERROR) << "Cannot get covers from track " << p.string() << ": " << e.what();
return boost::none; return std::nullopt;
} }
} }
@@ -174,10 +172,10 @@ Grabber::getFromTrack(Database::Session& dbSession, Database::IdType trackId, st
{ {
using namespace Database; using namespace Database;
boost::optional<Image::Image> cover; std::optional<Image::Image> cover;
bool hasCover {}; bool hasCover {};
boost::filesystem::path trackPath; std::filesystem::path trackPath;
{ {
auto transaction {dbSession.createSharedTransaction()}; auto transaction {dbSession.createSharedTransaction()};
@@ -208,9 +206,9 @@ Grabber::getFromTrack(Database::Session& dbSession, Database::IdType trackId, st
Image::Image Image::Image
Grabber::getFromRelease(Database::Session& session, Database::IdType releaseId, std::size_t size) Grabber::getFromRelease(Database::Session& session, Database::IdType releaseId, std::size_t size)
{ {
boost::optional<Image::Image> cover; std::optional<Image::Image> cover;
boost::optional<Database::IdType> trackId; std::optional<Database::IdType> trackId;
{ {
auto transaction {session.createSharedTransaction()}; auto transaction {session.createSharedTransaction()};
@@ -239,7 +237,8 @@ Grabber::getFromTrack(Database::Session& session, Database::IdType trackId, Imag
{ {
const Image::Image cover {getFromTrack(session, trackId, size)}; const Image::Image cover {getFromTrack(session, trackId, size)};
return cover.save(Image::Format::JPEG); assert(format == Image::Format::JPEG);
return cover.save(format);
} }
std::vector<uint8_t> std::vector<uint8_t>
@@ -247,7 +246,8 @@ Grabber::getFromRelease(Database::Session& session, Database::IdType releaseId,
{ {
const Image::Image cover {getFromRelease(session, releaseId, size)}; const Image::Image cover {getFromRelease(session, releaseId, size)};
return cover.save(Image::Format::JPEG); assert(format == Image::Format::JPEG);
return cover.save(format);
} }
} // namespace CoverArt } // namespace CoverArt
+8 -8
View File
@@ -19,12 +19,12 @@
#pragma once #pragma once
#include <filesystem>
#include <map> #include <map>
#include <mutex> #include <mutex>
#include <optional>
#include <vector> #include <vector>
#include <boost/optional.hpp>
#include "database/Types.hpp" #include "database/Types.hpp"
#include "image/Image.hpp" #include "image/Image.hpp"
@@ -44,7 +44,7 @@ class Grabber
Grabber(Grabber&&) = delete; Grabber(Grabber&&) = delete;
Grabber& operator=(Grabber&&) = delete; Grabber& operator=(Grabber&&) = delete;
void setDefaultCover(boost::filesystem::path defaultCoverPath); void setDefaultCover(const std::filesystem::path& defaultCoverPath);
std::vector<uint8_t> getFromTrack(Database::Session& dbSession, Database::IdType trackId, Image::Format format, std::size_t size); std::vector<uint8_t> getFromTrack(Database::Session& dbSession, Database::IdType trackId, Image::Format format, std::size_t size);
std::vector<uint8_t> getFromRelease(Database::Session& dbSession, Database::IdType releaseId, Image::Format format, std::size_t size); std::vector<uint8_t> getFromRelease(Database::Session& dbSession, Database::IdType releaseId, Image::Format format, std::size_t size);
@@ -54,9 +54,9 @@ class Grabber
Image::Image getFromTrack(Database::Session& dbSession, Database::IdType trackId, std::size_t size); Image::Image getFromTrack(Database::Session& dbSession, Database::IdType trackId, std::size_t size);
Image::Image getFromRelease(Database::Session& dbSession, Database::IdType releaseId, std::size_t size); Image::Image getFromRelease(Database::Session& dbSession, Database::IdType releaseId, std::size_t size);
boost::optional<Image::Image> getFromTrack(const boost::filesystem::path& path) const; std::optional<Image::Image> getFromTrack(const std::filesystem::path& path) const;
std::vector<boost::filesystem::path> getCoverPaths(const boost::filesystem::path& directoryPath) const; std::vector<std::filesystem::path> getCoverPaths(const std::filesystem::path& directoryPath) const;
boost::optional<Image::Image> getFromDirectory(const boost::filesystem::path& path) const; std::optional<Image::Image> getFromDirectory(const std::filesystem::path& path) const;
Image::Image getDefaultCover(std::size_t size); Image::Image getDefaultCover(std::size_t size);
@@ -65,12 +65,12 @@ class Grabber
std::mutex _mutex; std::mutex _mutex;
std::map<std::size_t /* size */, Image::Image> _defaultCovers; std::map<std::size_t /* size */, Image::Image> _defaultCovers;
std::vector<boost::filesystem::path> _fileExtensions std::vector<std::filesystem::path> _fileExtensions
= {".jpg", ".jpeg", ".png", ".bmp"}; // TODO parametrize = {".jpg", ".jpeg", ".png", ".bmp"}; // TODO parametrize
std::size_t _maxFileSize = 5000000; std::size_t _maxFileSize = 5000000;
std::vector<boost::filesystem::path> _preferredFileNames std::vector<std::filesystem::path> _preferredFileNames
= {"cover", "front"}; // TODO parametrize = {"cover", "front"}; // TODO parametrize
}; };
+13 -8
View File
@@ -75,7 +75,7 @@ Artist::create(Session& session, const std::string& name, const std::string& MBI
} }
std::vector<Artist::pointer> std::vector<Artist::pointer>
Artist::getAll(Session& session, boost::optional<std::size_t> offset, boost::optional<std::size_t> size) Artist::getAll(Session& session, std::optional<std::size_t> offset, std::optional<std::size_t> size)
{ {
session.checkSharedLocked(); session.checkSharedLocked();
Wt::Dbo::collection<pointer> res = session.getDboSession().find<Artist>() Wt::Dbo::collection<pointer> res = session.getDboSession().find<Artist>()
@@ -151,8 +151,8 @@ std::vector<Artist::pointer>
Artist::getByFilter(Session& session, Artist::getByFilter(Session& session,
const std::set<IdType>& clusters, const std::set<IdType>& clusters,
const std::vector<std::string>& keywords, const std::vector<std::string>& keywords,
boost::optional<std::size_t> offset, std::optional<std::size_t> offset,
boost::optional<std::size_t> size, std::optional<std::size_t> size,
bool& moreResults) bool& moreResults)
{ {
session.checkSharedLocked(); session.checkSharedLocked();
@@ -174,7 +174,7 @@ Artist::getByFilter(Session& session,
} }
std::vector<Artist::pointer> std::vector<Artist::pointer>
Artist::getLastAdded(Session& session, Wt::WDateTime after, boost::optional<std::size_t> limit) Artist::getLastAdded(Session& session, Wt::WDateTime after, std::optional<std::size_t> limit)
{ {
session.checkSharedLocked(); session.checkSharedLocked();
Wt::Dbo::collection<Artist::pointer> res = session.getDboSession().query<Artist::pointer>("SELECT a from artist a INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id INNER JOIN track t ON t.id = t_a_l.track_id") Wt::Dbo::collection<Artist::pointer> res = session.getDboSession().query<Artist::pointer>("SELECT a from artist a INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id INNER JOIN track t ON t.id = t_a_l.track_id")
@@ -243,7 +243,7 @@ Artist::getReleaseCount() const
} }
std::vector<Wt::Dbo::ptr<Track>> std::vector<Wt::Dbo::ptr<Track>>
Artist::getTracks(boost::optional<TrackArtistLink::Type> linkType) const Artist::getTracks(std::optional<TrackArtistLink::Type> linkType) const
{ {
assert(self()); assert(self());
assert(IdIsValid(self()->id())); assert(IdIsValid(self()->id()));
@@ -262,22 +262,27 @@ Artist::getTracks(boost::optional<TrackArtistLink::Type> linkType) const
} }
std::vector<Wt::Dbo::ptr<Track>> std::vector<Wt::Dbo::ptr<Track>>
Artist::getTracksWithRelease(boost::optional<TrackArtistLink::Type> linkType) const Artist::getTracksWithRelease(std::optional<TrackArtistLink::Type> linkType) const
{ {
assert(self()); assert(self());
assert(IdIsValid(self()->id())); assert(IdIsValid(self()->id()));
assert(session()); assert(session());
Wt::Dbo::collection<Wt::Dbo::ptr<Track>> tracks {session()->query<Wt::Dbo::ptr<Track>>("SELECT t FROM track t INNER JOIN artist a ON a.id = t_a_l.artist_id INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id INNER JOIN release r ON r.id = t.release_id") auto query {session()->query<Wt::Dbo::ptr<Track>>("SELECT t FROM track t INNER JOIN artist a ON a.id = t_a_l.artist_id INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id INNER JOIN release r ON r.id = t.release_id")
.where("a.id = ?").bind(self()->id()) .where("a.id = ?").bind(self()->id())
.orderBy("t.year,r.name,t.disc_number,t.track_number")}; .orderBy("t.year,r.name,t.disc_number,t.track_number")};
if (linkType)
query.where("t_a_l.type = ?").bind(*linkType);
Wt::Dbo::collection<Wt::Dbo::ptr<Track>> tracks {query.resultList()};
return std::vector<Wt::Dbo::ptr<Track>>(tracks.begin(), tracks.end()); return std::vector<Wt::Dbo::ptr<Track>>(tracks.begin(), tracks.end());
} }
std::vector<Wt::Dbo::ptr<Track>> std::vector<Wt::Dbo::ptr<Track>>
Artist::getRandomTracks(boost::optional<std::size_t> count) const Artist::getRandomTracks(std::optional<std::size_t> count) const
{ {
assert(self()); assert(self());
assert(IdIsValid(self()->id())); assert(IdIsValid(self()->id()));
+8 -9
View File
@@ -19,11 +19,10 @@
#pragma once #pragma once
#include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
#include <boost/optional.hpp>
#include <Wt/WDateTime.h> #include <Wt/WDateTime.h>
#include <Wt/Dbo/Dbo.h> #include <Wt/Dbo/Dbo.h>
@@ -58,13 +57,13 @@ class Artist : public Wt::Dbo::Dbo<Artist>
static std::vector<pointer> getByFilter(Session& session, static std::vector<pointer> getByFilter(Session& session,
const std::set<IdType>& clusters, // at least one track that belongs to these clusters const std::set<IdType>& clusters, // at least one track that belongs to these clusters
const std::vector<std::string>& keywords, // name must match all of these keywords const std::vector<std::string>& keywords, // name must match all of these keywords
boost::optional<std::size_t> offset, std::optional<std::size_t> offset,
boost::optional<std::size_t> size, std::optional<std::size_t> size,
bool& moreExpected); bool& moreExpected);
static std::vector<pointer> getAll(Session& session, boost::optional<std::size_t> offset = {}, boost::optional<std::size_t> size = {}); static std::vector<pointer> getAll(Session& session, std::optional<std::size_t> offset = {}, std::optional<std::size_t> size = {});
static std::vector<pointer> getAllOrphans(Session& session); // No track related static std::vector<pointer> getAllOrphans(Session& session); // No track related
static std::vector<pointer> getLastAdded(Session& session, Wt::WDateTime after, boost::optional<std::size_t> size = {}); static std::vector<pointer> getLastAdded(Session& session, Wt::WDateTime after, std::optional<std::size_t> size = {});
// Accessors // Accessors
const std::string& getName(void) const { return _name; } const std::string& getName(void) const { return _name; }
@@ -72,9 +71,9 @@ class Artist : public Wt::Dbo::Dbo<Artist>
std::vector<Wt::Dbo::ptr<Release>> getReleases(const std::set<IdType>& clusterIds = std::set<IdType>()) const; std::vector<Wt::Dbo::ptr<Release>> getReleases(const std::set<IdType>& clusterIds = std::set<IdType>()) const;
std::size_t getReleaseCount() const; std::size_t getReleaseCount() const;
std::vector<Wt::Dbo::ptr<Track>> getTracks(boost::optional<TrackArtistLink::Type> linkType = {}) const; std::vector<Wt::Dbo::ptr<Track>> getTracks(std::optional<TrackArtistLink::Type> linkType = {}) const;
std::vector<Wt::Dbo::ptr<Track>> getTracksWithRelease(boost::optional<TrackArtistLink::Type> linkType = {}) const; std::vector<Wt::Dbo::ptr<Track>> getTracksWithRelease(std::optional<TrackArtistLink::Type> linkType = {}) const;
std::vector<Wt::Dbo::ptr<Track>> getRandomTracks(boost::optional<std::size_t> count) const; std::vector<Wt::Dbo::ptr<Track>> getRandomTracks(std::optional<std::size_t> count) const;
// Get the cluster of the tracks made by this artist // Get the cluster of the tracks made by this artist
// Each clusters are grouped by cluster type, sorted by the number of occurence // Each clusters are grouped by cluster type, sorted by the number of occurence
@@ -17,7 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Database.hpp" #include "Db.hpp"
#include <Wt/Dbo/FixedSqlConnectionPool.h> #include <Wt/Dbo/FixedSqlConnectionPool.h>
#include <Wt/Dbo/backend/Sqlite3.h> #include <Wt/Dbo/backend/Sqlite3.h>
@@ -28,7 +28,7 @@
namespace Database { namespace Database {
// Session living class handling the database and the login // Session living class handling the database and the login
Database::Database(const boost::filesystem::path& dbPath) Db::Db(const std::filesystem::path& dbPath)
{ {
LMS_LOG(DB, INFO) << "Creating connection pool on file " << dbPath.string(); LMS_LOG(DB, INFO) << "Creating connection pool on file " << dbPath.string();
@@ -49,9 +49,9 @@ Database::Database(const boost::filesystem::path& dbPath)
} }
std::unique_ptr<Session> std::unique_ptr<Session>
Database::createSession() Db::createSession()
{ {
return std::unique_ptr<Session>{new Session {_sharedMutex, *_connectionPool.get()}}; return std::unique_ptr<Session>(new Session {_sharedMutex, *_connectionPool.get()});
} }
} // namespace Database } // namespace Database
@@ -19,10 +19,9 @@
#pragma once #pragma once
#include <filesystem>
#include <shared_mutex> #include <shared_mutex>
#include <boost/filesystem.hpp>
#include <Wt/Dbo/SqlConnectionPool.h> #include <Wt/Dbo/SqlConnectionPool.h>
#include "Session.hpp" #include "Session.hpp"
@@ -30,16 +29,16 @@
namespace Database { namespace Database {
// Session living class handling the database and the login // Session living class handling the database and the login
class Database class Db
{ {
public: public:
Database(const boost::filesystem::path& dbPath); Db(const std::filesystem::path& dbPath);
std::unique_ptr<Session> createSession(); std::unique_ptr<Session> createSession();
private: private:
std::shared_timed_mutex _sharedMutex; std::shared_mutex _sharedMutex;
std::unique_ptr<Wt::Dbo::SqlConnectionPool> _connectionPool; std::unique_ptr<Wt::Dbo::SqlConnectionPool> _connectionPool;
}; };
+18 -18
View File
@@ -84,7 +84,7 @@ Release::getCount(Session& session)
} }
std::vector<Release::pointer> std::vector<Release::pointer>
Release::getAll(Session& session, boost::optional<std::size_t> offset, boost::optional<std::size_t> size) Release::getAll(Session& session, std::optional<std::size_t> offset, std::optional<std::size_t> size)
{ {
session.checkSharedLocked(); session.checkSharedLocked();
@@ -97,7 +97,7 @@ Release::getAll(Session& session, boost::optional<std::size_t> offset, boost::op
} }
std::vector<Release::pointer> std::vector<Release::pointer>
Release::getAllOrderedByArtist(Session& session, boost::optional<std::size_t> offset, boost::optional<std::size_t> size) Release::getAllOrderedByArtist(Session& session, std::optional<std::size_t> offset, std::optional<std::size_t> size)
{ {
session.checkSharedLocked(); session.checkSharedLocked();
@@ -114,7 +114,7 @@ Release::getAllOrderedByArtist(Session& session, boost::optional<std::size_t> of
} }
std::vector<Release::pointer> std::vector<Release::pointer>
Release::getAllRandom(Session& session, boost::optional<std::size_t> size) Release::getAllRandom(Session& session, std::optional<std::size_t> size)
{ {
session.checkSharedLocked(); session.checkSharedLocked();
@@ -136,7 +136,7 @@ Release::getAllOrphans(Session& session)
} }
std::vector<Release::pointer> std::vector<Release::pointer>
Release::getLastAdded(Session& session, const Wt::WDateTime& after, boost::optional<std::size_t> offset, boost::optional<std::size_t> limit) Release::getLastAdded(Session& session, const Wt::WDateTime& after, std::optional<std::size_t> offset, std::optional<std::size_t> limit)
{ {
session.checkSharedLocked(); session.checkSharedLocked();
@@ -151,7 +151,7 @@ Release::getLastAdded(Session& session, const Wt::WDateTime& after, boost::optio
} }
std::vector<Release::pointer> std::vector<Release::pointer>
Release::getByYear(Session& session, int yearFrom, int yearTo, boost::optional<std::size_t> offset, boost::optional<std::size_t> limit) Release::getByYear(Session& session, int yearFrom, int yearTo, std::optional<std::size_t> offset, std::optional<std::size_t> limit)
{ {
Wt::Dbo::collection<Release::pointer> res = session.getDboSession().query<Release::pointer> Wt::Dbo::collection<Release::pointer> res = session.getDboSession().query<Release::pointer>
("SELECT DISTINCT r from release r INNER JOIN track t ON r.id = t.release_id") ("SELECT DISTINCT r from release r INNER JOIN track t ON r.id = t.release_id")
@@ -216,8 +216,8 @@ std::vector<Release::pointer>
Release::getByFilter(Session& session, Release::getByFilter(Session& session,
const std::set<IdType>& clusterIds, const std::set<IdType>& clusterIds,
const std::vector<std::string>& keywords, const std::vector<std::string>& keywords,
boost::optional<std::size_t> offset, std::optional<std::size_t> offset,
boost::optional<std::size_t> size, std::optional<std::size_t> size,
bool& moreResults) bool& moreResults)
{ {
Wt::Dbo::collection<pointer> collection = getQuery(session, clusterIds, keywords) Wt::Dbo::collection<pointer> collection = getQuery(session, clusterIds, keywords)
@@ -237,19 +237,19 @@ Release::getByFilter(Session& session,
return res; return res;
} }
boost::optional<std::size_t> std::optional<std::size_t>
Release::getTotalTrackNumber(void) const Release::getTotalTrackNumber(void) const
{ {
return (_totalTrackNumber > 0) ? boost::make_optional<std::size_t>(_totalTrackNumber) : boost::none; return (_totalTrackNumber > 0) ? std::make_optional<std::size_t>(_totalTrackNumber) : std::nullopt;
} }
boost::optional<std::size_t> std::optional<std::size_t>
Release::getTotalDiscNumber(void) const Release::getTotalDiscNumber(void) const
{ {
return (_totalDiscNumber > 0) ? boost::make_optional<std::size_t>(_totalDiscNumber) : boost::none; return (_totalDiscNumber > 0) ? std::make_optional<std::size_t>(_totalDiscNumber) : std::nullopt;
} }
boost::optional<int> std::optional<int>
Release::getReleaseYear(bool original) const Release::getReleaseYear(bool original) const
{ {
assert(session()); assert(session());
@@ -264,17 +264,17 @@ Release::getReleaseYear(bool original) const
// various dates => no date // various dates => no date
if (dates.empty() || dates.size() > 1) if (dates.empty() || dates.size() > 1)
return boost::none; return std::nullopt;
auto date {dates.front()}; auto date {dates.front()};
if (date > 0) if (date > 0)
return date; return date;
else else
return boost::none; return std::nullopt;
} }
boost::optional<std::string> std::optional<std::string>
Release::getCopyright() const Release::getCopyright() const
{ {
assert(session()); assert(session());
@@ -289,12 +289,12 @@ Release::getCopyright() const
// various copyrights => no copyright // various copyrights => no copyright
if (values.empty() || values.size() > 1 || values.front().empty()) if (values.empty() || values.size() > 1 || values.front().empty())
return boost::none; return std::nullopt;
return values.front(); return values.front();
} }
boost::optional<std::string> std::optional<std::string>
Release::getCopyrightURL() const Release::getCopyrightURL() const
{ {
assert(session()); assert(session());
@@ -309,7 +309,7 @@ Release::getCopyrightURL() const
// various copyright URLs => no copyright URL // various copyright URLs => no copyright URL
if (values.empty() || values.size() > 1 || values.front().empty()) if (values.empty() || values.size() > 1 || values.front().empty())
return boost::none; return std::nullopt;
return values.front(); return values.front();
} }
+13 -13
View File
@@ -19,7 +19,7 @@
#pragma once #pragma once
#include <boost/optional.hpp> #include <optional>
#include <Wt/Dbo/WtSqlTraits.h> #include <Wt/Dbo/WtSqlTraits.h>
@@ -51,18 +51,18 @@ class Release : public Wt::Dbo::Dbo<Release>
static std::vector<pointer> getByName(Session& session, const std::string& name); static std::vector<pointer> getByName(Session& session, const std::string& name);
static pointer getById(Session& session, IdType id); static pointer getById(Session& session, IdType id);
static std::vector<pointer> getAllOrphans(Session& session); // no track related static std::vector<pointer> getAllOrphans(Session& session); // no track related
static std::vector<pointer> getAll(Session& session, boost::optional<std::size_t> offset = {}, boost::optional<std::size_t> size = {}); static std::vector<pointer> getAll(Session& session, std::optional<std::size_t> offset = {}, std::optional<std::size_t> size = {});
static std::vector<pointer> getAllOrderedByArtist(Session& session, boost::optional<std::size_t> offset = {}, boost::optional<std::size_t> size = {}); static std::vector<pointer> getAllOrderedByArtist(Session& session, std::optional<std::size_t> offset = {}, std::optional<std::size_t> size = {});
static std::vector<pointer> getAllRandom(Session& session, boost::optional<std::size_t> size = {}); static std::vector<pointer> getAllRandom(Session& session, std::optional<std::size_t> size = {});
static std::vector<pointer> getLastAdded(Session& session, const Wt::WDateTime& after, boost::optional<std::size_t> offset = {}, boost::optional<std::size_t> size = {}); static std::vector<pointer> getLastAdded(Session& session, const Wt::WDateTime& after, std::optional<std::size_t> offset = {}, std::optional<std::size_t> size = {});
static std::vector<pointer> getByYear(Session& session, int yearFrom, int yearTo, boost::optional<std::size_t> offset = {}, boost::optional<std::size_t> size = {}); static std::vector<pointer> getByYear(Session& session, int yearFrom, int yearTo, std::optional<std::size_t> offset = {}, std::optional<std::size_t> size = {});
static std::vector<pointer> getByFilter(Session& session, const std::set<IdType>& clusters); static std::vector<pointer> getByFilter(Session& session, const std::set<IdType>& clusters);
static std::vector<pointer> getByFilter(Session& session, static std::vector<pointer> getByFilter(Session& session,
const std::set<IdType>& clusters, // at least one track that belongs to these clusters const std::set<IdType>& clusters, // at least one track that belongs to these clusters
const std::vector<std::string>& keywords, // name must match all of these keywords const std::vector<std::string>& keywords, // name must match all of these keywords
boost::optional<std::size_t> offset, std::optional<std::size_t> offset,
boost::optional<std::size_t> size, std::optional<std::size_t> size,
bool& moreExpected); bool& moreExpected);
std::vector<Wt::Dbo::ptr<Track>> getTracks(const std::set<IdType>& clusters = std::set<IdType>()) const; std::vector<Wt::Dbo::ptr<Track>> getTracks(const std::set<IdType>& clusters = std::set<IdType>()) const;
@@ -77,9 +77,9 @@ class Release : public Wt::Dbo::Dbo<Release>
static pointer create(Session& session, const std::string& name, const std::string& MBID = ""); static pointer create(Session& session, const std::string& name, const std::string& MBID = "");
// Utility functions // Utility functions
boost::optional<int> getReleaseYear(bool originalDate = false) const; // 0 if unknown or various std::optional<int> getReleaseYear(bool originalDate = false) const; // 0 if unknown or various
boost::optional<std::string> getCopyright() const; std::optional<std::string> getCopyright() const;
boost::optional<std::string> getCopyrightURL() const; std::optional<std::string> getCopyrightURL() const;
// Modifiers // Modifiers
void setTotalDiscNumber(std::size_t num) { _totalDiscNumber = static_cast<int>(num); } void setTotalDiscNumber(std::size_t num) { _totalDiscNumber = static_cast<int>(num); }
@@ -88,8 +88,8 @@ class Release : public Wt::Dbo::Dbo<Release>
// Accessors // Accessors
std::string getName() const { return _name; } std::string getName() const { return _name; }
std::string getMBID() const { return _MBID; } std::string getMBID() const { return _MBID; }
boost::optional<std::size_t> getTotalTrackNumber() const; std::optional<std::size_t> getTotalTrackNumber() const;
boost::optional<std::size_t> getTotalDiscNumber() const; std::optional<std::size_t> getTotalDiscNumber() const;
std::chrono::milliseconds getDuration() const; std::chrono::milliseconds getDuration() const;
// Get the artists of this release // Get the artists of this release
+4 -4
View File
@@ -62,11 +62,11 @@ ScanSettings::get(Session& session)
return session.getDboSession().find<ScanSettings>(); return session.getDboSession().find<ScanSettings>();
} }
std::set<boost::filesystem::path> std::set<std::filesystem::path>
ScanSettings::getAudioFileExtensions() const ScanSettings::getAudioFileExtensions() const
{ {
auto extensions = splitString(_audioFileExtensions, " "); auto extensions = splitString(_audioFileExtensions, " ");
return std::set<boost::filesystem::path>(std::cbegin(extensions), std::cend(extensions)); return std::set<std::filesystem::path>(std::cbegin(extensions), std::cend(extensions));
} }
std::vector<ClusterType::pointer> std::vector<ClusterType::pointer>
@@ -76,7 +76,7 @@ ScanSettings::getClusterTypes() const
} }
void void
ScanSettings::setMediaDirectory(boost::filesystem::path p) ScanSettings::setMediaDirectory(std::filesystem::path p)
{ {
_mediaDirectory = stringTrimEnd(p.string(), "/\\"); _mediaDirectory = stringTrimEnd(p.string(), "/\\");
} }
@@ -85,7 +85,7 @@ template <typename It>
std::set<std::string> getNames(It begin, It end) std::set<std::string> getNames(It begin, It end)
{ {
std::set<std::string> names; std::set<std::string> names;
std::transform(begin, end, std::inserter(names, std::begin(names)), std::transform(begin, end, std::inserter(names, std::cbegin(names)),
[](const ClusterType::pointer& clusterType) [](const ClusterType::pointer& clusterType)
{ {
return clusterType->getName(); return clusterType->getName();
+5 -5
View File
@@ -19,7 +19,7 @@
#pragma once #pragma once
#include <boost/filesystem.hpp> #include <filesystem>
#include <Wt/Dbo/Dbo.h> #include <Wt/Dbo/Dbo.h>
#include <Wt/WTime.h> #include <Wt/WTime.h>
@@ -47,18 +47,18 @@ class ScanSettings : public Wt::Dbo::Dbo<ScanSettings>
// Getters // Getters
std::size_t getScanVersion() const { return _scanVersion; } std::size_t getScanVersion() const { return _scanVersion; }
boost::filesystem::path getMediaDirectory() const { return _mediaDirectory; } std::filesystem::path getMediaDirectory() const { return _mediaDirectory; }
Wt::WTime getUpdateStartTime() const { return _startTime; } Wt::WTime getUpdateStartTime() const { return _startTime; }
UpdatePeriod getUpdatePeriod() const { return _updatePeriod; } UpdatePeriod getUpdatePeriod() const { return _updatePeriod; }
std::vector<Wt::Dbo::ptr<ClusterType>> getClusterTypes() const; std::vector<Wt::Dbo::ptr<ClusterType>> getClusterTypes() const;
std::set<boost::filesystem::path> getAudioFileExtensions() const; std::set<std::filesystem::path> getAudioFileExtensions() const;
// Setters // Setters
void setMediaDirectory(boost::filesystem::path p); void setMediaDirectory(std::filesystem::path p);
void setUpdateStartTime(Wt::WTime t) { _startTime = t; } void setUpdateStartTime(Wt::WTime t) { _startTime = t; }
void setUpdatePeriod(UpdatePeriod p) { _updatePeriod = p; } void setUpdatePeriod(UpdatePeriod p) { _updatePeriod = p; }
void setClusterTypes(Session& session, const std::set<std::string>& clusterTypeNames); void setClusterTypes(Session& session, const std::set<std::string>& clusterTypeNames);
void setAudioFileExtensions(std::set<boost::filesystem::path> fileExtensions); void setAudioFileExtensions(std::set<std::filesystem::path> fileExtensions);
template<class Action> template<class Action>
void persist(Action& a) void persist(Action& a)
+8 -8
View File
@@ -110,7 +110,7 @@ Session::doDatabaseMigrationIfNeeded()
VersionInfo::get(*this).modify()->setVersion(LMS_DATABASE_VERSION); VersionInfo::get(*this).modify()->setVersion(LMS_DATABASE_VERSION);
} }
Session::Session(std::shared_timed_mutex& mutex, Wt::Dbo::SqlConnectionPool& connectionPool) Session::Session(std::shared_mutex& mutex, Wt::Dbo::SqlConnectionPool& connectionPool)
: _mutex {mutex} : _mutex {mutex}
{ {
_session.setConnectionPool(connectionPool); _session.setConnectionPool(connectionPool);
@@ -140,9 +140,9 @@ enum class OwnedLock
Unique, Unique,
}; };
static thread_local std::map<std::shared_timed_mutex*, OwnedLock> lockDebug; static thread_local std::map<std::shared_mutex*, OwnedLock> lockDebug;
UniqueTransaction::UniqueTransaction(std::shared_timed_mutex& mutex, Wt::Dbo::Session& session) UniqueTransaction::UniqueTransaction(std::shared_mutex& mutex, Wt::Dbo::Session& session)
: _lock {mutex}, : _lock {mutex},
_transaction {session} _transaction {session}
{ {
@@ -156,7 +156,7 @@ UniqueTransaction::~UniqueTransaction()
lockDebug[_lock.mutex()] = OwnedLock::None; lockDebug[_lock.mutex()] = OwnedLock::None;
} }
SharedTransaction::SharedTransaction(std::shared_timed_mutex& mutex, Wt::Dbo::Session& session) SharedTransaction::SharedTransaction(std::shared_mutex& mutex, Wt::Dbo::Session& session)
: _lock {mutex}, : _lock {mutex},
_transaction {session} _transaction {session}
{ {
@@ -182,16 +182,16 @@ Session::checkSharedLocked()
assert(lockDebug[&_mutex] != OwnedLock::None); assert(lockDebug[&_mutex] != OwnedLock::None);
} }
std::unique_ptr<UniqueTransaction> UniqueTransaction
Session::createUniqueTransaction() Session::createUniqueTransaction()
{ {
return std::unique_ptr<UniqueTransaction>(new UniqueTransaction{_mutex, _session}); return UniqueTransaction{_mutex, _session};
} }
std::unique_ptr<SharedTransaction> SharedTransaction
Session::createSharedTransaction() Session::createSharedTransaction()
{ {
return std::unique_ptr<SharedTransaction>(new SharedTransaction{_mutex, _session}); return SharedTransaction{_mutex, _session};
} }
void void
+9 -10
View File
@@ -21,7 +21,6 @@
#include <shared_mutex> #include <shared_mutex>
#include <mutex> #include <mutex>
#include <boost/filesystem.hpp>
#include <memory> #include <memory>
#include <Wt/Dbo/Dbo.h> #include <Wt/Dbo/Dbo.h>
@@ -36,9 +35,9 @@ class UniqueTransaction
private: private:
friend class Session; friend class Session;
UniqueTransaction(std::shared_timed_mutex& mutex, Wt::Dbo::Session& session); UniqueTransaction(std::shared_mutex& mutex, Wt::Dbo::Session& session);
std::unique_lock<std::shared_timed_mutex> _lock; std::unique_lock<std::shared_mutex> _lock;
Wt::Dbo::Transaction _transaction; Wt::Dbo::Transaction _transaction;
}; };
@@ -49,9 +48,9 @@ class SharedTransaction
private: private:
friend class Session; friend class Session;
SharedTransaction(std::shared_timed_mutex& mutex, Wt::Dbo::Session& session); SharedTransaction(std::shared_mutex& mutex, Wt::Dbo::Session& session);
std::shared_lock<std::shared_timed_mutex> _lock; std::shared_lock<std::shared_mutex> _lock;
Wt::Dbo::Transaction _transaction; Wt::Dbo::Transaction _transaction;
}; };
@@ -63,8 +62,8 @@ class Session
Session& operator=(const Session&) = delete; Session& operator=(const Session&) = delete;
Session& operator=(Session&&) = delete; Session& operator=(Session&&) = delete;
std::unique_ptr<UniqueTransaction> createUniqueTransaction(); UniqueTransaction createUniqueTransaction();
std::unique_ptr<SharedTransaction> createSharedTransaction(); SharedTransaction createSharedTransaction();
void checkUniqueLocked(); void checkUniqueLocked();
void checkSharedLocked(); void checkSharedLocked();
@@ -74,14 +73,14 @@ class Session
Wt::Dbo::Session& getDboSession() { return _session; } Wt::Dbo::Session& getDboSession() { return _session; }
private: private:
friend class Database; friend class Db;
Session(std::shared_timed_mutex& mutex, Wt::Dbo::SqlConnectionPool& connectionPool); Session(std::shared_mutex& mutex, Wt::Dbo::SqlConnectionPool& connectionPool);
void doDatabaseMigrationIfNeeded(); void doDatabaseMigrationIfNeeded();
void prepareTables(); // need to run only once at startup void prepareTables(); // need to run only once at startup
std::shared_timed_mutex& _mutex; std::shared_mutex& _mutex;
Wt::Dbo::Session _session; Wt::Dbo::Session _session;
}; };
+23 -23
View File
@@ -32,14 +32,14 @@
namespace Database { namespace Database {
Track::Track(const boost::filesystem::path& p) Track::Track(const std::filesystem::path& p)
: :
_filePath( p.string() ) _filePath( p.string() )
{ {
} }
std::vector<Track::pointer> std::vector<Track::pointer>
Track::getAll(Session& session, boost::optional<std::size_t> limit) Track::getAll(Session& session, std::optional<std::size_t> limit)
{ {
session.checkSharedLocked(); session.checkSharedLocked();
@@ -50,7 +50,7 @@ Track::getAll(Session& session, boost::optional<std::size_t> limit)
} }
std::vector<Track::pointer> std::vector<Track::pointer>
Track::getAllRandom(Session& session, boost::optional<std::size_t> limit) Track::getAllRandom(Session& session, std::optional<std::size_t> limit)
{ {
session.checkSharedLocked(); session.checkSharedLocked();
@@ -71,7 +71,7 @@ Track::getAllIds(Session& session)
} }
Track::pointer Track::pointer
Track::getByPath(Session& session, const boost::filesystem::path& p) Track::getByPath(Session& session, const std::filesystem::path& p)
{ {
session.checkSharedLocked(); session.checkSharedLocked();
@@ -97,7 +97,7 @@ Track::getByMBID(Session& session, const std::string& mbid)
} }
Track::pointer Track::pointer
Track::create(Session& session, const boost::filesystem::path& p) Track::create(Session& session, const std::filesystem::path& p)
{ {
session.checkUniqueLocked(); session.checkUniqueLocked();
@@ -107,13 +107,13 @@ Track::create(Session& session, const boost::filesystem::path& p)
return res; return res;
} }
std::vector<boost::filesystem::path> std::vector<std::filesystem::path>
Track::getAllPaths(Session& session) Track::getAllPaths(Session& session)
{ {
session.checkSharedLocked(); session.checkSharedLocked();
Wt::Dbo::collection<std::string> res = session.getDboSession().query<std::string>("SELECT file_path FROM track"); Wt::Dbo::collection<std::string> res = session.getDboSession().query<std::string>("SELECT file_path FROM track");
return std::vector<boost::filesystem::path>(res.begin(), res.end()); return std::vector<std::filesystem::path>(res.begin(), res.end());
} }
std::vector<Track::pointer> std::vector<Track::pointer>
@@ -126,7 +126,7 @@ Track::getMBIDDuplicates(Session& session)
} }
std::vector<Track::pointer> std::vector<Track::pointer>
Track::getLastAdded(Session& session, const Wt::WDateTime& after, boost::optional<std::size_t> limit) Track::getLastAdded(Session& session, const Wt::WDateTime& after, std::optional<std::size_t> limit)
{ {
session.checkSharedLocked(); session.checkSharedLocked();
@@ -151,7 +151,7 @@ Track::getAllWithMBIDAndMissingFeatures(Session& session)
} }
std::vector<IdType> std::vector<IdType>
Track::getAllIdsWithFeatures(Session& session, boost::optional<std::size_t> limit) Track::getAllIdsWithFeatures(Session& session, std::optional<std::size_t> limit)
{ {
session.checkSharedLocked(); session.checkSharedLocked();
@@ -224,8 +224,8 @@ std::vector<Track::pointer>
Track::getByFilter(Session& session, Track::getByFilter(Session& session,
const std::set<IdType>& clusterIds, const std::set<IdType>& clusterIds,
const std::vector<std::string>& keywords, const std::vector<std::string>& keywords,
boost::optional<std::size_t> offset, std::optional<std::size_t> offset,
boost::optional<std::size_t> size, std::optional<std::size_t> size,
bool& moreResults) bool& moreResults)
{ {
session.checkSharedLocked(); session.checkSharedLocked();
@@ -289,40 +289,40 @@ Track::setFeatures(const Wt::Dbo::ptr<TrackFeatures>& features)
_trackFeatures = features; _trackFeatures = features;
} }
boost::optional<std::size_t> std::optional<std::size_t>
Track::getTrackNumber(void) const Track::getTrackNumber(void) const
{ {
return (_trackNumber > 0) ? boost::make_optional<std::size_t>(_trackNumber) : boost::none; return (_trackNumber > 0) ? std::make_optional<std::size_t>(_trackNumber) : std::nullopt;
} }
boost::optional<std::size_t> std::optional<std::size_t>
Track::getDiscNumber(void) const Track::getDiscNumber(void) const
{ {
return (_discNumber > 0) ? boost::make_optional<std::size_t>(_discNumber) : boost::none; return (_discNumber > 0) ? std::make_optional<std::size_t>(_discNumber) : std::nullopt;
} }
boost::optional<int> std::optional<int>
Track::getYear() const Track::getYear() const
{ {
return (_year > 0) ? boost::make_optional<int>(_year) : boost::none; return (_year > 0) ? std::make_optional<int>(_year) : std::nullopt;
} }
boost::optional<int> std::optional<int>
Track::getOriginalYear() const Track::getOriginalYear() const
{ {
return (_originalYear > 0) ? boost::make_optional<int>(_originalYear) : boost::none; return (_originalYear > 0) ? std::make_optional<int>(_originalYear) : std::nullopt;
} }
boost::optional<std::string> std::optional<std::string>
Track::getCopyright() const Track::getCopyright() const
{ {
return _copyright != "" ? boost::make_optional<std::string>(_copyright) : boost::none; return _copyright != "" ? std::make_optional<std::string>(_copyright) : std::nullopt;
} }
boost::optional<std::string> std::optional<std::string>
Track::getCopyrightURL() const Track::getCopyrightURL() const
{ {
return _copyrightURL != "" ? boost::make_optional<std::string>(_copyrightURL) : boost::none; return _copyrightURL != "" ? std::make_optional<std::string>(_copyrightURL) : std::nullopt;
} }
std::vector<Wt::Dbo::ptr<Artist>> std::vector<Wt::Dbo::ptr<Artist>>
+22 -23
View File
@@ -19,12 +19,11 @@
#pragma once #pragma once
#include <string>
#include <vector>
#include <chrono> #include <chrono>
#include <filesystem>
#include <boost/filesystem.hpp> #include <optional>
#include <boost/optional.hpp> #include <vector>
#include <string>
#include <Wt/Dbo/Dbo.h> #include <Wt/Dbo/Dbo.h>
#include <Wt/WDateTime.h> #include <Wt/WDateTime.h>
@@ -50,10 +49,10 @@ class Track : public Wt::Dbo::Dbo<Track>
using pointer = Wt::Dbo::ptr<Track>; using pointer = Wt::Dbo::ptr<Track>;
Track() {} Track() {}
Track(const boost::filesystem::path& p); Track(const std::filesystem::path& p);
// Find utility functions // Find utility functions
static pointer getByPath(Session& session, const boost::filesystem::path& p); static pointer getByPath(Session& session, const std::filesystem::path& p);
static pointer getById(Session& session, IdType id); static pointer getById(Session& session, IdType id);
static pointer getByMBID(Session& session, const std::string& MBID); static pointer getByMBID(Session& session, const std::string& MBID);
static std::vector<pointer> getByFilter(Session& session, static std::vector<pointer> getByFilter(Session& session,
@@ -61,21 +60,21 @@ class Track : public Wt::Dbo::Dbo<Track>
static std::vector<pointer> getByFilter(Session& session, static std::vector<pointer> getByFilter(Session& session,
const std::set<IdType>& clusters, // tracks that belong to these clusters const std::set<IdType>& clusters, // tracks that belong to these clusters
const std::vector<std::string>& keywords, // name must match all of these keywords const std::vector<std::string>& keywords, // name must match all of these keywords
boost::optional<std::size_t> offset, std::optional<std::size_t> offset,
boost::optional<std::size_t> size, std::optional<std::size_t> size,
bool& moreExpected); bool& moreExpected);
static std::vector<pointer> getAll(Session& session, boost::optional<std::size_t> limit = {}); static std::vector<pointer> getAll(Session& session, std::optional<std::size_t> limit = {});
static std::vector<pointer> getAllRandom(Session& session, boost::optional<std::size_t> limit = {}); static std::vector<pointer> getAllRandom(Session& session, std::optional<std::size_t> limit = {});
static std::vector<IdType> getAllIds(Session& session); // nested transaction static std::vector<IdType> getAllIds(Session& session); // nested transaction
static std::vector<boost::filesystem::path> getAllPaths(Session& session); // nested transaction static std::vector<std::filesystem::path> getAllPaths(Session& session); // nested transaction
static std::vector<pointer> getMBIDDuplicates(Session& session); static std::vector<pointer> getMBIDDuplicates(Session& session);
static std::vector<pointer> getLastAdded(Session& session, const Wt::WDateTime& after, boost::optional<std::size_t> size = 1); static std::vector<pointer> getLastAdded(Session& session, const Wt::WDateTime& after, std::optional<std::size_t> size = 1);
static std::vector<pointer> getAllWithMBIDAndMissingFeatures(Session& session); static std::vector<pointer> getAllWithMBIDAndMissingFeatures(Session& session);
static std::vector<IdType> getAllIdsWithFeatures(Session& session, boost::optional<std::size_t> limit = {}); static std::vector<IdType> getAllIdsWithFeatures(Session& session, std::optional<std::size_t> limit = {});
// Create utility // Create utility
static pointer create(Session& session, const boost::filesystem::path& p); static pointer create(Session& session, const std::filesystem::path& p);
// Accessors // Accessors
void setScanVersion(std::size_t version) { _scanVersion = version; } void setScanVersion(std::size_t version) { _scanVersion = version; }
@@ -98,20 +97,20 @@ class Track : public Wt::Dbo::Dbo<Track>
void setFeatures(const Wt::Dbo::ptr<TrackFeatures>& features); void setFeatures(const Wt::Dbo::ptr<TrackFeatures>& features);
std::size_t getScanVersion() const { return _scanVersion; } std::size_t getScanVersion() const { return _scanVersion; }
boost::optional<std::size_t> getTrackNumber() const; std::optional<std::size_t> getTrackNumber() const;
boost::optional<std::size_t> getDiscNumber() const; std::optional<std::size_t> getDiscNumber() const;
std::string getName() const { return _name; } std::string getName() const { return _name; }
boost::filesystem::path getPath() const { return _filePath; } std::filesystem::path getPath() const { return _filePath; }
std::chrono::milliseconds getDuration() const { return _duration; } std::chrono::milliseconds getDuration() const { return _duration; }
boost::optional<int> getYear() const; std::optional<int> getYear() const;
boost::optional<int> getOriginalYear() const; std::optional<int> getOriginalYear() const;
Wt::WDateTime getLastWriteTime() const { return _fileLastWrite; } Wt::WDateTime getLastWriteTime() const { return _fileLastWrite; }
Wt::WDateTime getAddedTime() const { return _fileAdded; } Wt::WDateTime getAddedTime() const { return _fileAdded; }
bool hasCover() const { return _hasCover; } bool hasCover() const { return _hasCover; }
const std::string& getMBID() const { return _MBID; } const std::string& getMBID() const { return _MBID; }
boost::optional<std::string> getCopyright() const; std::optional<std::string> getCopyright() const;
boost::optional<std::string> getCopyrightURL() const; std::optional<std::string> getCopyrightURL() const;
std::vector<Wt::Dbo::ptr<Artist>> getArtists(TrackArtistLink::Type type = {TrackArtistLink::Type::Artist}) const; std::vector<Wt::Dbo::ptr<Artist>> getArtists(TrackArtistLink::Type type = TrackArtistLink::Type::Artist) const;
std::vector<Wt::Dbo::ptr<TrackArtistLink>> getArtistLinks() const; std::vector<Wt::Dbo::ptr<TrackArtistLink>> getArtistLinks() const;
Wt::Dbo::ptr<Release> getRelease() const { return _release; } Wt::Dbo::ptr<Release> getRelease() const { return _release; }
std::vector<Wt::Dbo::ptr<Cluster>> getClusters() const; std::vector<Wt::Dbo::ptr<Cluster>> getClusters() const;
+2 -2
View File
@@ -100,7 +100,7 @@ TrackList::getById(Session& session, IdType id)
std::vector<Wt::Dbo::ptr<TrackListEntry>> std::vector<Wt::Dbo::ptr<TrackListEntry>>
TrackList::getEntries(boost::optional<std::size_t> offset, boost::optional<std::size_t> size) const TrackList::getEntries(std::optional<std::size_t> offset, std::optional<std::size_t> size) const
{ {
assert(session()); assert(session());
assert(IdIsValid(self()->id())); assert(IdIsValid(self()->id()));
@@ -116,7 +116,7 @@ TrackList::getEntries(boost::optional<std::size_t> offset, boost::optional<std::
} }
std::vector<Wt::Dbo::ptr<TrackListEntry>> std::vector<Wt::Dbo::ptr<TrackListEntry>>
TrackList::getEntriesReverse(boost::optional<std::size_t> offset, boost::optional<std::size_t> size) const TrackList::getEntriesReverse(std::optional<std::size_t> offset, std::optional<std::size_t> size) const
{ {
assert(session()); assert(session());
assert(IdIsValid(self()->id())); assert(IdIsValid(self()->id()));
+4 -5
View File
@@ -19,12 +19,11 @@
#pragma once #pragma once
#include <boost/optional.hpp> #include <optional>
#include <string>
#include <Wt/Dbo/Dbo.h> #include <Wt/Dbo/Dbo.h>
#include <string>
#include "Types.hpp" #include "Types.hpp"
namespace Database { namespace Database {
@@ -79,8 +78,8 @@ class TrackList : public Wt::Dbo::Dbo<TrackList>
// Get tracks, ordered by position // Get tracks, ordered by position
std::size_t getCount() const; std::size_t getCount() const;
Wt::Dbo::ptr<TrackListEntry> getEntry(std::size_t pos) const; Wt::Dbo::ptr<TrackListEntry> getEntry(std::size_t pos) const;
std::vector<Wt::Dbo::ptr<TrackListEntry>> getEntries(boost::optional<std::size_t> offset = {}, boost::optional<std::size_t> size = {}) const; std::vector<Wt::Dbo::ptr<TrackListEntry>> getEntries(std::optional<std::size_t> offset = {}, std::optional<std::size_t> size = {}) const;
std::vector<Wt::Dbo::ptr<TrackListEntry>> getEntriesReverse(boost::optional<std::size_t> offset = {}, boost::optional<std::size_t> size = {}) const; std::vector<Wt::Dbo::ptr<TrackListEntry>> getEntriesReverse(std::optional<std::size_t> offset = {}, std::optional<std::size_t> size = {}) const;
std::vector<IdType> getTrackIds() const; std::vector<IdType> getTrackIds() const;
+1 -1
View File
@@ -247,7 +247,7 @@ User::hasStarredRelease(Wt::Dbo::ptr<Release> release) const
} }
std::vector<Wt::Dbo::ptr<Release>> std::vector<Wt::Dbo::ptr<Release>>
User::getStarredReleases(boost::optional<std::size_t> offset, boost::optional<std::size_t> limit) const User::getStarredReleases(std::optional<std::size_t> offset, std::optional<std::size_t> limit) const
{ {
Wt::Dbo::collection<Wt::Dbo::ptr<Release>> res = _starredReleases.find() Wt::Dbo::collection<Wt::Dbo::ptr<Release>> res = _starredReleases.find()
.offset(offset ? static_cast<int>(*offset) : -1) .offset(offset ? static_cast<int>(*offset) : -1)
+2 -3
View File
@@ -19,10 +19,9 @@
#pragma once #pragma once
#include <optional>
#include <vector> #include <vector>
#include <boost/optional.hpp>
#include <Wt/Dbo/Dbo.h> #include <Wt/Dbo/Dbo.h>
#include <Wt/WDateTime.h> #include <Wt/WDateTime.h>
@@ -162,7 +161,7 @@ class User : public Wt::Dbo::Dbo<User>
void starRelease(Wt::Dbo::ptr<Release> release); void starRelease(Wt::Dbo::ptr<Release> release);
void unstarRelease(Wt::Dbo::ptr<Release> release); void unstarRelease(Wt::Dbo::ptr<Release> release);
bool hasStarredRelease(Wt::Dbo::ptr<Release> release) const; bool hasStarredRelease(Wt::Dbo::ptr<Release> release) const;
std::vector<Wt::Dbo::ptr<Release>> getStarredReleases(boost::optional<std::size_t> offset = {}, boost::optional<std::size_t> size = {}) const; std::vector<Wt::Dbo::ptr<Release>> getStarredReleases(std::optional<std::size_t> offset = {}, std::optional<std::size_t> size = {}) const;
void starTrack(Wt::Dbo::ptr<Track> track); void starTrack(Wt::Dbo::ptr<Track> track);
void unstarTrack(Wt::Dbo::ptr<Track> track); void unstarTrack(Wt::Dbo::ptr<Track> track);
+1 -1
View File
@@ -68,7 +68,7 @@ Image::load(const std::vector<unsigned char>& rawData)
} }
bool bool
Image::load(boost::filesystem::path p) Image::load(const std::filesystem::path& p)
{ {
try try
{ {
+2 -3
View File
@@ -19,10 +19,9 @@
#pragma once #pragma once
#include <filesystem>
#include <vector> #include <vector>
#include <boost/filesystem/path.hpp>
#include <Magick++.h> #include <Magick++.h>
namespace Image namespace Image
@@ -49,7 +48,7 @@ class Image
// input // input
bool load(const std::vector<unsigned char>& rawData); bool load(const std::vector<unsigned char>& rawData);
bool load(boost::filesystem::path p); bool load(const std::filesystem::path& p);
Geometry getSize() const; Geometry getSize() const;
+8 -9
View File
@@ -17,7 +17,6 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <boost/filesystem.hpp>
#include <boost/property_tree/xml_parser.hpp> #include <boost/property_tree/xml_parser.hpp>
#include <Wt/WServer.h> #include <Wt/WServer.h>
@@ -29,6 +28,7 @@
#include "auth/AuthTokenService.hpp" #include "auth/AuthTokenService.hpp"
#include "auth/PasswordService.hpp" #include "auth/PasswordService.hpp"
#include "cover/CoverArtGrabber.hpp" #include "cover/CoverArtGrabber.hpp"
#include "database/Db.hpp"
#include "image/Image.hpp" #include "image/Image.hpp"
#include "scanner/MediaScanner.hpp" #include "scanner/MediaScanner.hpp"
#include "similarity/features/SimilarityFeaturesScannerAddon.hpp" #include "similarity/features/SimilarityFeaturesScannerAddon.hpp"
@@ -42,9 +42,9 @@ std::vector<std::string> generateWtConfig(std::string execPath)
{ {
std::vector<std::string> args; std::vector<std::string> args;
const boost::filesystem::path wtConfigPath {getService<Config>()->getPath("working-dir") / "wt_config.xml"}; const std::filesystem::path wtConfigPath {getService<Config>()->getPath("working-dir") / "wt_config.xml"};
const boost::filesystem::path wtLogFilePath {getService<Config>()->getPath("log-file", "/var/log/lms.log")}; const std::filesystem::path wtLogFilePath {getService<Config>()->getPath("log-file", "/var/log/lms.log")};
const boost::filesystem::path wtAccessLogFilePath {getService<Config>()->getPath("access-log-file", "/var/log/lms.access.log")}; const std::filesystem::path wtAccessLogFilePath {getService<Config>()->getPath("access-log-file", "/var/log/lms.access.log")};
args.push_back(execPath); args.push_back(execPath);
args.push_back("--config=" + wtConfigPath.string()); args.push_back("--config=" + wtConfigPath.string());
@@ -86,7 +86,7 @@ std::vector<std::string> generateWtConfig(std::string execPath)
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
boost::filesystem::path configFilePath {"/etc/lms.conf"}; std::filesystem::path configFilePath {"/etc/lms.conf"};
int res = EXIT_FAILURE; int res = EXIT_FAILURE;
assert(argc > 0); assert(argc > 0);
@@ -110,8 +110,8 @@ int main(int argc, char* argv[])
ServiceProvider<Config>::create(configFilePath); ServiceProvider<Config>::create(configFilePath);
// Make sure the working directory exists // Make sure the working directory exists
boost::filesystem::create_directories(getService<Config>()->getPath("working-dir")); std::filesystem::create_directories(getService<Config>()->getPath("working-dir"));
boost::filesystem::create_directories(getService<Config>()->getPath("working-dir") / "cache"); std::filesystem::create_directories(getService<Config>()->getPath("working-dir") / "cache");
// Construct WT configuration and get the argc/argv back // Construct WT configuration and get the argc/argv back
std::vector<std::string> wtServerArgs = generateWtConfig(argv[0]); std::vector<std::string> wtServerArgs = generateWtConfig(argv[0]);
@@ -128,11 +128,10 @@ int main(int argc, char* argv[])
// lib init // lib init
Image::init(argv[0]); Image::init(argv[0]);
Av::AvInit();
Av::Transcoder::init(); Av::Transcoder::init();
// Initializing a connection pool to the database that will be shared along services // Initializing a connection pool to the database that will be shared along services
Database::Database database {getService<Config>()->getPath("working-dir") / "lms.db"}; Database::Db database {getService<Config>()->getPath("working-dir") / "lms.db"};
UserInterface::LmsApplicationGroupContainer appGroups; UserInterface::LmsApplicationGroupContainer appGroups;
+7 -7
View File
@@ -29,21 +29,21 @@ namespace MetaData
using MetadataMap = std::map<std::string, std::string>; using MetadataMap = std::map<std::string, std::string>;
boost::optional<std::string> std::optional<std::string>
findFirstValueOf(const MetadataMap& metadataMap, std::initializer_list<std::string> tags) findFirstValueOf(const MetadataMap& metadataMap, std::initializer_list<std::string> tags)
{ {
auto it = std::find_first_of(std::cbegin(metadataMap), std::cend(metadataMap), std::cbegin(tags), std::cend(tags), [](const auto& it, const auto& str) { return it.first == str; }); auto it = std::find_first_of(std::cbegin(metadataMap), std::cend(metadataMap), std::cbegin(tags), std::cend(tags), [](const auto& it, const auto& str) { return it.first == str; });
if (it == std::cend(metadataMap)) if (it == std::cend(metadataMap))
return boost::none; return std::nullopt;
return stringTrim(it->second); return stringTrim(it->second);
} }
static static
boost::optional<Album> std::optional<Album>
getAlbum(const MetadataMap& metadataMap) getAlbum(const MetadataMap& metadataMap)
{ {
boost::optional<Album> res; std::optional<Album> res;
auto album {findFirstValueOf(metadataMap, {"ALBUM"})}; auto album {findFirstValueOf(metadataMap, {"ALBUM"})};
if (!album) if (!album)
@@ -115,8 +115,8 @@ getArtists(const MetadataMap& metadataMap)
return artists; return artists;
} }
boost::optional<Track> std::optional<Track>
AvFormat::parse(const boost::filesystem::path& p, bool debug) AvFormat::parse(const std::filesystem::path& p, bool debug)
{ {
Track track; Track track;
@@ -215,7 +215,7 @@ AvFormat::parse(const boost::filesystem::path& p, bool debug)
} }
catch(Av::MediaFileException& e) catch(Av::MediaFileException& e)
{ {
return boost::none; return std::nullopt;
} }
return track; return track;
+1 -4
View File
@@ -19,9 +19,6 @@
#pragma once #pragma once
#include <map>
#include <string>
#include "MetaData.hpp" #include "MetaData.hpp"
namespace MetaData namespace MetaData
@@ -31,7 +28,7 @@ namespace MetaData
class AvFormat : public Parser class AvFormat : public Parser
{ {
public: public:
boost::optional<Track> parse(const boost::filesystem::path& p, bool debug = false) override; std::optional<Track> parse(const std::filesystem::path& p, bool debug = false) override;
}; };
} // namespace MetaData } // namespace MetaData
+10 -11
View File
@@ -20,12 +20,11 @@
#pragma once #pragma once
#include <chrono> #include <chrono>
#include <filesystem>
#include <map> #include <map>
#include <optional>
#include <set> #include <set>
#include <boost/optional.hpp>
#include <boost/filesystem.hpp>
namespace MetaData namespace MetaData
{ {
using Clusters = std::map<std::string /* type */, std::set<std::string> /* names */>; using Clusters = std::map<std::string /* type */, std::set<std::string> /* names */>;
@@ -54,15 +53,15 @@ namespace MetaData
std::string title; std::string title;
std::string musicBrainzTrackID; std::string musicBrainzTrackID;
std::string musicBrainzRecordID; std::string musicBrainzRecordID;
boost::optional<Album> album; std::optional<Album> album;
Clusters clusters; Clusters clusters;
std::chrono::milliseconds duration {}; std::chrono::milliseconds duration {};
boost::optional<std::size_t> trackNumber; std::optional<std::size_t> trackNumber;
boost::optional<std::size_t> totalTrack; std::optional<std::size_t> totalTrack;
boost::optional<std::size_t> discNumber; std::optional<std::size_t> discNumber;
boost::optional<std::size_t> totalDisc; std::optional<std::size_t> totalDisc;
boost::optional<int> year; std::optional<int> year;
boost::optional<int> originalYear; std::optional<int> originalYear;
bool hasCover {false}; bool hasCover {false};
std::vector<AudioStream> audioStreams; std::vector<AudioStream> audioStreams;
std::string acoustID; std::string acoustID;
@@ -73,7 +72,7 @@ namespace MetaData
class Parser class Parser
{ {
public: public:
virtual boost::optional<Track> parse(const boost::filesystem::path& p, bool debug = false) = 0; virtual std::optional<Track> parse(const std::filesystem::path& p, bool debug = false) = 0;
void setClusterTypeNames(const std::set<std::string>& clusterTypeNames) { _clusterTypeNames = clusterTypeNames; } void setClusterTypeNames(const std::set<std::string>& clusterTypeNames) { _clusterTypeNames = clusterTypeNames; }
+6 -6
View File
@@ -126,10 +126,10 @@ getAlbumArtists(const TagLib::PropertyMap& properties)
} }
static static
boost::optional<Album> std::optional<Album>
getAlbum(const TagLib::PropertyMap& properties) getAlbum(const TagLib::PropertyMap& properties)
{ {
boost::optional<Album> res; std::optional<Album> res;
std::vector<std::string> albumName {getPropertyValues(properties, "ALBUM")}; std::vector<std::string> albumName {getPropertyValues(properties, "ALBUM")};
if (albumName.empty()) if (albumName.empty())
@@ -145,8 +145,8 @@ getAlbum(const TagLib::PropertyMap& properties)
return res; return res;
} }
boost::optional<Track> std::optional<Track>
TagLibParser::parse(const boost::filesystem::path& p, bool debug) TagLibParser::parse(const std::filesystem::path& p, bool debug)
{ {
TagLib::FileRef f {p.string().c_str(), TagLib::FileRef f {p.string().c_str(),
true, // read audio properties true, // read audio properties
@@ -155,13 +155,13 @@ TagLibParser::parse(const boost::filesystem::path& p, bool debug)
if (f.isNull()) if (f.isNull())
{ {
LMS_LOG(METADATA, ERROR) << "File '" << p.string() << "': parsing failed"; LMS_LOG(METADATA, ERROR) << "File '" << p.string() << "': parsing failed";
return boost::none; return std::nullopt;
} }
if (!f.audioProperties()) if (!f.audioProperties())
{ {
LMS_LOG(METADATA, INFO) << "File '" << p.string() << "': no audio properties"; LMS_LOG(METADATA, INFO) << "File '" << p.string() << "': no audio properties";
return boost::none; return std::nullopt;
} }
Track track; Track track;
+1 -4
View File
@@ -19,9 +19,6 @@
#pragma once #pragma once
#include <map>
#include <string>
#include "MetaData.hpp" #include "MetaData.hpp"
namespace MetaData namespace MetaData
@@ -31,7 +28,7 @@ namespace MetaData
class TagLibParser : public Parser class TagLibParser : public Parser
{ {
public: public:
boost::optional<Track> parse(const boost::filesystem::path& p, bool debug = false) override; std::optional<Track> parse(const std::filesystem::path& p, bool debug = false) override;
}; };
} // namespace MetaData } // namespace MetaData
+22 -23
View File
@@ -21,7 +21,6 @@
#include <stdexcept> #include <stdexcept>
#include <boost/filesystem.hpp>
#include <boost/asio/placeholders.hpp> #include <boost/asio/placeholders.hpp>
#include <Wt/WLocalDateTime.h> #include <Wt/WLocalDateTime.h>
@@ -63,15 +62,15 @@ getNextFirstOfMonth(Wt::WDate current)
} }
bool bool
isFileSupported(const boost::filesystem::path& file, const std::set<boost::filesystem::path>& extensions) isFileSupported(const std::filesystem::path& file, const std::set<std::filesystem::path>& extensions)
{ {
return (extensions.find(file.extension()) != extensions.end()); return (extensions.find(file.extension()) != extensions.end());
} }
bool bool
isPathInParentPath(const boost::filesystem::path& path, const boost::filesystem::path& parentPath) isPathInParentPath(const std::filesystem::path& path, const std::filesystem::path& parentPath)
{ {
boost::filesystem::path curPath = path; std::filesystem::path curPath = path;
while (curPath.has_parent_path()) while (curPath.has_parent_path())
{ {
@@ -327,25 +326,25 @@ MediaScanner::scheduleNextScan()
void void
MediaScanner::countAllFiles(Stats& stats) MediaScanner::countAllFiles(Stats& stats)
{ {
boost::system::error_code ec; std::error_code ec;
stats.totalFiles = 0; stats.totalFiles = 0;
boost::filesystem::recursive_directory_iterator itPath {_mediaDirectory, ec}; std::filesystem::recursive_directory_iterator itPath {_mediaDirectory, ec};
if (ec) if (ec)
{ {
LMS_LOG(DBUPDATER, ERROR) << "Cannot iterate over '" << _mediaDirectory.string() << "': " << ec.message(); LMS_LOG(DBUPDATER, ERROR) << "Cannot iterate over '" << _mediaDirectory.string() << "': " << ec.message();
return; return;
} }
boost::filesystem::recursive_directory_iterator itEnd; std::filesystem::recursive_directory_iterator itEnd;
while (_running && itPath != itEnd) while (_running && itPath != itEnd)
{ {
const boost::filesystem::path& path {*itPath}; const std::filesystem::path& path {*itPath};
if (!ec) if (!ec)
{ {
if (boost::filesystem::is_regular(path) && isFileSupported(path, _fileExtensions)) if (std::filesystem::is_regular_file(path) && isFileSupported(path, _fileExtensions))
stats.totalFiles++; stats.totalFiles++;
if (stats.totalFiles % 250 == 0) if (stats.totalFiles % 250 == 0)
@@ -498,11 +497,11 @@ void MediaScanner::notifyInProgressIfNeeded(Stats& stats)
} }
void void
MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan, Stats& stats) MediaScanner::scanAudioFile(const std::filesystem::path& file, bool forceScan, Stats& stats)
{ {
notifyInProgressIfNeeded(stats); notifyInProgressIfNeeded(stats);
auto lastWriteTime = Wt::WDateTime::fromTime_t(boost::filesystem::last_write_time(file)); const auto lastWriteTime {Wt::WDateTime::fromTimePoint(std::filesystem::last_write_time(file))};
if (!forceScan) if (!forceScan)
{ {
@@ -518,7 +517,7 @@ MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan,
} }
} }
boost::optional<MetaData::Track> trackInfo {_metadataParser.parse(file)}; std::optional<MetaData::Track> trackInfo {_metadataParser.parse(file)};
if (!trackInfo) if (!trackInfo)
{ {
stats.scanErrors++; stats.scanErrors++;
@@ -642,11 +641,11 @@ MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan,
} }
void void
MediaScanner::scanMediaDirectory(boost::filesystem::path mediaDirectory, bool forceScan, Stats& stats) MediaScanner::scanMediaDirectory(const std::filesystem::path& mediaDirectory, bool forceScan, Stats& stats)
{ {
boost::system::error_code ec; std::error_code ec;
boost::filesystem::recursive_directory_iterator itPath(mediaDirectory, ec); std::filesystem::recursive_directory_iterator itPath {mediaDirectory, ec};
if (ec) if (ec)
{ {
LMS_LOG(DBUPDATER, ERROR) << "Cannot iterate over '" << mediaDirectory.string() << "': " << ec.message(); LMS_LOG(DBUPDATER, ERROR) << "Cannot iterate over '" << mediaDirectory.string() << "': " << ec.message();
@@ -654,17 +653,17 @@ MediaScanner::scanMediaDirectory(boost::filesystem::path mediaDirectory, bool fo
return; return;
} }
boost::filesystem::recursive_directory_iterator itEnd; std::filesystem::recursive_directory_iterator itEnd;
while (_running && itPath != itEnd) while (_running && itPath != itEnd)
{ {
const boost::filesystem::path& path {*itPath}; const std::filesystem::path& path {*itPath};
if (ec) if (ec)
{ {
LMS_LOG(DBUPDATER, ERROR) << "Cannot process entry '" << path.string() << "': " << ec.message(); LMS_LOG(DBUPDATER, ERROR) << "Cannot process entry '" << path.string() << "': " << ec.message();
stats.scanErrors++; stats.scanErrors++;
} }
else if (boost::filesystem::is_regular(path)) else if (std::filesystem::is_regular_file(path))
{ {
if (isFileSupported(path, _fileExtensions)) if (isFileSupported(path, _fileExtensions))
scanAudioFile(path, forceScan, stats ); scanAudioFile(path, forceScan, stats );
@@ -678,14 +677,14 @@ MediaScanner::scanMediaDirectory(boost::filesystem::path mediaDirectory, bool fo
// Check if a file exists and is still in a media directory // Check if a file exists and is still in a media directory
static bool static bool
checkFile(const boost::filesystem::path& p, const boost::filesystem::path& mediaDirectory, const std::set<boost::filesystem::path>& extensions) checkFile(const std::filesystem::path& p, const std::filesystem::path& mediaDirectory, const std::set<std::filesystem::path>& extensions)
{ {
try try
{ {
// For each track, make sure the the file still exists // For each track, make sure the the file still exists
// and still belongs to a media directory // and still belongs to a media directory
if (!boost::filesystem::exists( p ) if (!std::filesystem::exists( p )
|| !boost::filesystem::is_regular( p ) ) || !std::filesystem::is_regular_file( p ) )
{ {
LMS_LOG(DBUPDATER, INFO) << "Removing '" << p.string() << "': missing"; LMS_LOG(DBUPDATER, INFO) << "Removing '" << p.string() << "': missing";
return false; return false;
@@ -706,7 +705,7 @@ checkFile(const boost::filesystem::path& p, const boost::filesystem::path& media
return true; return true;
} }
catch (boost::filesystem::filesystem_error& e) catch (std::filesystem::filesystem_error& e)
{ {
LMS_LOG(DBUPDATER, ERROR) << "Caught exception while checking file '" << p.string() << "': " << e.what(); LMS_LOG(DBUPDATER, ERROR) << "Caught exception while checking file '" << p.string() << "': " << e.what();
return false; return false;
@@ -716,7 +715,7 @@ checkFile(const boost::filesystem::path& p, const boost::filesystem::path& media
void void
MediaScanner::removeMissingTracks(Stats& stats) MediaScanner::removeMissingTracks(Stats& stats)
{ {
std::vector<boost::filesystem::path> trackPaths; std::vector<std::filesystem::path> trackPaths;
{ {
auto transaction {_dbSession->createSharedTransaction()}; auto transaction {_dbSession->createSharedTransaction()};
trackPaths = Track::getAllPaths(*_dbSession);; trackPaths = Track::getAllPaths(*_dbSession);;
+10 -9
View File
@@ -21,6 +21,7 @@
#include <chrono> #include <chrono>
#include <mutex> #include <mutex>
#include <optional>
#include <Wt/WDateTime.h> #include <Wt/WDateTime.h>
#include <Wt/WIOService.h> #include <Wt/WIOService.h>
@@ -86,8 +87,8 @@ class MediaScanner
{ {
State currentState {State::NotScheduled}; State currentState {State::NotScheduled};
Wt::WDateTime nextScheduledScan; Wt::WDateTime nextScheduledScan;
boost::optional<Stats> lastScanStats; std::optional<Stats> lastScanStats;
boost::optional<Stats> inProgressStats; std::optional<Stats> inProgressStats;
}; };
Status getStatus(); Status getStatus();
@@ -110,7 +111,7 @@ class MediaScanner
// Update database (scheduled callback) // Update database (scheduled callback)
void scan(boost::system::error_code ec); void scan(boost::system::error_code ec);
void scanMediaDirectory( boost::filesystem::path mediaDirectory, bool forceScan, Stats& stats); void scanMediaDirectory( const std::filesystem::path& mediaDirectory, bool forceScan, Stats& stats);
// Helpers // Helpers
void refreshScanSettings(); void refreshScanSettings();
@@ -119,8 +120,8 @@ class MediaScanner
void removeMissingTracks(Stats& stats); void removeMissingTracks(Stats& stats);
void removeOrphanEntries(); void removeOrphanEntries();
void checkDuplicatedAudioFiles(Stats& stats); void checkDuplicatedAudioFiles(Stats& stats);
void scanAudioFile(const boost::filesystem::path& file, bool forceScan, Stats& stats); void scanAudioFile(const std::filesystem::path& file, bool forceScan, Stats& stats);
Database::IdType doScanAudioFile(const boost::filesystem::path& file, Stats& stats); Database::IdType doScanAudioFile(const std::filesystem::path& file, Stats& stats);
void notifyInProgressIfNeeded(Stats& stats); void notifyInProgressIfNeeded(Stats& stats);
void notifyInProgress(Stats& stats); void notifyInProgress(Stats& stats);
@@ -137,16 +138,16 @@ class MediaScanner
std::mutex _statusMutex; std::mutex _statusMutex;
State _curState {State::NotScheduled}; State _curState {State::NotScheduled};
boost::optional<Stats> _inProgressStats; std::optional<Stats> _inProgressStats;
boost::optional<Stats> _lastScanStats; std::optional<Stats> _lastScanStats;
Wt::WDateTime _nextScheduledScan; Wt::WDateTime _nextScheduledScan;
// Current scan settings // Current scan settings
std::size_t _scanVersion {}; std::size_t _scanVersion {};
Wt::WTime _startTime; Wt::WTime _startTime;
Database::ScanSettings::UpdatePeriod _updatePeriod {Database::ScanSettings::UpdatePeriod::Never}; Database::ScanSettings::UpdatePeriod _updatePeriod {Database::ScanSettings::UpdatePeriod::Never};
std::set<boost::filesystem::path> _fileExtensions; std::set<std::filesystem::path> _fileExtensions;
boost::filesystem::path _mediaDirectory; std::filesystem::path _mediaDirectory;
}; // class MediaScanner }; // class MediaScanner
@@ -31,24 +31,24 @@ namespace Similarity {
static static
boost::filesystem::path getCacheDirectory() std::filesystem::path getCacheDirectory()
{ {
return getService<Config>()->getPath("working-dir") / "cache" / "features"; return getService<Config>()->getPath("working-dir") / "cache" / "features";
} }
static boost::filesystem::path getCacheNetworkFilePath() static std::filesystem::path getCacheNetworkFilePath()
{ {
return getCacheDirectory() / "network"; return getCacheDirectory() / "network";
}; };
static boost::filesystem::path getCacheTrackPositionsFilePath() static std::filesystem::path getCacheTrackPositionsFilePath()
{ {
return getCacheDirectory() / "track_positions"; return getCacheDirectory() / "track_positions";
} }
static static
bool bool
networkToCacheFile(const SOM::Network& network, boost::filesystem::path path) networkToCacheFile(const SOM::Network& network, std::filesystem::path path)
{ {
try try
{ {
@@ -91,8 +91,8 @@ networkToCacheFile(const SOM::Network& network, boost::filesystem::path path)
} }
static static
boost::optional<SOM::Network> std::optional<SOM::Network>
createNetworkFromCacheFile(boost::filesystem::path path) createNetworkFromCacheFile(std::filesystem::path path)
{ {
try try
{ {
@@ -137,13 +137,13 @@ createNetworkFromCacheFile(boost::filesystem::path path)
catch (boost::property_tree::ptree_error& error) catch (boost::property_tree::ptree_error& error)
{ {
LMS_LOG(SIMILARITY, ERROR) << "Cannot read network cache: " << error.what(); LMS_LOG(SIMILARITY, ERROR) << "Cannot read network cache: " << error.what();
return boost::none; return std::nullopt;
} }
} }
static static
bool bool
objectPositionToCacheFile(const std::map<Database::IdType, std::set<SOM::Position>>& objectsPosition, boost::filesystem::path path) objectPositionToCacheFile(const std::map<Database::IdType, std::set<SOM::Position>>& objectsPosition, std::filesystem::path path)
{ {
try try
{ {
@@ -178,8 +178,8 @@ objectPositionToCacheFile(const std::map<Database::IdType, std::set<SOM::Positio
} }
static static
boost::optional<std::map<Database::IdType, std::set<SOM::Position>>> std::optional<std::map<Database::IdType, std::set<SOM::Position>>>
createObjectPositionsFromCacheFile(boost::filesystem::path path) createObjectPositionsFromCacheFile(std::filesystem::path path)
{ {
try try
{ {
@@ -210,21 +210,21 @@ createObjectPositionsFromCacheFile(boost::filesystem::path path)
catch (boost::property_tree::ptree_error& error) catch (boost::property_tree::ptree_error& error)
{ {
LMS_LOG(SIMILARITY, ERROR) << "Cannot create object position from cache file: " << error.what(); LMS_LOG(SIMILARITY, ERROR) << "Cannot create object position from cache file: " << error.what();
return boost::none; return std::nullopt;
} }
} }
void void
FeaturesCache::invalidate() FeaturesCache::invalidate()
{ {
boost::filesystem::remove(getCacheNetworkFilePath()); std::filesystem::remove(getCacheNetworkFilePath());
boost::filesystem::remove(getCacheTrackPositionsFilePath()); std::filesystem::remove(getCacheTrackPositionsFilePath());
} }
boost::optional<FeaturesCache> std::optional<FeaturesCache>
FeaturesCache::read() FeaturesCache::read()
{ {
boost::optional<FeaturesCache> res; std::optional<FeaturesCache> res;
auto network{createNetworkFromCacheFile(getCacheNetworkFilePath())}; auto network{createNetworkFromCacheFile(getCacheNetworkFilePath())};
if (!network) if (!network)
@@ -240,7 +240,7 @@ FeaturesCache::read()
void void
FeaturesCache::write() FeaturesCache::write()
{ {
boost::filesystem::create_directories(getService<Config>()->getPath("working-dir") / "cache" / "features"); std::filesystem::create_directories(getService<Config>()->getPath("working-dir") / "cache" / "features");
if (!networkToCacheFile(_network, getCacheNetworkFilePath()) if (!networkToCacheFile(_network, getCacheNetworkFilePath())
|| !objectPositionToCacheFile(_trackPositions, getCacheTrackPositionsFilePath())) || !objectPositionToCacheFile(_trackPositions, getCacheTrackPositionsFilePath()))
@@ -20,6 +20,7 @@
#pragma once #pragma once
#include <map> #include <map>
#include <optional>
#include <set> #include <set>
#include "database/Types.hpp" #include "database/Types.hpp"
@@ -33,7 +34,7 @@ class FeaturesCache
static void invalidate(); static void invalidate();
static boost::optional<FeaturesCache> read(); static std::optional<FeaturesCache> read();
void write(); void write();
private: private:
@@ -56,7 +56,7 @@ getTracksWithMBIDAndMissingFeatures(Database::Session& dbSession)
FeaturesScannerAddon::FeaturesScannerAddon(std::unique_ptr<Database::Session> dbSession) FeaturesScannerAddon::FeaturesScannerAddon(std::unique_ptr<Database::Session> dbSession)
: _dbSession {std::move(dbSession)} : _dbSession {std::move(dbSession)}
{ {
boost::optional<Similarity::FeaturesCache> cache {Similarity::FeaturesCache::read()}; std::optional<Similarity::FeaturesCache> cache {Similarity::FeaturesCache::read()};
if (cache) if (cache)
{ {
auto searcher {std::make_shared<Similarity::FeaturesSearcher>(*_dbSession.get(), *cache, [&]() { return _stopRequested; })}; auto searcher {std::make_shared<Similarity::FeaturesSearcher>(*_dbSession.get(), *cache, [&]() { return _stopRequested; })};
@@ -40,8 +40,8 @@ class FeaturesScannerAddon final : public Scanner::MediaScannerAddon
void requestStop() override; void requestStop() override;
void preScanComplete() override; void preScanComplete() override;
void trackAdded(Database::IdType trackId) override {} void trackAdded(Database::IdType) override {}
void trackToRemove(Database::IdType trackId) override {} void trackToRemove(Database::IdType) override {}
void trackUpdated(Database::IdType trackId) override; void trackUpdated(Database::IdType trackId) override;
bool fetchFeatures(Database::IdType trackId, const std::string& MBID); bool fetchFeatures(Database::IdType trackId, const std::string& MBID);
@@ -68,10 +68,10 @@ getFeatureInfoMapNbDimensions(const FeatureInfoMap& featureInfoMap)
} }
static static
boost::optional<SOM::InputVector> std::optional<SOM::InputVector>
getInputVectorFromTrack(Database::Session& session, Database::IdType trackId, const FeatureInfoMap& featuresInfo, std::size_t nbDimensions) getInputVectorFromTrack(Database::Session& session, Database::IdType trackId, const FeatureInfoMap& featuresInfo, std::size_t nbDimensions)
{ {
boost::optional<SOM::InputVector> res {SOM::InputVector {nbDimensions}}; std::optional<SOM::InputVector> res {SOM::InputVector {nbDimensions}};
std::map<std::string, std::vector<double>> features; std::map<std::string, std::vector<double>> features;
for (auto itFeatureInfo : featuresInfo) for (auto itFeatureInfo : featuresInfo)
@@ -150,7 +150,7 @@ FeaturesSearcher::FeaturesSearcher(Database::Session& session, std::function<boo
if (stopRequested()) if (stopRequested())
return; return;
boost::optional<SOM::InputVector> inputVector {getInputVectorFromTrack(session, trackId, featuresInfo, nbDimensions)}; std::optional<SOM::InputVector> inputVector {getInputVectorFromTrack(session, trackId, featuresInfo, nbDimensions)};
if (!inputVector) if (!inputVector)
continue; continue;
@@ -456,7 +456,7 @@ FeaturesSearcher::getSimilarObjects(const std::set<Database::IdType>& ids,
break; break;
// If there is not enough objects, try again with closest neighbour until there is too much distance // If there is not enough objects, try again with closest neighbour until there is too much distance
boost::optional<SOM::Position> closestRefVectorPosition {_network->getClosestRefVectorPosition(searchedRefVectorsPosition, _networkRefVectorsDistanceMedian * 0.75)}; std::optional<SOM::Position> closestRefVectorPosition {_network->getClosestRefVectorPosition(searchedRefVectorsPosition, _networkRefVectorsDistanceMedian * 0.75)};
if (!closestRefVectorPosition) if (!closestRefVectorPosition)
break; break;
+6 -6
View File
@@ -189,10 +189,10 @@ Network::getClosestRefVectorPosition(const InputVector& data) const
}); });
} }
boost::optional<Position> std::optional<Position>
Network::getClosestRefVectorPosition(const InputVector& data, InputVector::Distance maxDistance) const Network::getClosestRefVectorPosition(const InputVector& data, InputVector::Distance maxDistance) const
{ {
boost::optional<Position> position {getClosestRefVectorPosition(data)}; std::optional<Position> position {getClosestRefVectorPosition(data)};
if (_distanceFunc(data, _refVectors.get(*position), _weights) > maxDistance) if (_distanceFunc(data, _refVectors.get(*position), _weights) > maxDistance)
position.reset(); position.reset();
@@ -200,7 +200,7 @@ Network::getClosestRefVectorPosition(const InputVector& data, InputVector::Dista
return position; return position;
} }
boost::optional<Position> std::optional<Position>
Network::getClosestRefVectorPosition(const std::set<Position>& refVectorsPosition, InputVector::Distance maxDistance) const Network::getClosestRefVectorPosition(const std::set<Position>& refVectorsPosition, InputVector::Distance maxDistance) const
{ {
std::set<Position> neighboursPosition; std::set<Position> neighboursPosition;
@@ -221,7 +221,7 @@ Network::getClosestRefVectorPosition(const std::set<Position>& refVectorsPositio
neighboursPosition.erase(refVectorPosition); neighboursPosition.erase(refVectorPosition);
if (neighboursPosition.empty()) if (neighboursPosition.empty())
return boost::none; return std::nullopt;
// Now compute the distance for each neighbour // Now compute the distance for each neighbour
struct NeighbourInfo struct NeighbourInfo
@@ -247,9 +247,9 @@ Network::getClosestRefVectorPosition(const std::set<Position>& refVectorsPositio
} }
if (neighboursInfo.empty()) if (neighboursInfo.empty())
return boost::none; return std::nullopt;
auto min {std::min_element(neighboursInfo.begin(), neighboursInfo.end(), auto min {std::min_element(std::cbegin(neighboursInfo), std::cend(neighboursInfo),
[&](const auto& a, const auto& b) [&](const auto& a, const auto& b)
{ {
return a.distance < b.distance; return a.distance < b.distance;
+3 -4
View File
@@ -21,11 +21,10 @@
#include <vector> #include <vector>
#include <set> #include <set>
#include <optional>
#include <ostream> #include <ostream>
#include <functional> #include <functional>
#include <boost/optional.hpp>
#include "utils/Exception.hpp" #include "utils/Exception.hpp"
#include "InputVector.hpp" #include "InputVector.hpp"
#include "Matrix.hpp" #include "Matrix.hpp"
@@ -70,9 +69,9 @@ class Network
const InputVector& getRefVector(const Position& position) const; const InputVector& getRefVector(const Position& position) const;
Position getClosestRefVectorPosition(const InputVector& data) const; Position getClosestRefVectorPosition(const InputVector& data) const;
boost::optional<Position> getClosestRefVectorPosition(const InputVector& data, InputVector::Distance maxDistance) const; std::optional<Position> getClosestRefVectorPosition(const InputVector& data, InputVector::Distance maxDistance) const;
boost::optional<Position> getClosestRefVectorPosition(const std::set<Position>& refVectorsPosition, InputVector::Distance maxDistance) const; std::optional<Position> getClosestRefVectorPosition(const std::set<Position>& refVectorsPosition, InputVector::Distance maxDistance) const;
InputVector::Distance getRefVectorsDistance(const Position& position1, const Position& position2) const; InputVector::Distance getRefVectorsDistance(const Position& position1, const Position& position2) const;
+5 -6
View File
@@ -54,12 +54,12 @@ createAuthToken(Database::IdType userId, const Wt::WDateTime& expiry)
} }
boost::optional<Database::IdType> std::optional<Database::IdType>
processAuthToken(const Wt::WEnvironment& env) processAuthToken(const Wt::WEnvironment& env)
{ {
const std::string* authCookie {env.getCookie(authCookieName)}; const std::string* authCookie {env.getCookie(authCookieName)};
if (!authCookie) if (!authCookie)
return boost::none; return std::nullopt;
const auto res {getService<::Auth::AuthTokenService>()->processAuthToken(LmsApp->getDbSession(), boost::asio::ip::address::from_string(env.clientAddress()), *authCookie)}; const auto res {getService<::Auth::AuthTokenService>()->processAuthToken(LmsApp->getDbSession(), boost::asio::ip::address::from_string(env.clientAddress()), *authCookie)};
switch (res.state) switch (res.state)
@@ -67,7 +67,7 @@ processAuthToken(const Wt::WEnvironment& env)
case ::Auth::AuthTokenService::AuthTokenProcessResult::State::NotFound: case ::Auth::AuthTokenService::AuthTokenProcessResult::State::NotFound:
case ::Auth::AuthTokenService::AuthTokenProcessResult::State::Throttled: case ::Auth::AuthTokenService::AuthTokenProcessResult::State::Throttled:
LmsApp->setCookie(authCookieName, std::string {}, 0, "", "", env.urlScheme() == "https"); LmsApp->setCookie(authCookieName, std::string {}, 0, "", "", env.urlScheme() == "https");
return boost::none; return std::nullopt;
case ::Auth::AuthTokenService::AuthTokenProcessResult::State::Found: case ::Auth::AuthTokenService::AuthTokenProcessResult::State::Found:
createAuthToken(res.authTokenInfo->userId, res.authTokenInfo->expiry); createAuthToken(res.authTokenInfo->userId, res.authTokenInfo->expiry);
@@ -107,7 +107,6 @@ class AuthModel : public Wt::WFormModel
user.modify()->setLastLogin(Wt::WDateTime::currentDateTime()); user.modify()->setLastLogin(Wt::WDateTime::currentDateTime());
_userId = user.id(); _userId = user.id();
const Wt::WDateTime now {Wt::WDateTime::currentDateTime()};
isDemo = user->isDemo(); isDemo = user->isDemo();
} }
@@ -151,11 +150,11 @@ class AuthModel : public Wt::WFormModel
return (validation(field).state() == Wt::ValidationState::Valid); return (validation(field).state() == Wt::ValidationState::Valid);
} }
boost::optional<Database::IdType> getUserId() const { return _userId; } std::optional<Database::IdType> getUserId() const { return _userId; }
private: private:
boost::optional<Database::IdType> _userId; std::optional<Database::IdType> _userId;
}; };
const AuthModel::Field AuthModel::LoginNameField {"login-name"}; const AuthModel::Field AuthModel::LoginNameField {"login-name"};
+1 -3
View File
@@ -19,15 +19,13 @@
#pragma once #pragma once
#include <boost/optional.hpp>
#include <Wt/WTemplateFormView.h> #include <Wt/WTemplateFormView.h>
#include "database/Types.hpp" #include "database/Types.hpp"
namespace UserInterface { namespace UserInterface {
boost::optional<Database::IdType> std::optional<Database::IdType>
processAuthToken(const Wt::WEnvironment& env); processAuthToken(const Wt::WEnvironment& env);
class Auth : public Wt::WTemplateFormView class Auth : public Wt::WTemplateFormView
+7 -6
View File
@@ -33,6 +33,7 @@
#include "cover/CoverArtGrabber.hpp" #include "cover/CoverArtGrabber.hpp"
#include "database/Artist.hpp" #include "database/Artist.hpp"
#include "database/Cluster.hpp" #include "database/Cluster.hpp"
#include "database/Db.hpp"
#include "database/Release.hpp" #include "database/Release.hpp"
#include "database/User.hpp" #include "database/User.hpp"
#include "explore/Explore.hpp" #include "explore/Explore.hpp"
@@ -56,7 +57,7 @@
namespace UserInterface { namespace UserInterface {
std::unique_ptr<Wt::WApplication> std::unique_ptr<Wt::WApplication>
LmsApplication::create(const Wt::WEnvironment& env, Database::Database& db, LmsApplicationGroupContainer& appGroups) LmsApplication::create(const Wt::WEnvironment& env, Database::Db& db, LmsApplicationGroupContainer& appGroups)
{ {
return std::make_unique<LmsApplication>(env, db.createSession(), appGroups); return std::make_unique<LmsApplication>(env, db.createSession(), appGroups);
} }
@@ -496,13 +497,13 @@ LmsApplication::createHome()
playqueue->playNext(); playqueue->playNext();
}); });
playqueue->loadTrack.connect([=] (Database::IdType trackId, bool play) playqueue->trackSelected.connect([=] (Database::IdType trackId, bool play)
{ {
_events.lastLoadedTrackId = trackId; _events.lastLoadedTrackId = trackId;
_events.trackLoaded(trackId, play); _events.trackLoaded(trackId, play);
}); });
playqueue->trackUnload.connect([=] playqueue->trackUnselected.connect([=]
{ {
_events.lastLoadedTrackId.reset(); _events.lastLoadedTrackId.reset();
_events.trackUnloaded(); _events.trackUnloaded();
@@ -555,7 +556,7 @@ LmsApplication::createHome()
}); });
// Events from Application group // Events from Application group
_events.appOpen.connect([=] (LmsApplicationInfo info) _events.appOpen.connect([=] (LmsApplicationInfo)
{ {
// Only one active session by user // Only one active session by user
if (!LmsApp->isUserDemo()) if (!LmsApp->isUserDemo())
@@ -565,10 +566,10 @@ LmsApplication::createHome()
} }
}); });
internalPathChanged().connect(std::bind([=] internalPathChanged().connect([=]
{ {
handlePathChange(mainStack, isUserAdmin()); handlePathChange(mainStack, isUserAdmin());
})); });
handlePathChange(mainStack, isUserAdmin()); handlePathChange(mainStack, isUserAdmin());
} }
+7 -10
View File
@@ -17,14 +17,12 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LMS_APPLICATION_HPP #pragma once
#define LMS_APPLICATION_HPP
#include <boost/optional.hpp> #include <optional>
#include <Wt/WApplication.h> #include <Wt/WApplication.h>
#include "database/Database.hpp"
#include "scanner/MediaScanner.hpp" #include "scanner/MediaScanner.hpp"
#include "LmsApplicationGroup.hpp" #include "LmsApplicationGroup.hpp"
@@ -32,6 +30,7 @@
namespace Database { namespace Database {
class Artist; class Artist;
class Cluster; class Cluster;
class Db;
class Release; class Release;
class User; class User;
} }
@@ -51,7 +50,7 @@ struct Events
// A track is being loaded // A track is being loaded
Wt::Signal<Database::IdType /* trackId */, bool /* play */> trackLoaded; Wt::Signal<Database::IdType /* trackId */, bool /* play */> trackLoaded;
boost::optional<Database::IdType> lastLoadedTrackId; std::optional<Database::IdType> lastLoadedTrackId;
// Unload current track // Unload current track
Wt::Signal<> trackUnloaded; Wt::Signal<> trackUnloaded;
@@ -75,7 +74,7 @@ class LmsApplication : public Wt::WApplication
public: public:
LmsApplication(const Wt::WEnvironment& env, std::unique_ptr<Database::Session> dbSession, LmsApplicationGroupContainer& appGroups); LmsApplication(const Wt::WEnvironment& env, std::unique_ptr<Database::Session> dbSession, LmsApplicationGroupContainer& appGroups);
static std::unique_ptr<Wt::WApplication> create(const Wt::WEnvironment& env, Database::Database& db, LmsApplicationGroupContainer& appGroups); static std::unique_ptr<Wt::WApplication> create(const Wt::WEnvironment& env, Database::Db& db, LmsApplicationGroupContainer& appGroups);
static LmsApplication* instance(); static LmsApplication* instance();
// Session application data // Session application data
@@ -124,8 +123,8 @@ class LmsApplication : public Wt::WApplication
std::unique_ptr<Database::Session> _dbSession; std::unique_ptr<Database::Session> _dbSession;
LmsApplicationGroupContainer& _appGroups; LmsApplicationGroupContainer& _appGroups;
Events _events; Events _events;
boost::optional<Database::IdType> _userId; std::optional<Database::IdType> _userId;
boost::optional<bool> _userAuthStrong; std::optional<bool> _userAuthStrong;
std::shared_ptr<ImageResource> _imageResource; std::shared_ptr<ImageResource> _imageResource;
std::shared_ptr<AudioResource> _audioResource; std::shared_ptr<AudioResource> _audioResource;
}; };
@@ -136,5 +135,3 @@ class LmsApplication : public Wt::WApplication
} // namespace UserInterface } // namespace UserInterface
#endif
+1 -1
View File
@@ -30,7 +30,7 @@ namespace UserInterface {
LmsApplicationInfo LmsApplicationInfo
LmsApplicationInfo::fromEnvironment(const Wt::WEnvironment& env) LmsApplicationInfo::fromEnvironment(const Wt::WEnvironment& env)
{ {
LmsApplicationInfo info = {.userAgent = wApp->environment().agent()}; LmsApplicationInfo info = {.userAgent = env.agent()};
return info; return info;
} }
+9 -9
View File
@@ -139,7 +139,7 @@ PlayQueue::PlayQueue()
trackPos = LmsApp->getUser()->getCurPlayingTrackPos(); trackPos = LmsApp->getUser()->getCurPlayingTrackPos();
} }
load(trackPos, false); loadTrack(trackPos, false);
}); });
trackList = LmsApp->getUser()->getQueuedTrackList(LmsApp->getDbSession()); trackList = LmsApp->getUser()->getQueuedTrackList(LmsApp->getDbSession());
} }
@@ -192,11 +192,11 @@ PlayQueue::stop()
{ {
updateCurrentTrack(false); updateCurrentTrack(false);
_trackPos.reset(); _trackPos.reset();
trackUnload.emit(); trackUnselected.emit();
} }
void void
PlayQueue::load(std::size_t pos, bool play) PlayQueue::loadTrack(std::size_t pos, bool play)
{ {
updateCurrentTrack(false); updateCurrentTrack(false);
@@ -237,7 +237,7 @@ PlayQueue::load(std::size_t pos, bool play)
updateCurrentTrack(true); updateCurrentTrack(true);
loadTrack.emit(trackId, play); trackSelected.emit(trackId, play);
} }
void void
@@ -249,7 +249,7 @@ PlayQueue::playPrevious()
if (*_trackPos == 0) if (*_trackPos == 0)
stop(); stop();
else else
load(*_trackPos - 1, true); loadTrack(*_trackPos - 1, true);
} }
void void
@@ -257,11 +257,11 @@ PlayQueue::playNext()
{ {
if (!_trackPos) if (!_trackPos)
{ {
load(0, true); loadTrack(0, true);
return; return;
} }
load(*_trackPos + 1, true); loadTrack(*_trackPos + 1, true);
} }
void void
@@ -327,7 +327,7 @@ PlayQueue::playTracks(const std::vector<Database::IdType>& trackIds)
{ {
clearTracks(); clearTracks();
enqueueTracks(trackIds); enqueueTracks(trackIds);
load(0, true); loadTrack(0, true);
LmsApp->notifyMsg(MsgType::Info, Wt::WString::trn("Lms.PlayQueue.nb-tracks-playing", trackIds.size()).arg(trackIds.size()), std::chrono::milliseconds(2000)); LmsApp->notifyMsg(MsgType::Info, Wt::WString::trn("Lms.PlayQueue.nb-tracks-playing", trackIds.size()).arg(trackIds.size()), std::chrono::milliseconds(2000));
} }
@@ -377,7 +377,7 @@ PlayQueue::addSome()
{ {
auto pos = _entriesContainer->indexOf(entry); auto pos = _entriesContainer->indexOf(entry);
if (pos >= 0) if (pos >= 0)
load(pos, true); loadTrack(pos, true);
})); }));
Wt::WText* delBtn = entry->bindNew<Wt::WText>("del-btn", Wt::WString::tr("Lms.PlayQueue.template.delete-btn"), Wt::TextFormat::XHTML); Wt::WText* delBtn = entry->bindNew<Wt::WText>("del-btn", Wt::WString::tr("Lms.PlayQueue.template.delete-btn"), Wt::TextFormat::XHTML);
+7 -7
View File
@@ -19,13 +19,13 @@
#pragma once #pragma once
#include <optional>
#include <Wt/WContainerWidget.h> #include <Wt/WContainerWidget.h>
#include <Wt/WPushButton.h> #include <Wt/WPushButton.h>
#include <Wt/WTemplate.h> #include <Wt/WTemplate.h>
#include <Wt/WText.h> #include <Wt/WText.h>
#include <boost/optional.hpp>
#include "database/Types.hpp" #include "database/Types.hpp"
namespace Similarity { namespace Similarity {
@@ -53,10 +53,10 @@ class PlayQueue : public Wt::WTemplate
void playPrevious(); void playPrevious();
// Signal emitted when a track is to be load(and optionally played) // Signal emitted when a track is to be load(and optionally played)
Wt::Signal<Database::IdType /*trackId*/, bool /*play*/> loadTrack; Wt::Signal<Database::IdType /*trackId*/, bool /*play*/> trackSelected;
// Signal emitted when play has to be stopped // Signal emitted when track is unselected (has to be stopped)
Wt::Signal<> trackUnload; Wt::Signal<> trackUnselected;
private: private:
Wt::Dbo::ptr<Database::TrackList> getTrackList(); Wt::Dbo::ptr<Database::TrackList> getTrackList();
@@ -71,7 +71,7 @@ class PlayQueue : public Wt::WTemplate
void updateRepeatBtn(); void updateRepeatBtn();
void updateRadioBtn(); void updateRadioBtn();
void load(std::size_t pos, bool play); void loadTrack(std::size_t pos, bool play);
void stop(); void stop();
void addRadioTrackFromSimilarity(std::shared_ptr<Similarity::Finder> similarityFinder); void addRadioTrackFromSimilarity(std::shared_ptr<Similarity::Finder> similarityFinder);
@@ -85,7 +85,7 @@ class PlayQueue : public Wt::WTemplate
Wt::WText* _nbTracks {}; Wt::WText* _nbTracks {};
Wt::WText* _repeatBtn {}; Wt::WText* _repeatBtn {};
Wt::WText* _radioBtn {}; Wt::WText* _radioBtn {};
boost::optional<std::size_t> _trackPos; // current track position, if set std::optional<std::size_t> _trackPos; // current track position, if set
}; };
} // namespace UserInterface } // namespace UserInterface
+3 -3
View File
@@ -53,7 +53,7 @@ class UserModel : public Wt::WFormModel
static const Field AudioTranscodeBitrateLimitField; static const Field AudioTranscodeBitrateLimitField;
static const Field DemoField; static const Field DemoField;
UserModel(boost::optional<Database::IdType> userId) UserModel(std::optional<Database::IdType> userId)
: Wt::WFormModel(), : Wt::WFormModel(),
_userId(userId) _userId(userId)
{ {
@@ -80,7 +80,7 @@ class UserModel : public Wt::WFormModel
void saveData() void saveData()
{ {
boost::optional<Database::User::PasswordHash> passwordHash; std::optional<Database::User::PasswordHash> passwordHash;
if (!valueText(PasswordField).empty()) if (!valueText(PasswordField).empty())
passwordHash = getService<::Auth::PasswordService>()->hashPassword(valueText(PasswordField).toUTF8()); passwordHash = getService<::Auth::PasswordService>()->hashPassword(valueText(PasswordField).toUTF8());
@@ -203,7 +203,7 @@ class UserModel : public Wt::WFormModel
} }
std::shared_ptr<ValueStringModel<Bitrate>> _bitrateModel; std::shared_ptr<ValueStringModel<Bitrate>> _bitrateModel;
boost::optional<Database::IdType> _userId; std::optional<Database::IdType> _userId;
}; };
const Wt::WFormModel::Field UserModel::LoginField = "login"; const Wt::WFormModel::Field UserModel::LoginField = "login";
+4 -4
View File
@@ -19,7 +19,7 @@
#include "Validators.hpp" #include "Validators.hpp"
#include <boost/filesystem.hpp> #include <filesystem>
#include <Wt/WLengthValidator.h> #include <Wt/WLengthValidator.h>
@@ -53,11 +53,11 @@ DirectoryValidator::validate(const Wt::WString& input) const
if (input.empty()) if (input.empty())
return Wt::WValidator::validate(input); return Wt::WValidator::validate(input);
boost::filesystem::path p(input.toUTF8()); const std::filesystem::path p {input.toUTF8()};
boost::system::error_code ec; std::error_code ec;
// TODO check rights // TODO check rights
bool res = boost::filesystem::is_directory(p, ec); bool res = std::filesystem::is_directory(p, ec);
if (ec) if (ec)
return Wt::WValidator::Result(Wt::ValidationState::Invalid, ec.message()); // TODO translate common errors return Wt::WValidator::Result(Wt::ValidationState::Invalid, ec.message()); // TODO translate common errors
else if (res) else if (res)
+6 -5
View File
@@ -20,7 +20,8 @@
#pragma once #pragma once
#include <boost/optional.hpp> #include <optional>
#include <Wt/WStringListModel.h> #include <Wt/WStringListModel.h>
namespace UserInterface { namespace UserInterface {
@@ -41,7 +42,7 @@ class ValueStringModel : public Wt::WStringListModel
return Wt::cpp17::any_cast<Wt::WString>(data(index(static_cast<int>(row), 0), Wt::ItemDataRole::Display)); return Wt::cpp17::any_cast<Wt::WString>(data(index(static_cast<int>(row), 0), Wt::ItemDataRole::Display));
} }
boost::optional<std::size_t> std::optional<std::size_t>
getRowFromString(const Wt::WString& value) getRowFromString(const Wt::WString& value)
{ {
for (std::size_t i{}; i < static_cast<std::size_t>(rowCount()); ++i) for (std::size_t i{}; i < static_cast<std::size_t>(rowCount()); ++i)
@@ -50,10 +51,10 @@ class ValueStringModel : public Wt::WStringListModel
return i; return i;
} }
return boost::none; return std::nullopt;
} }
boost::optional<std::size_t> std::optional<std::size_t>
getRowFromValue(const T& value) getRowFromValue(const T& value)
{ {
for (std::size_t i{}; i < static_cast<std::size_t>(rowCount()); ++i) for (std::size_t i{}; i < static_cast<std::size_t>(rowCount()); ++i)
@@ -62,7 +63,7 @@ class ValueStringModel : public Wt::WStringListModel
return i; return i;
} }
return boost::none; return std::nullopt;
} }
void void
+10 -10
View File
@@ -42,16 +42,16 @@ namespace UserInterface {
Artist::Artist(Filters* filters) Artist::Artist(Filters* filters)
: _filters(filters) : _filters(filters)
{ {
wApp->internalPathChanged().connect(std::bind([=] wApp->internalPathChanged().connect([=]
{ {
refresh(); refresh();
})); });
refresh(); refresh();
filters->updated().connect(std::bind([=] { filters->updated().connect([=] {
refresh(); refresh();
})); });
} }
void void
@@ -162,13 +162,13 @@ Artist::refresh()
entry->bindWidget("artist", LmsApplication::createArtistAnchor(artists.front())); entry->bindWidget("artist", LmsApplication::createArtistAnchor(artists.front()));
} }
boost::optional<int> year = release->getReleaseYear(); std::optional<int> year {release->getReleaseYear()};
if (year) if (year)
{ {
entry->setCondition("if-has-year", true); entry->setCondition("if-has-year", true);
entry->bindInt("year", *year); entry->bindInt("year", *year);
boost::optional<int> originalYear = release->getReleaseYear(true); std::optional<int> originalYear {release->getReleaseYear(true)};
if (originalYear && *originalYear != *year) if (originalYear && *originalYear != *year)
{ {
entry->setCondition("if-has-orig-year", true); entry->setCondition("if-has-orig-year", true);
@@ -177,16 +177,16 @@ Artist::refresh()
} }
Wt::WText* playBtn = entry->bindNew<Wt::WText>("play-btn", Wt::WString::tr("Lms.Explore.template.play-btn"), Wt::TextFormat::XHTML); Wt::WText* playBtn = entry->bindNew<Wt::WText>("play-btn", Wt::WString::tr("Lms.Explore.template.play-btn"), Wt::TextFormat::XHTML);
playBtn->clicked().connect(std::bind([=] playBtn->clicked().connect([=]
{ {
releasesPlay.emit({releaseId}); releasesPlay.emit({releaseId});
})); });
Wt::WText* addBtn = entry->bindNew<Wt::WText>("add-btn", Wt::WString::tr("Lms.Explore.template.add-btn"), Wt::TextFormat::XHTML); Wt::WText* addBtn = entry->bindNew<Wt::WText>("add-btn", Wt::WString::tr("Lms.Explore.template.add-btn"), Wt::TextFormat::XHTML);
addBtn->clicked().connect(std::bind([=] addBtn->clicked().connect([=]
{ {
releasesAdd.emit({releaseId}); releasesAdd.emit({releaseId});
})); });
} }
} }
+2 -2
View File
@@ -76,8 +76,8 @@ ReleaseInfo::refresh()
if (!release) if (!release)
return; return;
boost::optional<std::string> copyright {release->getCopyright()}; std::optional<std::string> copyright {release->getCopyright()};
boost::optional<std::string> copyrightURL {release->getCopyrightURL()}; std::optional<std::string> copyrightURL {release->getCopyrightURL()};
setCondition("if-has-copyright-or-copyright-url", copyright || copyrightURL); setCondition("if-has-copyright-or-copyright-url", copyright || copyrightURL);
+2 -2
View File
@@ -81,13 +81,13 @@ Release::refresh()
t->bindString("name", Wt::WString::fromUTF8(release->getName()), Wt::TextFormat::Plain); t->bindString("name", Wt::WString::fromUTF8(release->getName()), Wt::TextFormat::Plain);
boost::optional<int> year {release->getReleaseYear()}; std::optional<int> year {release->getReleaseYear()};
if (year) if (year)
{ {
t->setCondition("if-has-year", true); t->setCondition("if-has-year", true);
t->bindInt("year", *year); t->bindInt("year", *year);
boost::optional<int> originalYear {release->getReleaseYear(true)}; std::optional<int> originalYear {release->getReleaseYear(true)};
if (originalYear && *originalYear != *year) if (originalYear && *originalYear != *year)
{ {
t->setCondition("if-has-orig-year", true); t->setCondition("if-has-orig-year", true);
+1 -1
View File
@@ -135,7 +135,7 @@ Releases::addSome()
} }
std::vector<Database::IdType> std::vector<Database::IdType>
Releases::getReleases(boost::optional<std::size_t> offset, boost::optional<std::size_t> limit, bool& moreResults) const Releases::getReleases(std::optional<std::size_t> offset, std::optional<std::size_t> limit, bool& moreResults) const
{ {
const auto searchKeywords {splitString(_search->text().toUTF8(), " ")}; const auto searchKeywords {splitString(_search->text().toUTF8(), " ")};
+2 -2
View File
@@ -19,7 +19,7 @@
#pragma once #pragma once
#include <boost/optional.hpp> #include <optional>
#include <Wt/WContainerWidget.h> #include <Wt/WContainerWidget.h>
#include <Wt/WLineEdit.h> #include <Wt/WLineEdit.h>
@@ -44,7 +44,7 @@ class Releases : public Wt::WTemplate
void refresh(); void refresh();
void addSome(); void addSome();
std::vector<Database::IdType> getReleases(boost::optional<std::size_t> offset, boost::optional<std::size_t> limit, bool& moreResults) const; std::vector<Database::IdType> getReleases(std::optional<std::size_t> offset, std::optional<std::size_t> limit, bool& moreResults) const;
std::vector<Database::IdType> getReleases() const; std::vector<Database::IdType> getReleases() const;
Filters* _filters; Filters* _filters;
+7 -7
View File
@@ -40,8 +40,8 @@ using namespace Database;
namespace UserInterface { namespace UserInterface {
Tracks::Tracks(Filters* filters) Tracks::Tracks(Filters* filters)
: Wt::WTemplate(Wt::WString::tr("Lms.Explore.Tracks.template")), : Wt::WTemplate {Wt::WString::tr("Lms.Explore.Tracks.template")},
_filters(filters) _filters {filters}
{ {
addFunction("tr", &Wt::WTemplate::Functions::tr); addFunction("tr", &Wt::WTemplate::Functions::tr);
@@ -56,18 +56,18 @@ _filters(filters)
}); });
Wt::WText* addBtn = bindNew<Wt::WText>("add-btn", Wt::WString::tr("Lms.Explore.template.add-btn"), Wt::TextFormat::XHTML); Wt::WText* addBtn = bindNew<Wt::WText>("add-btn", Wt::WString::tr("Lms.Explore.template.add-btn"), Wt::TextFormat::XHTML);
addBtn->clicked().connect(std::bind([=] addBtn->clicked().connect([=]
{ {
tracksAdd.emit(getTracks()); tracksAdd.emit(getTracks());
})); });
_tracksContainer = bindNew<Wt::WContainerWidget>("tracks"); _tracksContainer = bindNew<Wt::WContainerWidget>("tracks");
_showMore = bindNew<Wt::WPushButton>("show-more", Wt::WString::tr("Lms.Explore.show-more")); _showMore = bindNew<Wt::WPushButton>("show-more", Wt::WString::tr("Lms.Explore.show-more"));
_showMore->clicked().connect(std::bind([=] _showMore->clicked().connect([=]
{ {
addSome(); addSome();
})); });
refresh(); refresh();
@@ -75,7 +75,7 @@ _filters(filters)
} }
std::vector<Database::IdType> std::vector<Database::IdType>
Tracks::getTracks(boost::optional<std::size_t> offset, boost::optional<std::size_t> size, bool& moreResults) Tracks::getTracks(std::optional<std::size_t> offset, std::optional<std::size_t> size, bool& moreResults)
{ {
const auto searchKeywords {splitString(_search->text().toUTF8(), " ")}; const auto searchKeywords {splitString(_search->text().toUTF8(), " ")};
const auto clusterIds {_filters->getClusterIds()}; const auto clusterIds {_filters->getClusterIds()};
+2 -2
View File
@@ -19,7 +19,7 @@
#pragma once #pragma once
#include <boost/optional.hpp> #include <optional>
#include <Wt/WContainerWidget.h> #include <Wt/WContainerWidget.h>
#include <Wt/WLineEdit.h> #include <Wt/WLineEdit.h>
@@ -43,7 +43,7 @@ class Tracks : public Wt::WTemplate
void refresh(); void refresh();
void addSome(); void addSome();
std::vector<Database::IdType> getTracks(boost::optional<std::size_t> offset, boost::optional<std::size_t> size, bool& moreResults); std::vector<Database::IdType> getTracks(std::optional<std::size_t> offset, std::optional<std::size_t> size, bool& moreResults);
std::vector<Database::IdType> getTracks(); std::vector<Database::IdType> getTracks();
Wt::WContainerWidget* _tracksContainer; Wt::WContainerWidget* _tracksContainer;
+5 -7
View File
@@ -19,12 +19,10 @@
#include "Config.hpp" #include "Config.hpp"
#include <sstream>
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
Config::Config(const boost::filesystem::path& p) Config::Config(const std::filesystem::path& p)
{ {
_config.readFile(p.string().c_str()); _config.readFile(p.string().c_str());
} }
@@ -35,7 +33,7 @@ Config::getString(const std::string& setting, const std::string& def, const std:
try { try {
std::string res {(const char*)_config.lookup(setting)}; std::string res {(const char*)_config.lookup(setting)};
if (!allowedValues.empty() && allowedValues.find(res) == allowedValues.end()) if (!allowedValues.empty() && allowedValues.find(res) == std::cend(allowedValues))
{ {
LMS_LOG(MAIN, ERROR) << "Invalid setting for '" << setting << "', using default value '" << def << "'"; LMS_LOG(MAIN, ERROR) << "Invalid setting for '" << setting << "', using default value '" << def << "'";
return def; return def;
@@ -49,12 +47,12 @@ Config::getString(const std::string& setting, const std::string& def, const std:
} }
} }
boost::filesystem::path std::filesystem::path
Config::getPath(const std::string& setting, const boost::filesystem::path& path) Config::getPath(const std::string& setting, const std::filesystem::path& path)
{ {
try { try {
const char* res = _config.lookup(setting); const char* res = _config.lookup(setting);
return boost::filesystem::path(std::string(res)); return std::filesystem::path {std::string(res)};
} }
catch (std::exception &e) catch (std::exception &e)
{ {
+3 -3
View File
@@ -18,16 +18,16 @@
*/ */
#pragma once #pragma once
#include <filesystem>
#include <set> #include <set>
#include <boost/filesystem.hpp>
#include <libconfig.h++> #include <libconfig.h++>
// Used to get config values from configuration files // Used to get config values from configuration files
class Config final class Config final
{ {
public: public:
Config(const boost::filesystem::path& p); Config(const std::filesystem::path& p);
~Config() = default; ~Config() = default;
Config(const Config&) = delete; Config(const Config&) = delete;
@@ -37,7 +37,7 @@ class Config final
// Default values are returned in case of setting not found // Default values are returned in case of setting not found
std::string getString(const std::string& setting, const std::string& def = "", const std::set<std::string>& allowedValues = {}); std::string getString(const std::string& setting, const std::string& def = "", const std::set<std::string>& allowedValues = {});
boost::filesystem::path getPath(const std::string& setting, const boost::filesystem::path& def = boost::filesystem::path()); std::filesystem::path getPath(const std::string& setting, const std::filesystem::path& def = std::filesystem::path());
unsigned long getULong(const std::string& setting, unsigned long def = 0); unsigned long getULong(const std::string& setting, unsigned long def = 0);
long getLong(const std::string& setting, long def = 0); long getLong(const std::string& setting, long def = 0);
bool getBool(const std::string& setting, bool def = false); bool getBool(const std::string& setting, bool def = false);
+7 -7
View File
@@ -28,7 +28,7 @@
#include "utils/Exception.hpp" #include "utils/Exception.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
boost::filesystem::path searchExecPath(std::string filename) std::filesystem::path searchExecPath(std::string filename)
{ {
std::string path; std::string path;
@@ -42,7 +42,7 @@ boost::filesystem::path searchExecPath(std::string filename)
tokenizer tok(path, sep); tokenizer tok(path, sep);
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it) for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
{ {
boost::filesystem::path p = *it; std::filesystem::path p = *it;
p /= filename; p /= filename;
if (!::access(p.c_str(), X_OK)) if (!::access(p.c_str(), X_OK))
{ {
@@ -53,7 +53,7 @@ boost::filesystem::path searchExecPath(std::string filename)
return result; return result;
} }
void computeCrc(const boost::filesystem::path& p, std::vector<unsigned char>& crc) void computeCrc(const std::filesystem::path& p, std::vector<unsigned char>& crc)
{ {
using crc_type = boost::crc_32_type; using crc_type = boost::crc_32_type;
crc_type result; crc_type result;
@@ -87,11 +87,11 @@ void computeCrc(const boost::filesystem::path& p, std::vector<unsigned char>& cr
} }
} }
bool ensureDirectory(boost::filesystem::path dir) bool ensureDirectory(const std::filesystem::path& dir)
{ {
if (boost::filesystem::exists(dir)) if (std::filesystem::exists(dir))
return boost::filesystem::is_directory(dir); return std::filesystem::is_directory(dir);
else else
return boost::filesystem::create_directory(dir); return std::filesystem::create_directory(dir);
} }
+4 -4
View File
@@ -19,15 +19,15 @@
#pragma once #pragma once
#include <filesystem>
#include <string> #include <string>
#include <vector> #include <vector>
#include <boost/filesystem.hpp>
boost::filesystem::path searchExecPath(std::string filename); std::filesystem::path searchExecPath(std::string filename);
void computeCrc(const boost::filesystem::path& p, std::vector<unsigned char>& checksum); void computeCrc(const std::filesystem::path& p, std::vector<unsigned char>& checksum);
// Make sure the given path is a directory // Make sure the given path is a directory
// Create it if needed // Create it if needed
bool ensureDirectory(boost::filesystem::path dir); bool ensureDirectory(const std::filesystem::path& dir);
+3 -3
View File
@@ -55,7 +55,7 @@ bool readList(const std::string& str, const std::string& separators, std::list<s
} }
template<> template<>
boost::optional<std::string> std::optional<std::string>
readAs(const std::string& str) readAs(const std::string& str)
{ {
return str; return str;
@@ -137,13 +137,13 @@ stringEndsWith(const std::string& str, const std::string& ending)
return boost::algorithm::ends_with(str, ending); return boost::algorithm::ends_with(str, ending);
} }
boost::optional<std::string> std::optional<std::string>
stringFromHex(const std::string& str) stringFromHex(const std::string& str)
{ {
static const char lut[] {"0123456789ABCDEF"}; static const char lut[] {"0123456789ABCDEF"};
if (str.length() % 2 != 0) if (str.length() % 2 != 0)
return boost::none; return std::nullopt;
std::string res; std::string res;
res.reserve(str.length() / 2); res.reserve(str.length() / 2);
+5 -6
View File
@@ -22,13 +22,12 @@
#include <chrono> #include <chrono>
#include <list> #include <list>
#include <map> #include <map>
#include <optional>
#include <random> #include <random>
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
#include <boost/optional.hpp>
#include <Wt/WDate.h> #include <Wt/WDate.h>
bool bool
@@ -53,14 +52,14 @@ std::string
bufferToString(const std::vector<unsigned char>& data); bufferToString(const std::vector<unsigned char>& data);
template<typename T> template<typename T>
boost::optional<T> readAs(const std::string& str) std::optional<T> readAs(const std::string& str)
{ {
T res; T res;
std::istringstream iss ( str ); std::istringstream iss ( str );
iss >> res; iss >> res;
if (iss.fail()) if (iss.fail())
return boost::none; return std::nullopt;
return res; return res;
} }
@@ -71,7 +70,7 @@ replaceInString(const std::string& str, const std::string& from, const std::stri
bool bool
stringEndsWith(const std::string& str, const std::string& ending); stringEndsWith(const std::string& str, const std::string& ending);
boost::optional<std::string> std::optional<std::string>
stringFromHex(const std::string& str); stringFromHex(const std::string& str);
// warning: not efficient // warning: not efficient
@@ -105,7 +104,7 @@ void uniqueAndSortedByOccurence(In first, In last, Out out)
} }
template<class T, class Compare = std::less<>> template<class T, class Compare = std::less<>>
constexpr const T& clamp( T v, T lo, T hi, Compare comp = {}) constexpr T clamp(T v, T lo, T hi, Compare comp = {})
{ {
assert(!comp(hi, lo)); assert(!comp(hi, lo));
return comp(v, lo) ? lo : comp(hi, v) ? hi : v; return comp(v, lo) ? lo : comp(hi, v) ? hi : v;
+3 -3
View File
@@ -8,14 +8,14 @@ som_SOURCES = \
$(top_srcdir)/src/similarity/features/som/DataNormalizer.cpp \ $(top_srcdir)/src/similarity/features/som/DataNormalizer.cpp \
$(top_srcdir)/src/similarity/features/som/Network.cpp $(top_srcdir)/src/similarity/features/som/Network.cpp
som_CXXFLAGS=-std=c++14 -Wall -I${top_srcdir}/src/ -I${top_srcdir}/src/similarity/features/som/ som_CXXFLAGS=-std=c++17 -I${top_srcdir}/src/ -I${top_srcdir}/src/similarity/features/som/
database_SOURCES = \ database_SOURCES = \
$(srcdir)/database/DatabaseTest.cpp \ $(srcdir)/database/DatabaseTest.cpp \
$(top_srcdir)/src/database/Artist.cpp \ $(top_srcdir)/src/database/Artist.cpp \
$(top_srcdir)/src/database/Cluster.cpp \ $(top_srcdir)/src/database/Cluster.cpp \
$(top_srcdir)/src/database/Database.cpp \ $(top_srcdir)/src/database/Db.cpp \
$(top_srcdir)/src/database/TrackArtistLink.cpp \ $(top_srcdir)/src/database/TrackArtistLink.cpp \
$(top_srcdir)/src/database/TrackFeatures.cpp \ $(top_srcdir)/src/database/TrackFeatures.cpp \
$(top_srcdir)/src/database/TrackList.cpp \ $(top_srcdir)/src/database/TrackList.cpp \
@@ -29,5 +29,5 @@ database_SOURCES = \
$(top_srcdir)/src/utils/Logger.cpp \ $(top_srcdir)/src/utils/Logger.cpp \
$(top_srcdir)/src/utils/Utils.cpp $(top_srcdir)/src/utils/Utils.cpp
database_CXXFLAGS=-std=c++14 -Wall -I${top_srcdir}/src/ database_CXXFLAGS=-std=c++17 -I${top_srcdir}/src/
+8 -8
View File
@@ -19,11 +19,11 @@
#include <cstdlib> #include <cstdlib>
#include <boost/filesystem.hpp> #include <filesystem>
#include "database/Artist.hpp" #include "database/Artist.hpp"
#include "database/Cluster.hpp" #include "database/Cluster.hpp"
#include "database/Database.hpp" #include "database/Db.hpp"
#include "database/TrackList.hpp" #include "database/TrackList.hpp"
#include "database/Release.hpp" #include "database/Release.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
@@ -34,10 +34,10 @@ using namespace Database;
class ScopedFileDeleter final class ScopedFileDeleter final
{ {
public: public:
ScopedFileDeleter(const boost::filesystem::path& path) : _path {path} {} ScopedFileDeleter(const std::filesystem::path& path) : _path {path} {}
~ScopedFileDeleter() { boost::filesystem::remove(_path); } ~ScopedFileDeleter() { std::filesystem::remove(_path); }
private: private:
boost::filesystem::path _path; std::filesystem::path _path;
}; };
#define CHECK(PRED) \ #define CHECK(PRED) \
@@ -1247,19 +1247,19 @@ testDatabaseEmpty(Session& session)
CHECK(Track::getAll(session).empty()); CHECK(Track::getAll(session).empty());
} }
int main(int argc, char* argv[]) int main()
{ {
try try
{ {
const boost::filesystem::path tmpFile {boost::filesystem::temp_directory_path() / boost::filesystem::unique_path()}; const std::filesystem::path tmpFile {std::tmpnam(nullptr)};
ScopedFileDeleter tmpFileDeleter {tmpFile}; ScopedFileDeleter tmpFileDeleter {tmpFile};
std::cout << "Database test file: '" << tmpFile.string() << "'" << std::endl; std::cout << "Database test file: '" << tmpFile.string() << "'" << std::endl;
for (std::size_t i = 0; i < 2; ++i) for (std::size_t i = 0; i < 2; ++i)
{ {
Database::Database db {tmpFile}; Database::Db db {tmpFile};
std::unique_ptr<Session> session {db.createSession()}; std::unique_ptr<Session> session {db.createSession()};
auto runTest = [&session](const std::string& name, std::function<void(Session&)> testFunc) auto runTest = [&session](const std::string& name, std::function<void(Session&)> testFunc)
+1 -1
View File
@@ -26,7 +26,7 @@
using namespace SOM; using namespace SOM;
int main(int argc, char* argv[]) int main()
{ {
static const InputVector::value_type EPSILON = 0.01; static const InputVector::value_type EPSILON = 0.01;
{ {
+4 -5
View File
@@ -1,4 +1,5 @@
#include <chrono> #include <chrono>
#include <optional>
#include <stdexcept> #include <stdexcept>
#include <stdlib.h> #include <stdlib.h>
#include <iostream> #include <iostream>
@@ -31,13 +32,13 @@ std::ostream& operator<<(std::ostream& os, const MetaData::Album& album)
void parse(MetaData::Parser& parser, const boost::filesystem::path& file) void parse(MetaData::Parser& parser, const std::filesystem::path& file)
{ {
using namespace MetaData; using namespace MetaData;
parser.setClusterTypeNames( {"MOOD", "GENRE"} ); parser.setClusterTypeNames( {"MOOD", "GENRE"} );
boost::optional<Track> track {parser.parse(file, true)}; std::optional<Track> track {parser.parse(file, true)};
if (!track) if (!track)
{ {
std::cerr << "Parsing failed" << std::endl; std::cerr << "Parsing failed" << std::endl;
@@ -119,11 +120,9 @@ int main(int argc, char *argv[])
try try
{ {
Av::AvInit();
for (std::size_t i {}; i < static_cast<std::size_t>(argc - 1); ++i) for (std::size_t i {}; i < static_cast<std::size_t>(argc - 1); ++i)
{ {
boost::filesystem::path file {argv[i + 1]}; std::filesystem::path file {argv[i + 1]};
std::cout << "Parsing file '" << file << "'" << std::endl; std::cout << "Parsing file '" << file << "'" << std::endl;
+1 -1
View File
@@ -8,5 +8,5 @@ lms_metadata_SOURCES = \
$(top_srcdir)/src/utils/Logger.cpp \ $(top_srcdir)/src/utils/Logger.cpp \
$(top_srcdir)/src/utils/Utils.cpp $(top_srcdir)/src/utils/Utils.cpp
lms_metadata_CXXFLAGS=-std=c++14 -Wall -I$(top_srcdir)/src -D_REENTRANT lms_metadata_CXXFLAGS=-std=c++17 -I$(top_srcdir)/src -D_REENTRANT
+9 -9
View File
@@ -1,11 +1,11 @@
#include <stdlib.h>
#include <stdexcept>
#include <iostream>
#include <string>
#include <chrono> #include <chrono>
#include <random> #include <filesystem>
#include <iostream>
#include <stdexcept>
#include <stdlib.h>
#include <string>
#include "database/Database.hpp" #include "database/Db.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
#include "database/Artist.hpp" #include "database/Artist.hpp"
@@ -32,7 +32,7 @@ std::ostream& operator<<(std::ostream& os, const Database::Track::pointer& track
static static
bool bool
getTrackFeatures(Database::Session &session, const Database::Track::pointer& track, const std::map<std::string, std::size_t>& featuresSettings, SOM::InputVector& res) getTrackFeatures(Database::Session&, const Database::Track::pointer& track, const std::map<std::string, std::size_t>& featuresSettings, SOM::InputVector& res)
{ {
std::map<std::string, std::vector<double>> features; std::map<std::string, std::vector<double>> features;
for (const auto& featureSettings : featuresSettings) for (const auto& featureSettings : featuresSettings)
@@ -84,13 +84,13 @@ int main(int argc, char *argv[])
for (const auto& featureSettings : featuresSettings) for (const auto& featureSettings : featuresSettings)
nbDims += featureSettings.second; nbDims += featureSettings.second;
boost::filesystem::path configFilePath = "/etc/lms.conf"; std::filesystem::path configFilePath {"/etc/lms.conf"};
if (argc >= 2) if (argc >= 2)
configFilePath = std::string(argv[1], 0, 256); configFilePath = std::string(argv[1], 0, 256);
ServiceProvider<Config>::create(configFilePath); ServiceProvider<Config>::create(configFilePath);
Database::Database db {getService<Config>()->getPath("working-dir") / "lms.db"}; Database::Db db {getService<Config>()->getPath("working-dir") / "lms.db"};
auto session {db.createSession()}; auto session {db.createSession()};
std::cout << "Getting all features..." << std::endl; std::cout << "Getting all features..." << std::endl;
+2 -2
View File
@@ -4,7 +4,7 @@ lms_similarity_SOURCES = \
$(srcdir)/LmsSimilarity.cpp \ $(srcdir)/LmsSimilarity.cpp \
$(top_srcdir)/src/database/Artist.cpp \ $(top_srcdir)/src/database/Artist.cpp \
$(top_srcdir)/src/database/Cluster.cpp \ $(top_srcdir)/src/database/Cluster.cpp \
$(top_srcdir)/src/database/Database.cpp \ $(top_srcdir)/src/database/Db.cpp \
$(top_srcdir)/src/database/TrackFeatures.cpp \ $(top_srcdir)/src/database/TrackFeatures.cpp \
$(top_srcdir)/src/database/TrackList.cpp \ $(top_srcdir)/src/database/TrackList.cpp \
$(top_srcdir)/src/database/Release.cpp \ $(top_srcdir)/src/database/Release.cpp \
@@ -20,5 +20,5 @@ lms_similarity_SOURCES = \
$(top_srcdir)/src/utils/Logger.cpp \ $(top_srcdir)/src/utils/Logger.cpp \
$(top_srcdir)/src/utils/Utils.cpp $(top_srcdir)/src/utils/Utils.cpp
lms_similarity_CXXFLAGS=-std=c++14 -Wall -I$(top_srcdir)/src -D_REENTRANT lms_similarity_CXXFLAGS=-std=c++17 -I$(top_srcdir)/src -D_REENTRANT