Compare commits
64 Commits
lenerd/you
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e31b41f1f | ||
|
|
b36a41d4e9 | ||
|
|
900939f4ad | ||
|
|
2b4bd89e2e | ||
|
|
d885583d6e | ||
|
|
e8f1c4bd48 | ||
|
|
2f9a65e177 | ||
|
|
27b107ee37 | ||
|
|
3e6d992b93 | ||
|
|
4fdafc5320 | ||
|
|
440e9a5768 | ||
|
|
4ac9a0f0dd | ||
|
|
92b478ef31 | ||
|
|
72d990fe25 | ||
|
|
f9d0fb608c | ||
|
|
1d7d5152c6 | ||
|
|
9c27eec846 | ||
|
|
4b9eb741ea | ||
|
|
510e28c65a | ||
|
|
37aea91be1 | ||
|
|
377994daca | ||
|
|
33145940c8 | ||
|
|
cd9ae93c3e | ||
|
|
ba484cff1e | ||
|
|
603735d80e | ||
|
|
5238d0f6ed | ||
|
|
7078ed7f55 | ||
|
|
f51968b98b | ||
|
|
f83428a665 | ||
|
|
1c77138f51 | ||
|
|
838f600b57 | ||
|
|
68daf44032 | ||
|
|
985bc09b5c | ||
|
|
b2c8ca91c4 | ||
|
|
6f8d12da8c | ||
|
|
af7550a69f | ||
|
|
8ecbb8b49b | ||
|
|
b218d90193 | ||
|
|
95bca25cb6 | ||
|
|
8746ded880 | ||
|
|
f76dd085b2 | ||
|
|
e87c104dd6 | ||
|
|
afb150138d | ||
|
|
51ebe9e52d | ||
|
|
9c396d7ef0 | ||
|
|
81e5cf58b4 | ||
|
|
dc46f7a49b | ||
|
|
c7593a2087 | ||
|
|
73f5de7511 | ||
|
|
9f44edf0b1 | ||
|
|
d96e3e514d | ||
|
|
417d7172e5 | ||
|
|
727ca95ca5 | ||
|
|
26ee24a938 | ||
|
|
02754534fd | ||
|
|
40e4f98ee8 | ||
|
|
b023c737e3 | ||
|
|
70ca94f739 | ||
|
|
df1c4d7d7d | ||
|
|
35f9262a6e | ||
|
|
f47cf7f37c | ||
|
|
22fd919ce4 | ||
|
|
71970fa73c | ||
|
|
295663fc1c |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -3,7 +3,7 @@ name: Bug report
|
|||||||
about: Create a report to help us improve
|
about: Create a report to help us improve
|
||||||
title: "[BUG]"
|
title: "[BUG]"
|
||||||
labels: bug
|
labels: bug
|
||||||
assignees: larson-carter
|
assignees:
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -3,7 +3,7 @@ name: Feature request
|
|||||||
about: Suggest an idea for this project
|
about: Suggest an idea for this project
|
||||||
title: "[FEATURE]"
|
title: "[FEATURE]"
|
||||||
labels: enhancement
|
labels: enhancement
|
||||||
assignees: larson-carter
|
assignees:
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
79
.github/workflows/build.yml
vendored
Normal file
79
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: build ${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-22.04, ubuntu-24.04]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install build dependencies
|
||||||
|
env:
|
||||||
|
PACKAGES: >
|
||||||
|
ccache
|
||||||
|
libboost-dev
|
||||||
|
libboost-filesystem-dev
|
||||||
|
libboost-locale-dev
|
||||||
|
libboost-program-options-dev
|
||||||
|
libboost-regex-dev
|
||||||
|
libboost-thread-dev
|
||||||
|
libcurl4-gnutls-dev
|
||||||
|
libfftw3-dev
|
||||||
|
libmpdclient-dev
|
||||||
|
libncurses-dev
|
||||||
|
libreadline-dev
|
||||||
|
libtag1-dev
|
||||||
|
zlib1g-dev
|
||||||
|
run: |
|
||||||
|
sudo apt update -qq
|
||||||
|
sudo apt install -y --no-install-recommends ${{ env.PACKAGES }}
|
||||||
|
|
||||||
|
- name: Set up ccache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ${{ github.workspace }}/.ccache
|
||||||
|
key: ccache-${{ matrix.os }}-${{ github.run_id }}
|
||||||
|
restore-keys: ccache-${{ matrix.os }}-
|
||||||
|
|
||||||
|
- name: Run autoreconf
|
||||||
|
run: |
|
||||||
|
autoreconf -fiv
|
||||||
|
|
||||||
|
- name: Build ncmpcpp (light)
|
||||||
|
env:
|
||||||
|
CCACHE_DIR: ${{ github.workspace }}/.ccache/light
|
||||||
|
run: |
|
||||||
|
CC='ccache gcc' CXX='ccache g++' ./configure \
|
||||||
|
--disable-outputs \
|
||||||
|
--disable-visualizer \
|
||||||
|
--disable-clock \
|
||||||
|
--without-fftw \
|
||||||
|
--without-taglib \
|
||||||
|
--with-lto=$(nproc)
|
||||||
|
make -j$(nproc) || exit 1
|
||||||
|
|
||||||
|
- name: Build ncmpcpp (full)
|
||||||
|
env:
|
||||||
|
CCACHE_DIR: ${{ github.workspace }}/.ccache/full
|
||||||
|
run: |
|
||||||
|
CC='ccache gcc' CXX='ccache g++' ./configure \
|
||||||
|
--enable-outputs \
|
||||||
|
--enable-visualizer \
|
||||||
|
--enable-clock \
|
||||||
|
--with-fftw \
|
||||||
|
--with-taglib \
|
||||||
|
--with-lto=$(nproc)
|
||||||
|
make -j$(nproc) || exit 1
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -6,13 +6,16 @@ Makefile
|
|||||||
Makefile.in
|
Makefile.in
|
||||||
aclocal.m4
|
aclocal.m4
|
||||||
autom4te.cache/
|
autom4te.cache/
|
||||||
|
compile
|
||||||
config.*
|
config.*
|
||||||
configure
|
configure
|
||||||
depcomp
|
depcomp
|
||||||
|
**/.dirstamp
|
||||||
install-sh
|
install-sh
|
||||||
libtool
|
libtool
|
||||||
ltmain.sh
|
ltmain.sh
|
||||||
missing
|
missing
|
||||||
src/.deps/
|
**.m4
|
||||||
|
**/.deps/
|
||||||
src/ncmpcpp
|
src/ncmpcpp
|
||||||
stamp-h1
|
stamp-h1
|
||||||
|
|||||||
30
CHANGELOG.md
30
CHANGELOG.md
@@ -1,6 +1,34 @@
|
|||||||
# ncmpcpp-0.10 (????-??-??)
|
# ncmpcpp-0.10.2 (2025-??-??)
|
||||||
|
* Update lyrics fetchers.
|
||||||
|
* Add support for hexadecimal HTML escape codes.
|
||||||
|
|
||||||
|
# ncmpcpp-0.10.1 (2024-10-24)
|
||||||
|
* Fix compilation with `libc++`.
|
||||||
|
* Remove `autogen.sh` in favour of `autoreconf`.
|
||||||
|
* Do not crash when trying to reverse an empty playlist.
|
||||||
|
|
||||||
|
# ncmpcpp-0.10 (2024-09-03)
|
||||||
* Add the configuration option `mpd_password`.
|
* Add the configuration option `mpd_password`.
|
||||||
* Separate chunks of lyrics with a double newline.
|
* Separate chunks of lyrics with a double newline.
|
||||||
|
* Fix separator between albums with the same name, to check for album artist
|
||||||
|
instead of artist.
|
||||||
|
* Column widths are now configurable via `media_library_column_width_ratio_two`,
|
||||||
|
`media_library_column_width_ratio_three` and
|
||||||
|
`playlist_editor_column_width_ratio`.
|
||||||
|
* Removed deprecated `visualizer_fifo_path` and `visualizer_sync_interval`
|
||||||
|
options.
|
||||||
|
* Added support for italic text.
|
||||||
|
* Framerate limit for visualizer was removed.
|
||||||
|
* Performer tag is now read from the `TPE4` frame instead of `TPE3`.
|
||||||
|
* Potential crash when fetching lyrics for streams in the background was fixed.
|
||||||
|
* Seeking now accepts the `hh:mm:ss` format.
|
||||||
|
* Tag editor now only writes to files with modified tags.
|
||||||
|
* Column view can now display full filepaths.
|
||||||
|
* Updated the list of working lyrics fetchers.
|
||||||
|
* Add `visualizer_spectrum_smooth_look_legacy_chars` option (enabled by default)
|
||||||
|
for potentially improved bottom part of the spectrum visualizer in terminals
|
||||||
|
with transparent background.
|
||||||
|
* Add support for fetching lyrics from tags.
|
||||||
|
|
||||||
# ncmpcpp-0.9.2 (2021-01-24)
|
# ncmpcpp-0.9.2 (2021-01-24)
|
||||||
* Revert suppression of output of all external commands as that makes e.g album
|
* Revert suppression of output of all external commands as that makes e.g album
|
||||||
|
|||||||
2
INSTALL
2
INSTALL
@@ -30,7 +30,7 @@ The simplest way to compile this package is:
|
|||||||
For the next two commands, `csh' users will need to prefix them with
|
For the next two commands, `csh' users will need to prefix them with
|
||||||
`sh '.
|
`sh '.
|
||||||
|
|
||||||
2. Run `./autogen.sh' to generate the `configure' script.
|
2. Run `autoreconf -fiv' to generate the `configure' script.
|
||||||
|
|
||||||
3. Run `./configure' to configure the package for your system. This
|
3. Run `./configure' to configure the package for your system. This
|
||||||
will take a while. While running, it prints some messages
|
will take a while. While running, it prints some messages
|
||||||
|
|||||||
37
README.md
37
README.md
@@ -1,11 +1,22 @@
|
|||||||
# NCurses Music Player Client (Plus Plus)
|
# NCurses Music Player Client (Plus Plus) (Plus yt-dlp)
|
||||||
|
|
||||||
Project page - http://rybczak.net/ncmpcpp/
|
|
||||||
|
|
||||||
## ncmpcpp – featureful ncurses based MPD client inspired by ncmpc
|
## ncmpcpp – featureful ncurses based MPD client inspired by ncmpc
|
||||||
|
|
||||||
### Main features:
|
### yt-dlp fork
|
||||||
|
|
||||||
|
This fork allows adding items with yt-dlp via shift+d at the playlist screen, add a single item or a playlist (with a cap of 100 items)
|
||||||
|
|
||||||
|
## Project status
|
||||||
|
|
||||||
|
The project is officially in maintenance mode. I (Andrzej Rybczak) still use it
|
||||||
|
daily, but it's feature complete for me and there is very limited time I have
|
||||||
|
for tending to the issue tracker and open pull requests.
|
||||||
|
|
||||||
|
No new, substantial features should be expected (at least from me). However, if
|
||||||
|
there are any serious bugs or the project outright stops compiling because of
|
||||||
|
new, incompatible versions of dependencies, it will be fixed.
|
||||||
|
|
||||||
|
### Main features:
|
||||||
* tag editor
|
* tag editor
|
||||||
* playlist editor
|
* playlist editor
|
||||||
* easy to use search engine
|
* easy to use search engine
|
||||||
@@ -18,19 +29,18 @@ Project page - http://rybczak.net/ncmpcpp/
|
|||||||
…and a lot more minor functions.
|
…and a lot more minor functions.
|
||||||
|
|
||||||
### Dependencies:
|
### Dependencies:
|
||||||
|
* [boost](https://www.boost.org/)
|
||||||
* boost library [https://www.boost.org/]
|
* [ncurses](https://invisible-island.net/ncurses/announce.html)
|
||||||
* ncurses library [http://www.gnu.org/software/ncurses/ncurses.html]
|
* [readline](https://tiswww.case.edu/php/chet/readline/rltop.html)
|
||||||
* readline library [https://tiswww.case.edu/php/chet/readline/rltop.html]
|
* [curl](https://curl.se), for fetching lyrics and last.fm data
|
||||||
* curl library (optional, required for fetching lyrics and last.fm data) [https://curl.haxx.se/]
|
#### Optional libraries
|
||||||
* fftw library (optional, required for frequency spectrum music visualization mode) [http://www.fftw.org/]
|
* [fftw](http://www.fftw.org), for frequency spectrum music visualization mode
|
||||||
* tag library (optional, required for tag editing) [https://taglib.org/]
|
* [taglib](https://taglib.org/), for tag editing
|
||||||
|
|
||||||
### Known issues:
|
### Known issues:
|
||||||
* No full support for handling encodings other than UTF-8.
|
* No full support for handling encodings other than UTF-8.
|
||||||
|
|
||||||
### Installation:
|
### Installation:
|
||||||
|
|
||||||
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.
|
1. `cd` to the directory containing the package's source code.
|
||||||
@@ -38,7 +48,7 @@ The simplest way to compile this package is:
|
|||||||
For the next two commands, `csh` users will need to prefix them with
|
For the next two commands, `csh` users will need to prefix them with
|
||||||
`sh `.
|
`sh `.
|
||||||
|
|
||||||
2. Run `./autogen.sh` to generate the `configure` script.
|
2. Run `autoreconf -fiv` to generate the `configure` script.
|
||||||
|
|
||||||
3. Run `./configure` to configure the package for your system. This
|
3. Run `./configure` to configure the package for your system. This
|
||||||
will take a while. While running, it prints some messages
|
will take a while. While running, it prints some messages
|
||||||
@@ -55,7 +65,6 @@ The simplest way to compile this package is:
|
|||||||
Detailed intallation instructions can be found in the `INSTALL` file.
|
Detailed intallation instructions can be found in the `INSTALL` file.
|
||||||
|
|
||||||
### Optional features:
|
### Optional features:
|
||||||
|
|
||||||
Optional features can be enable by specifying them during configure. For
|
Optional features can be enable by specifying them during configure. For
|
||||||
example, to enable visualizer run `./configure --enable-visualizer`.
|
example, to enable visualizer run `./configure --enable-visualizer`.
|
||||||
|
|
||||||
|
|||||||
158
autogen.sh
158
autogen.sh
@@ -1,158 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Run this to set up the build system: configure, makefiles, etc.
|
|
||||||
# (at one point this was based on the version in enlightenment's cvs)
|
|
||||||
|
|
||||||
package="ncmpcpp"
|
|
||||||
|
|
||||||
olddir="`pwd`"
|
|
||||||
srcdir="`dirname $0`"
|
|
||||||
test -z "$srcdir" && srcdir=.
|
|
||||||
cd "$srcdir"
|
|
||||||
DIE=
|
|
||||||
AM_VERSIONGREP="sed -e s/.*[^0-9\.]\([0-9]\.[0-9]\).*/\1/"
|
|
||||||
AC_VERSIONGREP="sed -e s/.*[^0-9\.]\([0-9]\.[0-9][0-9]\).*/\1/"
|
|
||||||
VERSIONMKINT="sed -e s/[^0-9]//"
|
|
||||||
if test -n "$AM_FORCE_VERSION"
|
|
||||||
then
|
|
||||||
AM_VERSIONS="$AM_FORCE_VERSION"
|
|
||||||
else
|
|
||||||
AM_VERSIONS='1.6 1.7 1.8 1.9'
|
|
||||||
fi
|
|
||||||
if test -n "$AC_FORCE_VERSION"
|
|
||||||
then
|
|
||||||
AC_VERSIONS="$AC_FORCE_VERSION"
|
|
||||||
else
|
|
||||||
AC_VERSIONS='2.58 2.59'
|
|
||||||
fi
|
|
||||||
|
|
||||||
versioned_bins ()
|
|
||||||
{
|
|
||||||
bin="$1"
|
|
||||||
needed_int=`echo $VERNEEDED | $VERSIONMKINT`
|
|
||||||
for i in $VERSIONS
|
|
||||||
do
|
|
||||||
i_int=`echo $i | $VERSIONMKINT`
|
|
||||||
if test $i_int -ge $needed_int
|
|
||||||
then
|
|
||||||
echo $bin-$i $bin$i $bin-$i_int $bin$i_int
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo $bin
|
|
||||||
}
|
|
||||||
|
|
||||||
for c in autoconf autoheader automake aclocal
|
|
||||||
do
|
|
||||||
uc=`echo $c | tr a-z A-Z`
|
|
||||||
eval "val=`echo '$'$uc`"
|
|
||||||
if test -n "$val"
|
|
||||||
then
|
|
||||||
echo "$uc=$val in environment, will not attempt to auto-detect"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$c" in
|
|
||||||
autoconf|autoheader)
|
|
||||||
VERNEEDED=`fgrep AC_PREREQ configure.ac | $AC_VERSIONGREP`
|
|
||||||
VERSIONS="$AC_VERSIONS"
|
|
||||||
pkg=autoconf
|
|
||||||
;;
|
|
||||||
automake|aclocal)
|
|
||||||
VERNEEDED=`fgrep AUTOMAKE_OPTIONS Makefile.am | $AM_VERSIONGREP`
|
|
||||||
VERSIONS="$AM_VERSIONS"
|
|
||||||
pkg=automake
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
printf "checking for $c ... "
|
|
||||||
for x in `versioned_bins $c`; do
|
|
||||||
($x --version < /dev/null > /dev/null 2>&1) > /dev/null 2>&1
|
|
||||||
if test $? -eq 0
|
|
||||||
then
|
|
||||||
echo $x
|
|
||||||
eval $uc=$x
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
eval "val=`echo '$'$uc`"
|
|
||||||
if test -z "$val"
|
|
||||||
then
|
|
||||||
if test $c = $pkg
|
|
||||||
then
|
|
||||||
DIE="$DIE $c=$VERNEEDED"
|
|
||||||
else
|
|
||||||
DIE="$DIE $c($pkg)=$VERNEEDED"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if test -n "$LIBTOOLIZE"
|
|
||||||
then
|
|
||||||
echo "LIBTOOLIZE=$LIBTOOLIZE in environment," \
|
|
||||||
"will not attempt to auto-detect"
|
|
||||||
else
|
|
||||||
printf "checking for libtoolize ... "
|
|
||||||
for x in libtoolize glibtoolize
|
|
||||||
do
|
|
||||||
($x --version < /dev/null > /dev/null 2>&1) > /dev/null 2>&1
|
|
||||||
if test $? -eq 0
|
|
||||||
then
|
|
||||||
echo $x
|
|
||||||
LIBTOOLIZE=$x
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -z "$LIBTOOLIZE"
|
|
||||||
then
|
|
||||||
DIE="$DIE libtoolize(libtool)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -n "$DIE"
|
|
||||||
then
|
|
||||||
echo "You must have the following installed to compile $package:"
|
|
||||||
for i in $DIE
|
|
||||||
do
|
|
||||||
printf ' '
|
|
||||||
echo $i | sed -e 's/(/ (from /' -e 's/=\(.*\)/ (>= \1)/'
|
|
||||||
done
|
|
||||||
echo "Download the appropriate package(s) for your system,"
|
|
||||||
echo "or get the source from one of the GNU ftp sites"
|
|
||||||
echo "listed in http://www.gnu.org/order/ftp.html"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Generating configuration files for $package, please wait...."
|
|
||||||
|
|
||||||
ACLOCAL_FLAGS="$ACLOCAL_FLAGS"
|
|
||||||
|
|
||||||
# /usr/share/aclocal is most likely included by default, already...
|
|
||||||
ac_local_paths='
|
|
||||||
/usr/local/share/aclocal
|
|
||||||
/sw/share/aclocal
|
|
||||||
/usr/pkg/share/aclocal
|
|
||||||
/opt/share/aclocal
|
|
||||||
/usr/gnu/share/aclocal
|
|
||||||
'
|
|
||||||
|
|
||||||
for i in $ac_local_paths; do
|
|
||||||
if test -d "$i"; then
|
|
||||||
ACLOCAL_FLAGS="$ACLOCAL_FLAGS -I $i"
|
|
||||||
# we probably only want one of these...
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo " $ACLOCAL $ACLOCAL_FLAGS"
|
|
||||||
$ACLOCAL $ACLOCAL_FLAGS || exit 1
|
|
||||||
|
|
||||||
echo " $AUTOHEADER"
|
|
||||||
$AUTOHEADER || exit 1
|
|
||||||
|
|
||||||
echo " $LIBTOOLIZE --automake"
|
|
||||||
$LIBTOOLIZE --automake || exit 1
|
|
||||||
|
|
||||||
echo " $AUTOMAKE --add-missing $AUTOMAKE_FLAGS"
|
|
||||||
$AUTOMAKE --add-missing $AUTOMAKE_FLAGS || exit 1
|
|
||||||
|
|
||||||
echo " $AUTOCONF"
|
|
||||||
$AUTOCONF || exit 1
|
|
||||||
52
configure.ac
52
configure.ac
@@ -1,15 +1,15 @@
|
|||||||
AC_INIT([ncmpcpp], [0.10_dev])
|
AC_INIT([ncmpcpp],[0.10.2_dev])
|
||||||
AC_CONFIG_SRCDIR([configure.ac])
|
AC_CONFIG_SRCDIR([configure.ac])
|
||||||
AC_CONFIG_HEADERS(config.h)
|
AC_CONFIG_HEADERS(config.h)
|
||||||
AM_INIT_AUTOMAKE([subdir-objects])
|
AM_INIT_AUTOMAKE([subdir-objects])
|
||||||
|
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
|
|
||||||
AC_PREREQ(2.59)
|
AC_PREREQ([2.71])
|
||||||
|
|
||||||
AC_LANG_CPLUSPLUS
|
AC_LANG([C++])
|
||||||
AC_PROG_CXX
|
AC_PROG_CXX
|
||||||
AC_PROG_LIBTOOL
|
LT_INIT
|
||||||
|
|
||||||
AC_ARG_ENABLE(outputs, AS_HELP_STRING([--enable-outputs], [Enable outputs screen @<:@default=no@:>@]), [outputs=$enableval], [outputs=no])
|
AC_ARG_ENABLE(outputs, AS_HELP_STRING([--enable-outputs], [Enable outputs screen @<:@default=no@:>@]), [outputs=$enableval], [outputs=no])
|
||||||
AC_ARG_ENABLE(visualizer, AS_HELP_STRING([--enable-visualizer], [Enable music visualizer screen @<:@default=no@:>@]), [visualizer=$enableval], [visualizer=no])
|
AC_ARG_ENABLE(visualizer, AS_HELP_STRING([--enable-visualizer], [Enable music visualizer screen @<:@default=no@:>@]), [visualizer=$enableval], [visualizer=no])
|
||||||
@@ -70,15 +70,15 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]])],
|
|||||||
)
|
)
|
||||||
CXXFLAGS="$old_CXXFLAGS $fast_math"
|
CXXFLAGS="$old_CXXFLAGS $fast_math"
|
||||||
|
|
||||||
# -std=c++14
|
# -std=c++20
|
||||||
AC_MSG_CHECKING([whether compiler supports -std=c++14])
|
AC_MSG_CHECKING([whether compiler supports -std=c++20])
|
||||||
old_CXXFLAGS="$CXXFLAGS"
|
old_CXXFLAGS="$CXXFLAGS"
|
||||||
CXXFLAGS="-std=c++14"
|
CXXFLAGS="-std=c++20"
|
||||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]])],
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]])],
|
||||||
AC_MSG_RESULT([yes])
|
AC_MSG_RESULT([yes])
|
||||||
std_cpp14="-std=c++14",
|
std_cpp14="-std=c++20",
|
||||||
AC_MSG_RESULT([no])
|
AC_MSG_RESULT([no])
|
||||||
AC_MSG_ERROR([[Your compiler doesn't seem to support C++14, please upgrade (GCC >= 5)]])
|
AC_MSG_ERROR([[Your compiler doesn't seem to support C++20, please upgrade]])
|
||||||
)
|
)
|
||||||
CXXFLAGS="$old_CXXFLAGS $std_cpp14"
|
CXXFLAGS="$old_CXXFLAGS $std_cpp14"
|
||||||
|
|
||||||
@@ -90,6 +90,9 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[auto f = [](auto n) { return n*n; }; f(
|
|||||||
AC_MSG_ERROR([[Your compiler doesn't seem to support generic lambda expressions, please upgrade (GCC >= 5)]])
|
AC_MSG_ERROR([[Your compiler doesn't seem to support generic lambda expressions, please upgrade (GCC >= 5)]])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# warnings
|
||||||
|
CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wshadow -Wimplicit-fallthrough"
|
||||||
|
|
||||||
# boost
|
# boost
|
||||||
BOOST_REQUIRE([1.60])
|
BOOST_REQUIRE([1.60])
|
||||||
AC_SUBST(BOOST_CPPFLAGS)
|
AC_SUBST(BOOST_CPPFLAGS)
|
||||||
@@ -139,7 +142,7 @@ LIBS="$LIBS $BOOST_REGEX_LIBS"
|
|||||||
BOOST_THREAD
|
BOOST_THREAD
|
||||||
AC_SUBST(BOOST_THREAD_LDFLAGS)
|
AC_SUBST(BOOST_THREAD_LDFLAGS)
|
||||||
AC_SUBST(BOOST_THREAD_LIBS)
|
AC_SUBST(BOOST_THREAD_LIBS)
|
||||||
LDFLAGS+="$LDFLAGS $BOOST_THREAD_LDFLAGS"
|
LDFLAGS="$LDFLAGS $BOOST_THREAD_LDFLAGS"
|
||||||
LIBS="$LIBS $BOOST_THREAD_LIBS"
|
LIBS="$LIBS $BOOST_THREAD_LIBS"
|
||||||
|
|
||||||
# icu
|
# icu
|
||||||
@@ -149,7 +152,7 @@ PKG_CHECK_MODULES([ICU], [icu-i18n icu-uc], [
|
|||||||
old_LIBS="$LIBS"
|
old_LIBS="$LIBS"
|
||||||
AC_SUBST(ICU_CFLAGS)
|
AC_SUBST(ICU_CFLAGS)
|
||||||
AC_SUBST(ICU_LIBS)
|
AC_SUBST(ICU_LIBS)
|
||||||
CPPFLAGS="$CPPFLAGS $ICU_CFLAGS -DU_USING_ICU_NAMESPACE=0"
|
CPPFLAGS="$CPPFLAGS $ICU_CFLAGS"
|
||||||
LIBS="$LIBS $ICU_LIBS"
|
LIBS="$LIBS $ICU_LIBS"
|
||||||
AC_MSG_CHECKING([whether boost.regex was compiled with ICU support])
|
AC_MSG_CHECKING([whether boost.regex was compiled with ICU support])
|
||||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([
|
AC_LINK_IFELSE([AC_LANG_PROGRAM([
|
||||||
@@ -257,19 +260,30 @@ PKG_CHECK_MODULES([libcurl], [libcurl], [
|
|||||||
|
|
||||||
# taglib
|
# taglib
|
||||||
if test "$taglib" != "no" ; then
|
if test "$taglib" != "no" ; then
|
||||||
AC_PATH_PROG(TAGLIB_CONFIG, taglib-config)
|
PKG_CHECK_MODULES([taglib], [taglib], [
|
||||||
if test "$TAGLIB_CONFIG" != "" ; then
|
AC_SUBST(taglib_CFLAGS)
|
||||||
CPPFLAGS="$CPPFLAGS `$TAGLIB_CONFIG --cflags`"
|
AC_SUBST(taglib_LIBS)
|
||||||
LIBS="$LIBS `$TAGLIB_CONFIG --libs`"
|
], [
|
||||||
|
AC_PATH_PROG([TAGLIB_CONFIG], [taglib-config])
|
||||||
|
if test "$TAGLIB_CONFIG" != ""; then
|
||||||
|
taglib_CFLAGS=`$TAGLIB_CONFIG --cflags`
|
||||||
|
taglib_LIBS=`$TAGLIB_CONFIG --libs`
|
||||||
|
else
|
||||||
|
if test "$taglib" = "yes" ; then
|
||||||
|
AC_MSG_ERROR([could not find taglib.pc or taglib-config executable])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
if test "$TAGLIB_CONFIG$taglib_LIBS" != "" ; then
|
||||||
|
CPPFLAGS="$CPPFLAGS $taglib_CFLAGS"
|
||||||
|
LIBS="$LIBS $taglib_LIBS"
|
||||||
|
|
||||||
AC_CHECK_HEADERS([taglib.h], ,
|
AC_CHECK_HEADERS([taglib.h], ,
|
||||||
if test "$taglib" = "yes" ; then
|
if test "$taglib" = "yes" ; then
|
||||||
AC_MSG_ERROR([missing taglib.h header])
|
AC_MSG_ERROR([missing taglib.h header])
|
||||||
fi
|
fi
|
||||||
)
|
)
|
||||||
else
|
|
||||||
if test "$taglib" = "yes" ; then
|
|
||||||
AC_MSG_ERROR([taglib-config executable is missing])
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
31
doc/config
31
doc/config
@@ -125,6 +125,14 @@
|
|||||||
#
|
#
|
||||||
#visualizer_spectrum_smooth_look = yes
|
#visualizer_spectrum_smooth_look = yes
|
||||||
#
|
#
|
||||||
|
## Use unicode block characters from "symbols for legacy computing". This
|
||||||
|
## improves the smooth look on transparent terminals by using special unicode
|
||||||
|
## chars instead of reversing the background and foreground color on the bottom
|
||||||
|
## edge of the spectrum. If it leads to a garbled output on the bottom edge of
|
||||||
|
## the spectrum, you can either change the font or disable this option.
|
||||||
|
#
|
||||||
|
#visualizer_spectrum_smooth_look_legacy_chars = yes
|
||||||
|
#
|
||||||
## A value between 1 and 5 inclusive. Specifying a larger value makes the
|
## A value between 1 and 5 inclusive. Specifying a larger value makes the
|
||||||
## visualizer look at a larger slice of time, which results in less jumpy
|
## visualizer look at a larger slice of time, which results in less jumpy
|
||||||
## visualizer output.
|
## visualizer output.
|
||||||
@@ -141,6 +149,11 @@
|
|||||||
#
|
#
|
||||||
#visualizer_spectrum_hz_max = 20000
|
#visualizer_spectrum_hz_max = 20000
|
||||||
#
|
#
|
||||||
|
## Use log scaling for the frequency spectrum axes
|
||||||
|
#
|
||||||
|
#visualizer_spectrum_log_scale_x = yes
|
||||||
|
#visualizer_spectrum_log_scale_y = yes
|
||||||
|
#
|
||||||
##### system encoding #####
|
##### system encoding #####
|
||||||
##
|
##
|
||||||
## ncmpcpp should detect your charset encoding but if it failed to do so, you
|
## ncmpcpp should detect your charset encoding but if it failed to do so, you
|
||||||
@@ -172,6 +185,7 @@
|
|||||||
##
|
##
|
||||||
## %l - length
|
## %l - length
|
||||||
## %f - filename
|
## %f - filename
|
||||||
|
## %F - full filepath
|
||||||
## %D - directory
|
## %D - directory
|
||||||
## %a - artist
|
## %a - artist
|
||||||
## %A - album artist
|
## %A - album artist
|
||||||
@@ -215,6 +229,7 @@
|
|||||||
## - 9 - end of current color
|
## - 9 - end of current color
|
||||||
## - b - bold text
|
## - b - bold text
|
||||||
## - u - underline text
|
## - u - underline text
|
||||||
|
## - i - italic text
|
||||||
## - r - reverse colors
|
## - r - reverse colors
|
||||||
## - a - use alternative character set
|
## - a - use alternative character set
|
||||||
##
|
##
|
||||||
@@ -407,7 +422,7 @@
|
|||||||
#
|
#
|
||||||
#cyclic_scrolling = no
|
#cyclic_scrolling = no
|
||||||
#
|
#
|
||||||
#lyrics_fetchers = azlyrics, genius, musixmatch, sing365, metrolyrics, justsomelyrics, jahlyrics, plyrics, tekstowo, zeneszoveg, internet
|
#lyrics_fetchers = tags, genius, tekstowo, plyrics, justsomelyrics, jahlyrics, zeneszoveg, internet
|
||||||
#
|
#
|
||||||
#follow_now_playing_lyrics = no
|
#follow_now_playing_lyrics = no
|
||||||
#
|
#
|
||||||
@@ -465,6 +480,20 @@
|
|||||||
#
|
#
|
||||||
#ask_for_locked_screen_width_part = yes
|
#ask_for_locked_screen_width_part = yes
|
||||||
#
|
#
|
||||||
|
##
|
||||||
|
## Width of media_library screen columns
|
||||||
|
##
|
||||||
|
#
|
||||||
|
#media_library_column_width_ratio_two = 1:1
|
||||||
|
#
|
||||||
|
#media_library_column_width_ratio_three = 1:1:1
|
||||||
|
#
|
||||||
|
##
|
||||||
|
## Width of playlist_editor screen columns
|
||||||
|
##
|
||||||
|
#
|
||||||
|
#playlist_editor_column_width_ratio = 1:2
|
||||||
|
#
|
||||||
#jump_to_now_playing_song_at_start = yes
|
#jump_to_now_playing_song_at_start = yes
|
||||||
#
|
#
|
||||||
#ask_before_clearing_playlists = yes
|
#ask_before_clearing_playlists = yes
|
||||||
|
|||||||
@@ -114,6 +114,13 @@ Automatically scale visualizer size.
|
|||||||
.B visualizer_spectrum_smooth_look = yes/no
|
.B visualizer_spectrum_smooth_look = yes/no
|
||||||
For spectrum visualizer, use unicode block characters for a smoother, more continuous look. This will override the visualizer_look option. With transparent terminals and visualizer_in_stereo set, artifacts may be visible on the bottom half of the visualization.
|
For spectrum visualizer, use unicode block characters for a smoother, more continuous look. This will override the visualizer_look option. With transparent terminals and visualizer_in_stereo set, artifacts may be visible on the bottom half of the visualization.
|
||||||
.TP
|
.TP
|
||||||
|
.B visualizer_spectrum_smooth_look_legacy_chars = yes/no
|
||||||
|
Use unicode block characters from "symbols for legacy computing". This improves
|
||||||
|
the smooth look on transparent terminals by using special unicode chars instead
|
||||||
|
of reversing the background and foreground color on the bottom edge of the
|
||||||
|
spectrum. If it leads to a garbled output on the bottom edge of the spectrum,
|
||||||
|
you can either change the font or disable this option.
|
||||||
|
.TP
|
||||||
.B visualizer_spectrum_dft_size = NUMBER
|
.B visualizer_spectrum_dft_size = NUMBER
|
||||||
For spectrum visualizer, a value between 1 and 5 inclusive. Specifying a larger value makes the visualizer look at a larger slice of time, which results in less jumpy visualizer output.
|
For spectrum visualizer, a value between 1 and 5 inclusive. Specifying a larger value makes the visualizer look at a larger slice of time, which results in less jumpy visualizer output.
|
||||||
.TP
|
.TP
|
||||||
@@ -335,6 +342,15 @@ If you want to lock a screen, ncmpcpp asks for % of locked screen's width to be
|
|||||||
.B ask_for_locked_screen_width_part = yes/no
|
.B ask_for_locked_screen_width_part = yes/no
|
||||||
If enabled, ncmpcpp will ask for % of locked screen's width each time you want to lock a screen. If you disable that, it'll silently attempt to use default value.
|
If enabled, ncmpcpp will ask for % of locked screen's width each time you want to lock a screen. If you disable that, it'll silently attempt to use default value.
|
||||||
.TP
|
.TP
|
||||||
|
.B media_library_column_width_ratio_two = a:b
|
||||||
|
The ratio of the column widths in the media library, when there are two columns.
|
||||||
|
.TP
|
||||||
|
.B media_library_column_width_ratio_three = a:b:c
|
||||||
|
The ratio of the column widths in the media library, when there are three columns.
|
||||||
|
.TP
|
||||||
|
.B playlist_editor_column_width_ratio = a:b
|
||||||
|
The ratio of the column widths in the playlist editor.
|
||||||
|
.TP
|
||||||
.B jump_to_now_playing_song_at_start = yes/no
|
.B jump_to_now_playing_song_at_start = yes/no
|
||||||
If enabled, ncmpcpp will jump at start to now playing song if mpd is playing or paused.
|
If enabled, ncmpcpp will jump at start to now playing song if mpd is playing or paused.
|
||||||
.TP
|
.TP
|
||||||
@@ -463,6 +479,7 @@ For song format you can use:
|
|||||||
|
|
||||||
%l - length
|
%l - length
|
||||||
%f - filename
|
%f - filename
|
||||||
|
%F - full filepath
|
||||||
%D - directory
|
%D - directory
|
||||||
%a - artist
|
%a - artist
|
||||||
%A - album artist
|
%A - album artist
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ enum class CopyResult { Success, NoArtist, AlbumArtistAlreadyInPlace };
|
|||||||
bool is_framelist_empty(const TagLib::ID3v2::FrameList &list)
|
bool is_framelist_empty(const TagLib::ID3v2::FrameList &list)
|
||||||
{
|
{
|
||||||
for (auto it = list.begin(); it != list.end(); ++it)
|
for (auto it = list.begin(); it != list.end(); ++it)
|
||||||
if ((*it)->toString() != TagLib::String::null)
|
if (!(*it)->toString().isEmpty())
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
447
m4/boost.m4
447
m4/boost.m4
@@ -22,7 +22,7 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
m4_define([_BOOST_SERIAL], [m4_translit([
|
m4_define([_BOOST_SERIAL], [m4_translit([
|
||||||
# serial 26
|
# serial 39
|
||||||
], [#
|
], [#
|
||||||
], [])])
|
], [])])
|
||||||
|
|
||||||
@@ -226,7 +226,7 @@ AC_LANG_POP([C++])dnl
|
|||||||
AC_CACHE_CHECK([for Boost's header version],
|
AC_CACHE_CHECK([for Boost's header version],
|
||||||
[boost_cv_lib_version],
|
[boost_cv_lib_version],
|
||||||
[m4_pattern_allow([^BOOST_LIB_VERSION$])dnl
|
[m4_pattern_allow([^BOOST_LIB_VERSION$])dnl
|
||||||
_BOOST_SED_CPP([[/^boost-lib-version = /{s///;s/[\" ]//g;p;q;}]],
|
_BOOST_SED_CPP([[/^.*boost-lib-version = /{s///;s/[\" ]//g;p;q;}]],
|
||||||
[#include <boost/version.hpp>
|
[#include <boost/version.hpp>
|
||||||
boost-lib-version = BOOST_LIB_VERSION],
|
boost-lib-version = BOOST_LIB_VERSION],
|
||||||
[boost_cv_lib_version=`cat conftest.i`])])
|
[boost_cv_lib_version=`cat conftest.i`])])
|
||||||
@@ -288,14 +288,17 @@ fi
|
|||||||
|
|
||||||
# BOOST_FIND_LIBS([COMPONENT-NAME], [CANDIDATE-LIB-NAMES],
|
# BOOST_FIND_LIBS([COMPONENT-NAME], [CANDIDATE-LIB-NAMES],
|
||||||
# [PREFERRED-RT-OPT], [HEADER-NAME], [CXX-TEST],
|
# [PREFERRED-RT-OPT], [HEADER-NAME], [CXX-TEST],
|
||||||
# [CXX-PROLOGUE])
|
# [CXX-PROLOGUE], [CXX-POST-INCLUDE-PROLOGUE],
|
||||||
|
# [ERROR_ON_UNUSABLE])
|
||||||
# --------------------------------------------------------------
|
# --------------------------------------------------------------
|
||||||
# Look for the Boost library COMPONENT-NAME (e.g., `thread', for
|
# Look for the Boost library COMPONENT-NAME (e.g., `thread', for
|
||||||
# libboost_thread) under the possible CANDIDATE-LIB-NAMES (e.g.,
|
# libboost_thread) under the possible CANDIDATE-LIB-NAMES (e.g.,
|
||||||
# "thread_win32 thread"). Check that HEADER-NAME works and check that
|
# "thread_win32 thread"). Check that HEADER-NAME works and check that
|
||||||
# libboost_LIB-NAME can link with the code CXX-TEST. The optional
|
# libboost_LIB-NAME can link with the code CXX-TEST. The optional
|
||||||
# argument CXX-PROLOGUE can be used to include some C++ code before
|
# argument CXX-PROLOGUE can be used to include some C++ code before
|
||||||
# the `main' function.
|
# the `main' function. The CXX-POST-INCLUDE-PROLOGUE can be used to
|
||||||
|
# include some code before the `main' function, but after the
|
||||||
|
# `#include <HEADER-NAME>'.
|
||||||
#
|
#
|
||||||
# Invokes BOOST_FIND_HEADER([HEADER-NAME]) (see above).
|
# Invokes BOOST_FIND_HEADER([HEADER-NAME]) (see above).
|
||||||
#
|
#
|
||||||
@@ -309,6 +312,9 @@ fi
|
|||||||
# builds. Some sample values for PREFERRED-RT-OPT: (nothing), mt, d, mt-d, gdp
|
# builds. Some sample values for PREFERRED-RT-OPT: (nothing), mt, d, mt-d, gdp
|
||||||
# ... If you want to make sure you have a specific version of Boost
|
# ... If you want to make sure you have a specific version of Boost
|
||||||
# (eg, >= 1.33) you *must* invoke BOOST_REQUIRE before this macro.
|
# (eg, >= 1.33) you *must* invoke BOOST_REQUIRE before this macro.
|
||||||
|
#
|
||||||
|
# ERROR_ON_UNUSABLE can be set to "no" if the caller does not want their
|
||||||
|
# configure to fail
|
||||||
AC_DEFUN([BOOST_FIND_LIBS],
|
AC_DEFUN([BOOST_FIND_LIBS],
|
||||||
[AC_REQUIRE([BOOST_REQUIRE])dnl
|
[AC_REQUIRE([BOOST_REQUIRE])dnl
|
||||||
AC_REQUIRE([_BOOST_FIND_COMPILER_TAG])dnl
|
AC_REQUIRE([_BOOST_FIND_COMPILER_TAG])dnl
|
||||||
@@ -317,26 +323,32 @@ AC_REQUIRE([_BOOST_GUESS_WHETHER_TO_USE_MT])dnl
|
|||||||
if test x"$boost_cv_inc_path" = xno; then
|
if test x"$boost_cv_inc_path" = xno; then
|
||||||
AC_MSG_NOTICE([Boost not available, not searching for the Boost $1 library])
|
AC_MSG_NOTICE([Boost not available, not searching for the Boost $1 library])
|
||||||
else
|
else
|
||||||
dnl The else branch is huge and wasn't intended on purpose.
|
dnl The else branch is huge and wasn't indented on purpose.
|
||||||
AC_LANG_PUSH([C++])dnl
|
AC_LANG_PUSH([C++])dnl
|
||||||
AS_VAR_PUSHDEF([Boost_lib], [boost_cv_lib_$1])dnl
|
AS_VAR_PUSHDEF([Boost_lib], [boost_cv_lib_$1])dnl
|
||||||
AS_VAR_PUSHDEF([Boost_lib_LDFLAGS], [boost_cv_lib_$1_LDFLAGS])dnl
|
AS_VAR_PUSHDEF([Boost_lib_LDFLAGS], [boost_cv_lib_$1_LDFLAGS])dnl
|
||||||
AS_VAR_PUSHDEF([Boost_lib_LDPATH], [boost_cv_lib_$1_LDPATH])dnl
|
AS_VAR_PUSHDEF([Boost_lib_LDPATH], [boost_cv_lib_$1_LDPATH])dnl
|
||||||
AS_VAR_PUSHDEF([Boost_lib_LIBS], [boost_cv_lib_$1_LIBS])dnl
|
AS_VAR_PUSHDEF([Boost_lib_LIBS], [boost_cv_lib_$1_LIBS])dnl
|
||||||
BOOST_FIND_HEADER([$4])
|
AS_IF([test x"$8" = "xno"], [not_found_header='true'])
|
||||||
|
BOOST_FIND_HEADER([$4], [$not_found_header])
|
||||||
boost_save_CPPFLAGS=$CPPFLAGS
|
boost_save_CPPFLAGS=$CPPFLAGS
|
||||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||||
AC_CACHE_CHECK([for the Boost $1 library], [Boost_lib],
|
AC_CACHE_CHECK([for the Boost $1 library], [Boost_lib],
|
||||||
[_BOOST_FIND_LIBS($@)])
|
[_BOOST_FIND_LIBS($@)])
|
||||||
case $Boost_lib in #(
|
case $Boost_lib in #(
|
||||||
|
(yes) _AC_MSG_LOG_CONFTEST
|
||||||
|
AC_DEFINE(AS_TR_CPP([HAVE_BOOST_$1]), [1], [Defined if the Boost $1 library is available])dnl
|
||||||
|
AC_SUBST(AS_TR_CPP([BOOST_$1_LDFLAGS]), [$Boost_lib_LDFLAGS])dnl
|
||||||
|
AC_SUBST(AS_TR_CPP([BOOST_$1_LDPATH]), [$Boost_lib_LDPATH])dnl
|
||||||
|
AC_SUBST([BOOST_LDPATH], [$Boost_lib_LDPATH])dnl
|
||||||
|
AC_SUBST(AS_TR_CPP([BOOST_$1_LIBS]), [$Boost_lib_LIBS])dnl
|
||||||
|
;;
|
||||||
(no) _AC_MSG_LOG_CONFTEST
|
(no) _AC_MSG_LOG_CONFTEST
|
||||||
AC_MSG_ERROR([cannot find the flags to link with Boost $1])
|
AS_IF([test x"$8" != "xno"], [
|
||||||
|
AC_MSG_ERROR([cannot find flags to link with the Boost $1 library (libboost-$1)])
|
||||||
|
])
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
AC_SUBST(AS_TR_CPP([BOOST_$1_LDFLAGS]), [$Boost_lib_LDFLAGS])dnl
|
|
||||||
AC_SUBST(AS_TR_CPP([BOOST_$1_LDPATH]), [$Boost_lib_LDPATH])dnl
|
|
||||||
AC_SUBST([BOOST_LDPATH], [$Boost_lib_LDPATH])dnl
|
|
||||||
AC_SUBST(AS_TR_CPP([BOOST_$1_LIBS]), [$Boost_lib_LIBS])dnl
|
|
||||||
CPPFLAGS=$boost_save_CPPFLAGS
|
CPPFLAGS=$boost_save_CPPFLAGS
|
||||||
AS_VAR_POPDEF([Boost_lib])dnl
|
AS_VAR_POPDEF([Boost_lib])dnl
|
||||||
AS_VAR_POPDEF([Boost_lib_LDFLAGS])dnl
|
AS_VAR_POPDEF([Boost_lib_LDFLAGS])dnl
|
||||||
@@ -349,16 +361,20 @@ fi
|
|||||||
|
|
||||||
# BOOST_FIND_LIB([LIB-NAME],
|
# BOOST_FIND_LIB([LIB-NAME],
|
||||||
# [PREFERRED-RT-OPT], [HEADER-NAME], [CXX-TEST],
|
# [PREFERRED-RT-OPT], [HEADER-NAME], [CXX-TEST],
|
||||||
# [CXX-PROLOGUE])
|
# [CXX-PROLOGUE], [CXX-POST-INCLUDE-PROLOGUE],
|
||||||
|
# [ERROR_ON_UNUSABLE])
|
||||||
# --------------------------------------------------------------
|
# --------------------------------------------------------------
|
||||||
# Backward compatibility wrapper for BOOST_FIND_LIBS.
|
# Backward compatibility wrapper for BOOST_FIND_LIBS.
|
||||||
|
# ERROR_ON_UNUSABLE can be set to "no" if the caller does not want their
|
||||||
|
# configure to fail
|
||||||
AC_DEFUN([BOOST_FIND_LIB],
|
AC_DEFUN([BOOST_FIND_LIB],
|
||||||
[BOOST_FIND_LIBS([$1], $@)])
|
[BOOST_FIND_LIBS([$1], $@)])
|
||||||
|
|
||||||
|
|
||||||
# _BOOST_FIND_LIBS([LIB-NAME], [CANDIDATE-LIB-NAMES],
|
# _BOOST_FIND_LIBS([LIB-NAME], [CANDIDATE-LIB-NAMES],
|
||||||
# [PREFERRED-RT-OPT], [HEADER-NAME], [CXX-TEST],
|
# [PREFERRED-RT-OPT], [HEADER-NAME], [CXX-TEST],
|
||||||
# [CXX-PROLOGUE])
|
# [CXX-PROLOGUE], [CXX-POST-INCLUDE-PROLOGUE],
|
||||||
|
# [ERROR_ON_UNUSABLE])
|
||||||
# --------------------------------------------------------------
|
# --------------------------------------------------------------
|
||||||
# Real implementation of BOOST_FIND_LIBS: rely on these local macros:
|
# Real implementation of BOOST_FIND_LIBS: rely on these local macros:
|
||||||
# Boost_lib, Boost_lib_LDFLAGS, Boost_lib_LDPATH, Boost_lib_LIBS
|
# Boost_lib, Boost_lib_LDFLAGS, Boost_lib_LDPATH, Boost_lib_LIBS
|
||||||
@@ -370,6 +386,9 @@ AC_DEFUN([BOOST_FIND_LIB],
|
|||||||
# usually installed. If we can't find the standard variants, we try
|
# usually installed. If we can't find the standard variants, we try
|
||||||
# to enforce -mt (for instance on MacOSX, libboost_thread.dylib
|
# to enforce -mt (for instance on MacOSX, libboost_thread.dylib
|
||||||
# doesn't exist but there's -obviously- libboost_thread-mt.dylib).
|
# doesn't exist but there's -obviously- libboost_thread-mt.dylib).
|
||||||
|
#
|
||||||
|
# ERROR_ON_UNUSABLE can be set to "no" if the caller does not want their
|
||||||
|
# configure to fail
|
||||||
AC_DEFUN([_BOOST_FIND_LIBS],
|
AC_DEFUN([_BOOST_FIND_LIBS],
|
||||||
[Boost_lib=no
|
[Boost_lib=no
|
||||||
case "$3" in #(
|
case "$3" in #(
|
||||||
@@ -396,7 +415,8 @@ AC_DEFUN([_BOOST_FIND_LIBS],
|
|||||||
AC_MSG_ERROR([the libext variable is empty, did you invoke Libtool?])
|
AC_MSG_ERROR([the libext variable is empty, did you invoke Libtool?])
|
||||||
boost_save_ac_objext=$ac_objext
|
boost_save_ac_objext=$ac_objext
|
||||||
# Generate the test file.
|
# Generate the test file.
|
||||||
AC_LANG_CONFTEST([AC_LANG_PROGRAM([#include <$4>
|
AC_LANG_CONFTEST([AC_LANG_PROGRAM([$7
|
||||||
|
#include <$4>
|
||||||
$6], [$5])])
|
$6], [$5])])
|
||||||
dnl Optimization hacks: compiling C++ is slow, especially with Boost. What
|
dnl Optimization hacks: compiling C++ is slow, especially with Boost. What
|
||||||
dnl we're trying to do here is guess the right combination of link flags
|
dnl we're trying to do here is guess the right combination of link flags
|
||||||
@@ -416,7 +436,10 @@ dnl empty because the test file is generated only once above (before we
|
|||||||
dnl start the for loops).
|
dnl start the for loops).
|
||||||
AC_COMPILE_IFELSE([],
|
AC_COMPILE_IFELSE([],
|
||||||
[ac_objext=do_not_rm_me_plz],
|
[ac_objext=do_not_rm_me_plz],
|
||||||
[AC_MSG_ERROR([cannot compile a test that uses Boost $1])])
|
[AS_IF([test x"$8" != x"no"], [
|
||||||
|
AC_MSG_ERROR([cannot compile a test that uses Boost $1])
|
||||||
|
])
|
||||||
|
])
|
||||||
ac_objext=$boost_save_ac_objext
|
ac_objext=$boost_save_ac_objext
|
||||||
boost_failed_libs=
|
boost_failed_libs=
|
||||||
# Don't bother to ident the following nested for loops, only the 2
|
# Don't bother to ident the following nested for loops, only the 2
|
||||||
@@ -426,12 +449,15 @@ for boost_tag_ in -$boost_cv_lib_tag ''; do
|
|||||||
for boost_ver_ in -$boost_cv_lib_version ''; do
|
for boost_ver_ in -$boost_cv_lib_version ''; do
|
||||||
for boost_mt_ in $boost_mt -mt ''; do
|
for boost_mt_ in $boost_mt -mt ''; do
|
||||||
for boost_rtopt_ in $boost_rtopt '' -d; do
|
for boost_rtopt_ in $boost_rtopt '' -d; do
|
||||||
for boost_lib in \
|
for boost_full_suffix in \
|
||||||
boost_$boost_lib_$boost_tag_$boost_mt_$boost_rtopt_$boost_ver_ \
|
$boost_last_suffix \
|
||||||
boost_$boost_lib_$boost_tag_$boost_rtopt_$boost_ver_ \
|
x$boost_tag_$boost_mt_$boost_rtopt_$boost_ver_ \
|
||||||
boost_$boost_lib_$boost_tag_$boost_mt_$boost_ver_ \
|
x$boost_tag_$boost_rtopt_$boost_ver_ \
|
||||||
boost_$boost_lib_$boost_tag_$boost_ver_
|
x$boost_tag_$boost_mt_$boost_ver_ \
|
||||||
|
x$boost_tag_$boost_ver_
|
||||||
do
|
do
|
||||||
|
boost_real_suffix=`echo "$boost_full_suffix" | sed 's/^x//'`
|
||||||
|
boost_lib="boost_$boost_lib_$boost_real_suffix"
|
||||||
# Avoid testing twice the same lib
|
# Avoid testing twice the same lib
|
||||||
case $boost_failed_libs in #(
|
case $boost_failed_libs in #(
|
||||||
(*@$boost_lib@*) continue;;
|
(*@$boost_lib@*) continue;;
|
||||||
@@ -480,7 +506,7 @@ dnl generated only once above (before we start the for loops).
|
|||||||
*)
|
*)
|
||||||
for boost_cv_rpath_link_ldflag in -Wl,-R, -Wl,-rpath,; do
|
for boost_cv_rpath_link_ldflag in -Wl,-R, -Wl,-rpath,; do
|
||||||
LDFLAGS="$boost_save_LDFLAGS -L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
|
LDFLAGS="$boost_save_LDFLAGS -L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
|
||||||
LIBS="$boost_save_LIBS $Boost_lib_LIBS"
|
LIBS="$Boost_lib_LIBS $boost_save_LIBS"
|
||||||
_BOOST_AC_LINK_IFELSE([],
|
_BOOST_AC_LINK_IFELSE([],
|
||||||
[boost_rpath_link_ldflag_found=yes
|
[boost_rpath_link_ldflag_found=yes
|
||||||
break],
|
break],
|
||||||
@@ -496,6 +522,7 @@ dnl generated only once above (before we start the for loops).
|
|||||||
test x"$boost_ldpath" != x &&
|
test x"$boost_ldpath" != x &&
|
||||||
Boost_lib_LDFLAGS="-L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
|
Boost_lib_LDFLAGS="-L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
|
||||||
Boost_lib_LDPATH="$boost_ldpath"
|
Boost_lib_LDPATH="$boost_ldpath"
|
||||||
|
boost_last_suffix="$boost_full_suffix"
|
||||||
break 7
|
break 7
|
||||||
else
|
else
|
||||||
boost_failed_libs="$boost_failed_libs@$boost_lib@"
|
boost_failed_libs="$boost_failed_libs@$boost_lib@"
|
||||||
@@ -534,6 +561,14 @@ m4_popdef([BOOST_Library])dnl
|
|||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
# BOOST_ANY()
|
||||||
|
# ------------
|
||||||
|
# Look for Boost.Any
|
||||||
|
BOOST_DEFUN([Any],
|
||||||
|
[BOOST_FIND_HEADER([boost/any.hpp])])
|
||||||
|
|
||||||
|
|
||||||
# BOOST_ARRAY()
|
# BOOST_ARRAY()
|
||||||
# -------------
|
# -------------
|
||||||
# Look for Boost.Array
|
# Look for Boost.Array
|
||||||
@@ -548,6 +583,12 @@ BOOST_DEFUN([Asio],
|
|||||||
[AC_REQUIRE([BOOST_SYSTEM])dnl
|
[AC_REQUIRE([BOOST_SYSTEM])dnl
|
||||||
BOOST_FIND_HEADER([boost/asio.hpp])])
|
BOOST_FIND_HEADER([boost/asio.hpp])])
|
||||||
|
|
||||||
|
# BOOST_BIMAP()
|
||||||
|
# ------------
|
||||||
|
# Look for Boost.Bimap
|
||||||
|
BOOST_DEFUN([Bimap],
|
||||||
|
[BOOST_FIND_HEADER([boost/bimap.hpp])])
|
||||||
|
|
||||||
|
|
||||||
# BOOST_ASSIGN()
|
# BOOST_ASSIGN()
|
||||||
# -------------
|
# -------------
|
||||||
@@ -556,6 +597,24 @@ BOOST_DEFUN([Assign],
|
|||||||
[BOOST_FIND_HEADER([boost/assign.hpp])])
|
[BOOST_FIND_HEADER([boost/assign.hpp])])
|
||||||
|
|
||||||
|
|
||||||
|
# BOOST_ATOMIC([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
|
# -------------------------------
|
||||||
|
# Look for Boost.Atomic. For the documentation of PREFERRED-RT-OPT, see the
|
||||||
|
# documentation of BOOST_FIND_LIB above.
|
||||||
|
BOOST_DEFUN([Atomic],
|
||||||
|
[BOOST_FIND_LIB([atomic], [$1],
|
||||||
|
[boost/atomic.hpp],
|
||||||
|
[boost::atomic<int> a;],
|
||||||
|
[ ],
|
||||||
|
[#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_STDINT_H
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif], [$2])
|
||||||
|
])# BOOST_ATOMIC
|
||||||
|
|
||||||
|
|
||||||
# BOOST_BIND()
|
# BOOST_BIND()
|
||||||
# ------------
|
# ------------
|
||||||
# Look for Boost.Bind.
|
# Look for Boost.Bind.
|
||||||
@@ -563,7 +622,14 @@ BOOST_DEFUN([Bind],
|
|||||||
[BOOST_FIND_HEADER([boost/bind.hpp])])
|
[BOOST_FIND_HEADER([boost/bind.hpp])])
|
||||||
|
|
||||||
|
|
||||||
# BOOST_CHRONO()
|
# BOOST_CAST()
|
||||||
|
# ------------
|
||||||
|
# Look for Boost.Cast
|
||||||
|
BOOST_DEFUN([Cast],
|
||||||
|
[BOOST_FIND_HEADER([boost/cast.hpp])])
|
||||||
|
|
||||||
|
|
||||||
|
# BOOST_CHRONO([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# --------------
|
# --------------
|
||||||
# Look for Boost.Chrono.
|
# Look for Boost.Chrono.
|
||||||
BOOST_DEFUN([Chrono],
|
BOOST_DEFUN([Chrono],
|
||||||
@@ -571,7 +637,7 @@ BOOST_DEFUN([Chrono],
|
|||||||
# added as of 1.35.0. If we have a version <1.35, we must not attempt to
|
# added as of 1.35.0. If we have a version <1.35, we must not attempt to
|
||||||
# find Boost.System as it didn't exist by then.
|
# find Boost.System as it didn't exist by then.
|
||||||
if test $boost_major_version -ge 135; then
|
if test $boost_major_version -ge 135; then
|
||||||
BOOST_SYSTEM([$1])
|
BOOST_SYSTEM([$1], [$2])
|
||||||
fi # end of the Boost.System check.
|
fi # end of the Boost.System check.
|
||||||
boost_filesystem_save_LIBS=$LIBS
|
boost_filesystem_save_LIBS=$LIBS
|
||||||
boost_filesystem_save_LDFLAGS=$LDFLAGS
|
boost_filesystem_save_LDFLAGS=$LDFLAGS
|
||||||
@@ -580,7 +646,7 @@ LIBS="$LIBS $BOOST_SYSTEM_LIBS"
|
|||||||
LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS"
|
LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS"
|
||||||
BOOST_FIND_LIB([chrono], [$1],
|
BOOST_FIND_LIB([chrono], [$1],
|
||||||
[boost/chrono.hpp],
|
[boost/chrono.hpp],
|
||||||
[boost::chrono::thread_clock d;])
|
[boost::chrono::thread_clock d;], [], [], [$2])
|
||||||
if test $enable_static_boost = yes && test $boost_major_version -ge 135; then
|
if test $enable_static_boost = yes && test $boost_major_version -ge 135; then
|
||||||
BOOST_CHRONO_LIBS="$BOOST_CHRONO_LIBS $BOOST_SYSTEM_LIBS"
|
BOOST_CHRONO_LIBS="$BOOST_CHRONO_LIBS $BOOST_SYSTEM_LIBS"
|
||||||
fi
|
fi
|
||||||
@@ -589,7 +655,7 @@ LDFLAGS=$boost_filesystem_save_LDFLAGS
|
|||||||
])# BOOST_CHRONO
|
])# BOOST_CHRONO
|
||||||
|
|
||||||
|
|
||||||
# BOOST_CONTEXT([PREFERRED-RT-OPT])
|
# BOOST_CONTEXT([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# -----------------------------------
|
# -----------------------------------
|
||||||
# Look for Boost.Context. For the documentation of PREFERRED-RT-OPT, see the
|
# Look for Boost.Context. For the documentation of PREFERRED-RT-OPT, see the
|
||||||
# documentation of BOOST_FIND_LIB above.
|
# documentation of BOOST_FIND_LIB above.
|
||||||
@@ -597,17 +663,76 @@ LDFLAGS=$boost_filesystem_save_LDFLAGS
|
|||||||
# * This library was introduced in Boost 1.51.0
|
# * This library was introduced in Boost 1.51.0
|
||||||
# * The signatures of make_fcontext() and jump_fcontext were changed in 1.56.0
|
# * The signatures of make_fcontext() and jump_fcontext were changed in 1.56.0
|
||||||
# * A dependency on boost_thread appears in 1.57.0
|
# * A dependency on boost_thread appears in 1.57.0
|
||||||
|
# * The implementation details were moved to boost::context::detail in 1.61.0
|
||||||
|
# * 1.61 also introduces execution_context_v2, which is the "lowest common
|
||||||
|
# denominator" for boost::context presence since then.
|
||||||
|
# * boost::context::fiber was introduced in 1.69 and execution_context_v2 was
|
||||||
|
# removed in 1.72
|
||||||
BOOST_DEFUN([Context],
|
BOOST_DEFUN([Context],
|
||||||
[boost_context_save_LIBS=$LIBS
|
[boost_context_save_LIBS=$LIBS
|
||||||
boost_context_save_LDFLAGS=$LDFLAGS
|
boost_context_save_LDFLAGS=$LDFLAGS
|
||||||
if test $boost_major_version -ge 157; then
|
if test $boost_major_version -ge 157; then
|
||||||
BOOST_THREAD([$1])
|
BOOST_THREAD([$1], [$2])
|
||||||
m4_pattern_allow([^BOOST_THREAD_(LIBS|LDFLAGS)$])dnl
|
m4_pattern_allow([^BOOST_THREAD_(LIBS|LDFLAGS)$])dnl
|
||||||
LIBS="$LIBS $BOOST_THREAD_LIBS"
|
LIBS="$LIBS $BOOST_THREAD_LIBS"
|
||||||
LDFLAGS="$LDFLAGS $BOOST_THREAD_LDFLAGS"
|
LDFLAGS="$LDFLAGS $BOOST_THREAD_LDFLAGS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test $boost_major_version -ge 169; then
|
||||||
|
|
||||||
BOOST_FIND_LIB([context], [$1],
|
BOOST_FIND_LIB([context], [$1],
|
||||||
[boost/context/all.hpp],[[
|
[boost/context/fiber.hpp], [[
|
||||||
|
namespace ctx=boost::context;
|
||||||
|
int a;
|
||||||
|
ctx::fiber source{[&a](ctx::fiber&& sink){
|
||||||
|
a=0;
|
||||||
|
int b=1;
|
||||||
|
for(;;){
|
||||||
|
sink=std::move(sink).resume();
|
||||||
|
int next=a+b;
|
||||||
|
a=b;
|
||||||
|
b=next;
|
||||||
|
}
|
||||||
|
return std::move(sink);
|
||||||
|
}};
|
||||||
|
for (int j=0;j<10;++j) {
|
||||||
|
source=std::move(source).resume();
|
||||||
|
}
|
||||||
|
return a == 34;
|
||||||
|
]], [], [], [$2])
|
||||||
|
|
||||||
|
elif test $boost_major_version -ge 161; then
|
||||||
|
|
||||||
|
BOOST_FIND_LIB([context], [$1],
|
||||||
|
[boost/context/execution_context_v2.hpp], [[
|
||||||
|
namespace ctx=boost::context;
|
||||||
|
int res=0;
|
||||||
|
int n=35;
|
||||||
|
ctx::execution_context<int> source(
|
||||||
|
[n, &res](ctx::execution_context<int> sink, int) mutable {
|
||||||
|
int a=0;
|
||||||
|
int b=1;
|
||||||
|
while(n-->0){
|
||||||
|
auto result=sink(a);
|
||||||
|
sink=std::move(std::get<0>(result));
|
||||||
|
auto next=a+b;
|
||||||
|
a=b;
|
||||||
|
b=next;
|
||||||
|
}
|
||||||
|
return sink;
|
||||||
|
});
|
||||||
|
for(int i=0;i<10;++i){
|
||||||
|
auto result=source(i);
|
||||||
|
source=std::move(std::get<0>(result));
|
||||||
|
res = std::get<1>(result);
|
||||||
|
}
|
||||||
|
return res == 34;
|
||||||
|
]], [], [], [$2])
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
BOOST_FIND_LIB([context], [$1],
|
||||||
|
[boost/context/fcontext.hpp],[[
|
||||||
|
|
||||||
// creates a stack
|
// creates a stack
|
||||||
void * stack_pointer = new void*[4096];
|
void * stack_pointer = new void*[4096];
|
||||||
@@ -662,7 +787,10 @@ static void f(intptr_t i) {
|
|||||||
ctx::jump_fcontext(&fc, fcm, i * 2);
|
ctx::jump_fcontext(&fc, fcm, i * 2);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
])
|
], [], [], [$2])
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
LIBS=$boost_context_save_LIBS
|
LIBS=$boost_context_save_LIBS
|
||||||
LDFLAGS=$boost_context_save_LDFLAGS
|
LDFLAGS=$boost_context_save_LDFLAGS
|
||||||
])# BOOST_CONTEXT
|
])# BOOST_CONTEXT
|
||||||
@@ -677,7 +805,7 @@ BOOST_FIND_HEADER([boost/lexical_cast.hpp])
|
|||||||
])# BOOST_CONVERSION
|
])# BOOST_CONVERSION
|
||||||
|
|
||||||
|
|
||||||
# BOOST_COROUTINE([PREFERRED-RT-OPT])
|
# BOOST_COROUTINE([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# -----------------------------------
|
# -----------------------------------
|
||||||
# Look for Boost.Coroutine. For the documentation of PREFERRED-RT-OPT, see the
|
# Look for Boost.Coroutine. For the documentation of PREFERRED-RT-OPT, see the
|
||||||
# documentation of BOOST_FIND_LIB above. This library was introduced in Boost
|
# documentation of BOOST_FIND_LIB above. This library was introduced in Boost
|
||||||
@@ -687,10 +815,10 @@ BOOST_DEFUN([Coroutine],
|
|||||||
boost_coroutine_save_LIBS=$LIBS
|
boost_coroutine_save_LIBS=$LIBS
|
||||||
boost_coroutine_save_LDFLAGS=$LDFLAGS
|
boost_coroutine_save_LDFLAGS=$LDFLAGS
|
||||||
# Link-time dependency from coroutine to context
|
# Link-time dependency from coroutine to context
|
||||||
BOOST_CONTEXT([$1])
|
BOOST_CONTEXT([$1], [$2])
|
||||||
# Starting from Boost 1.55 a dependency on Boost.System is added
|
# Starting from Boost 1.55 a dependency on Boost.System is added
|
||||||
if test $boost_major_version -ge 155; then
|
if test $boost_major_version -ge 155; then
|
||||||
BOOST_SYSTEM([$1])
|
BOOST_SYSTEM([$1], [$2])
|
||||||
fi
|
fi
|
||||||
m4_pattern_allow([^BOOST_(CONTEXT|SYSTEM)_(LIBS|LDFLAGS)])
|
m4_pattern_allow([^BOOST_(CONTEXT|SYSTEM)_(LIBS|LDFLAGS)])
|
||||||
LIBS="$LIBS $BOOST_CONTEXT_LIBS $BOOST_SYSTEM_LIBS"
|
LIBS="$LIBS $BOOST_CONTEXT_LIBS $BOOST_SYSTEM_LIBS"
|
||||||
@@ -698,7 +826,8 @@ LDFLAGS="$LDFLAGS $BOOST_CONTEXT_LDFLAGS"
|
|||||||
|
|
||||||
# in 1.53 coroutine was a header only library
|
# in 1.53 coroutine was a header only library
|
||||||
if test $boost_major_version -eq 153; then
|
if test $boost_major_version -eq 153; then
|
||||||
BOOST_FIND_HEADER([boost/coroutine/coroutine.hpp])
|
AS_IF([test x"$2" = "xno"], [not_found_header='true'])
|
||||||
|
BOOST_FIND_HEADER([boost/coroutine/coroutine.hpp], [$not_found_header])
|
||||||
else
|
else
|
||||||
BOOST_FIND_LIB([coroutine], [$1],
|
BOOST_FIND_LIB([coroutine], [$1],
|
||||||
[boost/coroutine/coroutine.hpp],
|
[boost/coroutine/coroutine.hpp],
|
||||||
@@ -709,7 +838,7 @@ else
|
|||||||
#else
|
#else
|
||||||
boost::coroutines::asymmetric_coroutine<int>::pull_type coro; coro.get();
|
boost::coroutines::asymmetric_coroutine<int>::pull_type coro; coro.get();
|
||||||
#endif
|
#endif
|
||||||
])
|
], [], [], [$2])
|
||||||
fi
|
fi
|
||||||
# Link-time dependency from coroutine to context, existed only in 1.53, in 1.54
|
# Link-time dependency from coroutine to context, existed only in 1.53, in 1.54
|
||||||
# coroutine doesn't use context from its headers but from its library.
|
# coroutine doesn't use context from its headers but from its library.
|
||||||
@@ -734,18 +863,25 @@ BOOST_DEFUN([CRC],
|
|||||||
])# BOOST_CRC
|
])# BOOST_CRC
|
||||||
|
|
||||||
|
|
||||||
# BOOST_DATE_TIME([PREFERRED-RT-OPT])
|
# BOOST_DATE_TIME([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# -----------------------------------
|
# -----------------------------------
|
||||||
# Look for Boost.Date_Time. For the documentation of PREFERRED-RT-OPT, see the
|
# Look for Boost.Date_Time. For the documentation of PREFERRED-RT-OPT, see the
|
||||||
# documentation of BOOST_FIND_LIB above.
|
# documentation of BOOST_FIND_LIB above.
|
||||||
BOOST_DEFUN([Date_Time],
|
BOOST_DEFUN([Date_Time],
|
||||||
[BOOST_FIND_LIB([date_time], [$1],
|
[BOOST_FIND_LIB([date_time], [$1],
|
||||||
[boost/date_time/posix_time/posix_time.hpp],
|
[boost/date_time/posix_time/posix_time.hpp],
|
||||||
[boost::posix_time::ptime t;])
|
[boost::posix_time::ptime t;], [], [], [$2])
|
||||||
])# BOOST_DATE_TIME
|
])# BOOST_DATE_TIME
|
||||||
|
|
||||||
|
|
||||||
# BOOST_FILESYSTEM([PREFERRED-RT-OPT])
|
# BOOST_EXCEPTION()
|
||||||
|
# ------------
|
||||||
|
# Look for Boost.Exception
|
||||||
|
BOOST_DEFUN([Exception],
|
||||||
|
[BOOST_FIND_HEADER([boost/exception/all.hpp])])
|
||||||
|
|
||||||
|
|
||||||
|
# BOOST_FILESYSTEM([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# ------------------------------------
|
# ------------------------------------
|
||||||
# Look for Boost.Filesystem. For the documentation of PREFERRED-RT-OPT, see
|
# Look for Boost.Filesystem. For the documentation of PREFERRED-RT-OPT, see
|
||||||
# the documentation of BOOST_FIND_LIB above.
|
# the documentation of BOOST_FIND_LIB above.
|
||||||
@@ -756,7 +892,7 @@ BOOST_DEFUN([Filesystem],
|
|||||||
# added as of 1.35.0. If we have a version <1.35, we must not attempt to
|
# added as of 1.35.0. If we have a version <1.35, we must not attempt to
|
||||||
# find Boost.System as it didn't exist by then.
|
# find Boost.System as it didn't exist by then.
|
||||||
if test $boost_major_version -ge 135; then
|
if test $boost_major_version -ge 135; then
|
||||||
BOOST_SYSTEM([$1])
|
BOOST_SYSTEM([$1], [$2])
|
||||||
fi # end of the Boost.System check.
|
fi # end of the Boost.System check.
|
||||||
boost_filesystem_save_LIBS=$LIBS
|
boost_filesystem_save_LIBS=$LIBS
|
||||||
boost_filesystem_save_LDFLAGS=$LDFLAGS
|
boost_filesystem_save_LDFLAGS=$LDFLAGS
|
||||||
@@ -764,7 +900,8 @@ m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl
|
|||||||
LIBS="$LIBS $BOOST_SYSTEM_LIBS"
|
LIBS="$LIBS $BOOST_SYSTEM_LIBS"
|
||||||
LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS"
|
LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS"
|
||||||
BOOST_FIND_LIB([filesystem], [$1],
|
BOOST_FIND_LIB([filesystem], [$1],
|
||||||
[boost/filesystem/path.hpp], [boost::filesystem::path p;])
|
[boost/filesystem/path.hpp], [boost::filesystem::path p;],
|
||||||
|
[], [], [$2])
|
||||||
if test $enable_static_boost = yes && test $boost_major_version -ge 135; then
|
if test $enable_static_boost = yes && test $boost_major_version -ge 135; then
|
||||||
BOOST_FILESYSTEM_LIBS="$BOOST_FILESYSTEM_LIBS $BOOST_SYSTEM_LIBS"
|
BOOST_FILESYSTEM_LIBS="$BOOST_FILESYSTEM_LIBS $BOOST_SYSTEM_LIBS"
|
||||||
fi
|
fi
|
||||||
@@ -809,6 +946,13 @@ BOOST_DEFUN([Function],
|
|||||||
[BOOST_FIND_HEADER([boost/function.hpp])])
|
[BOOST_FIND_HEADER([boost/function.hpp])])
|
||||||
|
|
||||||
|
|
||||||
|
# BOOST_FUSION()
|
||||||
|
# -----------------
|
||||||
|
# Look for Boost.Fusion
|
||||||
|
BOOST_DEFUN([Fusion],
|
||||||
|
[BOOST_FIND_HEADER([boost/fusion/sequence.hpp])])
|
||||||
|
|
||||||
|
|
||||||
# BOOST_GEOMETRY()
|
# BOOST_GEOMETRY()
|
||||||
# ----------------
|
# ----------------
|
||||||
# Look for Boost.Geometry (new since 1.47.0).
|
# Look for Boost.Geometry (new since 1.47.0).
|
||||||
@@ -817,7 +961,7 @@ BOOST_DEFUN([Geometry],
|
|||||||
])# BOOST_GEOMETRY
|
])# BOOST_GEOMETRY
|
||||||
|
|
||||||
|
|
||||||
# BOOST_GRAPH([PREFERRED-RT-OPT])
|
# BOOST_GRAPH([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# -------------------------------
|
# -------------------------------
|
||||||
# Look for Boost.Graphs. For the documentation of PREFERRED-RT-OPT, see the
|
# Look for Boost.Graphs. For the documentation of PREFERRED-RT-OPT, see the
|
||||||
# documentation of BOOST_FIND_LIB above.
|
# documentation of BOOST_FIND_LIB above.
|
||||||
@@ -826,29 +970,19 @@ BOOST_DEFUN([Graph],
|
|||||||
boost_graph_save_LDFLAGS=$LDFLAGS
|
boost_graph_save_LDFLAGS=$LDFLAGS
|
||||||
# Link-time dependency from graph to regex was added as of 1.40.0.
|
# Link-time dependency from graph to regex was added as of 1.40.0.
|
||||||
if test $boost_major_version -ge 140; then
|
if test $boost_major_version -ge 140; then
|
||||||
BOOST_REGEX([$1])
|
BOOST_REGEX([$1], [$2])
|
||||||
m4_pattern_allow([^BOOST_REGEX_(LIBS|LDFLAGS)$])dnl
|
m4_pattern_allow([^BOOST_REGEX_(LIBS|LDFLAGS)$])dnl
|
||||||
LIBS="$LIBS $BOOST_REGEX_LIBS"
|
LIBS="$LIBS $BOOST_REGEX_LIBS"
|
||||||
LDFLAGS="$LDFLAGS $BOOST_REGEX_LDFLAGS"
|
LDFLAGS="$LDFLAGS $BOOST_REGEX_LDFLAGS"
|
||||||
fi
|
fi
|
||||||
BOOST_FIND_LIB([graph], [$1],
|
BOOST_FIND_LIB([graph], [$1],
|
||||||
[boost/graph/adjacency_list.hpp], [boost::adjacency_list<> g;])
|
[boost/graph/adjacency_list.hpp], [boost::adjacency_list<> g;],
|
||||||
|
[], [], [$2])
|
||||||
LIBS=$boost_graph_save_LIBS
|
LIBS=$boost_graph_save_LIBS
|
||||||
LDFLAGS=$boost_graph_save_LDFLAGS
|
LDFLAGS=$boost_graph_save_LDFLAGS
|
||||||
])# BOOST_GRAPH
|
])# BOOST_GRAPH
|
||||||
|
|
||||||
|
|
||||||
# BOOST_IOSTREAMS([PREFERRED-RT-OPT])
|
|
||||||
# -----------------------------------
|
|
||||||
# Look for Boost.IOStreams. For the documentation of PREFERRED-RT-OPT, see the
|
|
||||||
# documentation of BOOST_FIND_LIB above.
|
|
||||||
BOOST_DEFUN([IOStreams],
|
|
||||||
[BOOST_FIND_LIB([iostreams], [$1],
|
|
||||||
[boost/iostreams/device/file_descriptor.hpp],
|
|
||||||
[boost::iostreams::file_descriptor fd; fd.close();])
|
|
||||||
])# BOOST_IOSTREAMS
|
|
||||||
|
|
||||||
|
|
||||||
# BOOST_HASH()
|
# BOOST_HASH()
|
||||||
# ------------
|
# ------------
|
||||||
# Look for Boost.Functional/Hash
|
# Look for Boost.Functional/Hash
|
||||||
@@ -856,6 +990,25 @@ BOOST_DEFUN([Hash],
|
|||||||
[BOOST_FIND_HEADER([boost/functional/hash.hpp])])
|
[BOOST_FIND_HEADER([boost/functional/hash.hpp])])
|
||||||
|
|
||||||
|
|
||||||
|
# BOOST_IOSTREAMS([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
|
# -----------------------------------
|
||||||
|
# Look for Boost.IOStreams. For the documentation of PREFERRED-RT-OPT, see the
|
||||||
|
# documentation of BOOST_FIND_LIB above.
|
||||||
|
BOOST_DEFUN([IOStreams],
|
||||||
|
[BOOST_FIND_LIB([iostreams], [$1],
|
||||||
|
[boost/iostreams/device/file_descriptor.hpp],
|
||||||
|
[boost::iostreams::file_descriptor fd; fd.close();],
|
||||||
|
[], [], [$2])
|
||||||
|
])# BOOST_IOSTREAMS
|
||||||
|
|
||||||
|
|
||||||
|
# BOOST_ITERATOR()
|
||||||
|
# ------------
|
||||||
|
# Look for Boost.Iterator
|
||||||
|
BOOST_DEFUN([Iterator],
|
||||||
|
[BOOST_FIND_HEADER([boost/iterator/iterator_adaptor.hpp])])
|
||||||
|
|
||||||
|
|
||||||
# BOOST_LAMBDA()
|
# BOOST_LAMBDA()
|
||||||
# --------------
|
# --------------
|
||||||
# Look for Boost.Lambda
|
# Look for Boost.Lambda
|
||||||
@@ -863,7 +1016,7 @@ BOOST_DEFUN([Lambda],
|
|||||||
[BOOST_FIND_HEADER([boost/lambda/lambda.hpp])])
|
[BOOST_FIND_HEADER([boost/lambda/lambda.hpp])])
|
||||||
|
|
||||||
|
|
||||||
# BOOST_LOCALE()
|
# BOOST_LOCALE([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# --------------
|
# --------------
|
||||||
# Look for Boost.Locale
|
# Look for Boost.Locale
|
||||||
BOOST_DEFUN([Locale],
|
BOOST_DEFUN([Locale],
|
||||||
@@ -872,40 +1025,40 @@ boost_locale_save_LIBS=$LIBS
|
|||||||
boost_locale_save_LDFLAGS=$LDFLAGS
|
boost_locale_save_LDFLAGS=$LDFLAGS
|
||||||
# require SYSTEM for boost-1.50.0 and up
|
# require SYSTEM for boost-1.50.0 and up
|
||||||
if test $boost_major_version -ge 150; then
|
if test $boost_major_version -ge 150; then
|
||||||
BOOST_SYSTEM([$1])
|
BOOST_SYSTEM([$1], [$2])
|
||||||
m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl
|
m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl
|
||||||
LIBS="$LIBS $BOOST_SYSTEM_LIBS"
|
LIBS="$LIBS $BOOST_SYSTEM_LIBS"
|
||||||
LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS"
|
LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS"
|
||||||
fi # end of the Boost.System check.
|
fi # end of the Boost.System check.
|
||||||
BOOST_FIND_LIB([locale], [$1],
|
BOOST_FIND_LIB([locale], [$1],
|
||||||
[boost/locale.hpp],
|
[boost/locale.hpp],
|
||||||
[[boost::locale::generator gen; std::locale::global(gen(""));]])
|
[[boost::locale::generator gen; std::locale::global(gen(""));]], [], [], [$2])
|
||||||
LIBS=$boost_locale_save_LIBS
|
LIBS=$boost_locale_save_LIBS
|
||||||
LDFLAGS=$boost_locale_save_LDFLAGS
|
LDFLAGS=$boost_locale_save_LDFLAGS
|
||||||
])# BOOST_LOCALE
|
])# BOOST_LOCALE
|
||||||
|
|
||||||
# BOOST_LOG([PREFERRED-RT-OPT])
|
# BOOST_LOG([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
# Look for Boost.Log. For the documentation of PREFERRED-RT-OPT, see the
|
# Look for Boost.Log. For the documentation of PREFERRED-RT-OPT, see the
|
||||||
# documentation of BOOST_FIND_LIB above.
|
# documentation of BOOST_FIND_LIB above.
|
||||||
BOOST_DEFUN([Log],
|
BOOST_DEFUN([Log],
|
||||||
[boost_log_save_LIBS=$LIBS
|
[boost_log_save_LIBS=$LIBS
|
||||||
boost_log_save_LDFLAGS=$LDFLAGS
|
boost_log_save_LDFLAGS=$LDFLAGS
|
||||||
BOOST_SYSTEM([$1])
|
BOOST_SYSTEM([$1], [$2])
|
||||||
BOOST_FILESYSTEM([$1])
|
BOOST_FILESYSTEM([$1], [$2])
|
||||||
BOOST_DATE_TIME([$1])
|
BOOST_DATE_TIME([$1], [$2])
|
||||||
m4_pattern_allow([^BOOST_(SYSTEM|FILESYSTEM|DATE_TIME)_(LIBS|LDFLAGS)$])dnl
|
m4_pattern_allow([^BOOST_(SYSTEM|FILESYSTEM|DATE_TIME)_(LIBS|LDFLAGS)$])dnl
|
||||||
LIBS="$LIBS $BOOST_DATE_TIME_LIBS $BOOST_FILESYSTEM_LIBS $BOOST_SYSTEM_LIBS"
|
LIBS="$LIBS $BOOST_DATE_TIME_LIBS $BOOST_FILESYSTEM_LIBS $BOOST_SYSTEM_LIBS"
|
||||||
LDFLAGS="$LDFLAGS $BOOST_DATE_TIME_LDFLAGS $BOOST_FILESYSTEM_LDFLAGS $BOOST_SYSTEM_LDFLAGS"
|
LDFLAGS="$LDFLAGS $BOOST_DATE_TIME_LDFLAGS $BOOST_FILESYSTEM_LDFLAGS $BOOST_SYSTEM_LDFLAGS"
|
||||||
BOOST_FIND_LIB([log], [$1],
|
BOOST_FIND_LIB([log], [$1],
|
||||||
[boost/log/core/core.hpp],
|
[boost/log/core/core.hpp],
|
||||||
[boost::log::attribute a; a.get_value();])
|
[boost::log::attribute a; a.get_value();], [], [], [$2])
|
||||||
LIBS=$boost_log_save_LIBS
|
LIBS=$boost_log_save_LIBS
|
||||||
LDFLAGS=$boost_log_save_LDFLAGS
|
LDFLAGS=$boost_log_save_LDFLAGS
|
||||||
])# BOOST_LOG
|
])# BOOST_LOG
|
||||||
|
|
||||||
|
|
||||||
# BOOST_LOG_SETUP([PREFERRED-RT-OPT])
|
# BOOST_LOG_SETUP([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# -----------------------------------
|
# -----------------------------------
|
||||||
# Look for Boost.Log. For the documentation of PREFERRED-RT-OPT, see the
|
# Look for Boost.Log. For the documentation of PREFERRED-RT-OPT, see the
|
||||||
# documentation of BOOST_FIND_LIB above.
|
# documentation of BOOST_FIND_LIB above.
|
||||||
@@ -918,7 +1071,7 @@ LIBS="$LIBS $BOOST_LOG_LIBS"
|
|||||||
LDFLAGS="$LDFLAGS $BOOST_LOG_LDFLAGS"
|
LDFLAGS="$LDFLAGS $BOOST_LOG_LDFLAGS"
|
||||||
BOOST_FIND_LIB([log_setup], [$1],
|
BOOST_FIND_LIB([log_setup], [$1],
|
||||||
[boost/log/utility/setup/from_settings.hpp],
|
[boost/log/utility/setup/from_settings.hpp],
|
||||||
[boost::log::basic_settings<char> bs; bs.empty();])
|
[boost::log::basic_settings<char> bs; bs.empty();], [], [], [$2])
|
||||||
LIBS=$boost_log_setup_save_LIBS
|
LIBS=$boost_log_setup_save_LIBS
|
||||||
LDFLAGS=$boost_log_setup_save_LDFLAGS
|
LDFLAGS=$boost_log_setup_save_LDFLAGS
|
||||||
])# BOOST_LOG_SETUP
|
])# BOOST_LOG_SETUP
|
||||||
@@ -936,7 +1089,7 @@ BOOST_DEFUN([Math],
|
|||||||
[BOOST_FIND_HEADER([boost/math/special_functions.hpp])])
|
[BOOST_FIND_HEADER([boost/math/special_functions.hpp])])
|
||||||
|
|
||||||
|
|
||||||
# BOOST_MPI([PREFERRED-RT-OPT])
|
# BOOST_MPI([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# -------------------------------
|
# -------------------------------
|
||||||
# Look for Boost MPI. For the documentation of PREFERRED-RT-OPT, see the
|
# Look for Boost MPI. For the documentation of PREFERRED-RT-OPT, see the
|
||||||
# documentation of BOOST_FIND_LIB above. Uses MPICXX variable if it is
|
# documentation of BOOST_FIND_LIB above. Uses MPICXX variable if it is
|
||||||
@@ -953,12 +1106,20 @@ BOOST_FIND_LIB([mpi], [$1],
|
|||||||
[boost/mpi.hpp],
|
[boost/mpi.hpp],
|
||||||
[int argc = 0;
|
[int argc = 0;
|
||||||
char **argv = 0;
|
char **argv = 0;
|
||||||
boost::mpi::environment env(argc,argv);])
|
boost::mpi::environment env(argc,argv);],
|
||||||
|
[], [], [$2])
|
||||||
CXX=${boost_save_CXX}
|
CXX=${boost_save_CXX}
|
||||||
CXXCPP=${boost_save_CXXCPP}
|
CXXCPP=${boost_save_CXXCPP}
|
||||||
])# BOOST_MPI
|
])# BOOST_MPI
|
||||||
|
|
||||||
|
|
||||||
|
# BOOST_MPL()
|
||||||
|
# ------------------
|
||||||
|
# Look for Boost.MPL
|
||||||
|
BOOST_DEFUN([MPL],
|
||||||
|
[BOOST_FIND_HEADER([boost/mpl/for_each.hpp])])
|
||||||
|
|
||||||
|
|
||||||
# BOOST_MULTIARRAY()
|
# BOOST_MULTIARRAY()
|
||||||
# ------------------
|
# ------------------
|
||||||
# Look for Boost.MultiArray
|
# Look for Boost.MultiArray
|
||||||
@@ -966,6 +1127,13 @@ BOOST_DEFUN([MultiArray],
|
|||||||
[BOOST_FIND_HEADER([boost/multi_array.hpp])])
|
[BOOST_FIND_HEADER([boost/multi_array.hpp])])
|
||||||
|
|
||||||
|
|
||||||
|
# BOOST_MULTIINDEXCCONTAINER()
|
||||||
|
# ------------------
|
||||||
|
# Look for Boost.MultiIndexContainer
|
||||||
|
BOOST_DEFUN([MultiIndexContainer],
|
||||||
|
[BOOST_FIND_HEADER([boost/multi_index_container.hpp])])
|
||||||
|
|
||||||
|
|
||||||
# BOOST_NUMERIC_UBLAS()
|
# BOOST_NUMERIC_UBLAS()
|
||||||
# --------------------------
|
# --------------------------
|
||||||
# Look for Boost.NumericUblas (Basic Linear Algebra)
|
# Look for Boost.NumericUblas (Basic Linear Algebra)
|
||||||
@@ -996,6 +1164,25 @@ BOOST_DEFUN([Preprocessor],
|
|||||||
[BOOST_FIND_HEADER([boost/preprocessor/repeat.hpp])])
|
[BOOST_FIND_HEADER([boost/preprocessor/repeat.hpp])])
|
||||||
|
|
||||||
|
|
||||||
|
# BOOST_PROPERTY_TREE([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
|
# -----------------------------------------
|
||||||
|
# Look for Boost.Property_Tree. For the documentation of PREFERRED-RT-OPT,
|
||||||
|
# see the documentation of BOOST_FIND_LIB above.
|
||||||
|
BOOST_DEFUN([Property_Tree],
|
||||||
|
[BOOST_FIND_LIB([property_tree], [$1],
|
||||||
|
[boost/property_tree/ptree.hpp],
|
||||||
|
[boost::property_tree::ptree pt; boost::property_tree::read_xml d("test", pt);],
|
||||||
|
[], [], [$2])
|
||||||
|
])# BOOST_PROPERTY_TREE
|
||||||
|
|
||||||
|
|
||||||
|
# BOOST_RANDOM()
|
||||||
|
# --------------------
|
||||||
|
# Look for Boost.Random
|
||||||
|
BOOST_DEFUN([Random],
|
||||||
|
[BOOST_FIND_HEADER([boost/random/random_number_generator.hpp])])
|
||||||
|
|
||||||
|
|
||||||
# BOOST_RANGE()
|
# BOOST_RANGE()
|
||||||
# --------------------
|
# --------------------
|
||||||
# Look for Boost.Range
|
# Look for Boost.Range
|
||||||
@@ -1016,14 +1203,15 @@ BOOST_DEFUN([Uuid],
|
|||||||
[BOOST_FIND_HEADER([boost/uuid/uuid.hpp])])
|
[BOOST_FIND_HEADER([boost/uuid/uuid.hpp])])
|
||||||
|
|
||||||
|
|
||||||
# BOOST_PROGRAM_OPTIONS([PREFERRED-RT-OPT])
|
# BOOST_PROGRAM_OPTIONS([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# -----------------------------------------
|
# -----------------------------------------
|
||||||
# Look for Boost.Program_options. For the documentation of PREFERRED-RT-OPT,
|
# Look for Boost.Program_options. For the documentation of PREFERRED-RT-OPT,
|
||||||
# see the documentation of BOOST_FIND_LIB above.
|
# see the documentation of BOOST_FIND_LIB above.
|
||||||
BOOST_DEFUN([Program_Options],
|
BOOST_DEFUN([Program_Options],
|
||||||
[BOOST_FIND_LIB([program_options], [$1],
|
[BOOST_FIND_LIB([program_options], [$1],
|
||||||
[boost/program_options.hpp],
|
[boost/program_options.hpp],
|
||||||
[boost::program_options::options_description d("test");])
|
[boost::program_options::options_description d("test");],
|
||||||
|
[], [], [$2])
|
||||||
])# BOOST_PROGRAM_OPTIONS
|
])# BOOST_PROGRAM_OPTIONS
|
||||||
|
|
||||||
|
|
||||||
@@ -1039,7 +1227,7 @@ boost_python_save_$1=$$1
|
|||||||
$1="$$1 $BOOST_PYTHON_$1"])
|
$1="$$1 $BOOST_PYTHON_$1"])
|
||||||
|
|
||||||
|
|
||||||
# BOOST_PYTHON([PREFERRED-RT-OPT])
|
# BOOST_PYTHON([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# --------------------------------
|
# --------------------------------
|
||||||
# Look for Boost.Python. For the documentation of PREFERRED-RT-OPT,
|
# Look for Boost.Python. For the documentation of PREFERRED-RT-OPT,
|
||||||
# see the documentation of BOOST_FIND_LIB above.
|
# see the documentation of BOOST_FIND_LIB above.
|
||||||
@@ -1050,7 +1238,7 @@ _BOOST_PYTHON_CONFIG([LIBS], [libs])
|
|||||||
m4_pattern_allow([^BOOST_PYTHON_MODULE$])dnl
|
m4_pattern_allow([^BOOST_PYTHON_MODULE$])dnl
|
||||||
BOOST_FIND_LIBS([python], [python python3], [$1],
|
BOOST_FIND_LIBS([python], [python python3], [$1],
|
||||||
[boost/python.hpp],
|
[boost/python.hpp],
|
||||||
[], [BOOST_PYTHON_MODULE(empty) {}])
|
[], [BOOST_PYTHON_MODULE(empty) {}], [], [$2])
|
||||||
CPPFLAGS=$boost_python_save_CPPFLAGS
|
CPPFLAGS=$boost_python_save_CPPFLAGS
|
||||||
LDFLAGS=$boost_python_save_LDFLAGS
|
LDFLAGS=$boost_python_save_LDFLAGS
|
||||||
LIBS=$boost_python_save_LIBS
|
LIBS=$boost_python_save_LIBS
|
||||||
@@ -1064,18 +1252,26 @@ BOOST_DEFUN([Ref],
|
|||||||
[BOOST_FIND_HEADER([boost/ref.hpp])])
|
[BOOST_FIND_HEADER([boost/ref.hpp])])
|
||||||
|
|
||||||
|
|
||||||
# BOOST_REGEX([PREFERRED-RT-OPT])
|
# BOOST_REGEX([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# -------------------------------
|
# -------------------------------
|
||||||
# Look for Boost.Regex. For the documentation of PREFERRED-RT-OPT, see the
|
# Look for Boost.Regex. For the documentation of PREFERRED-RT-OPT, see the
|
||||||
# documentation of BOOST_FIND_LIB above.
|
# documentation of BOOST_FIND_LIB above.
|
||||||
BOOST_DEFUN([Regex],
|
BOOST_DEFUN([Regex],
|
||||||
[BOOST_FIND_LIB([regex], [$1],
|
[BOOST_FIND_LIB([regex], [$1],
|
||||||
[boost/regex.hpp],
|
[boost/regex.hpp],
|
||||||
[boost::regex exp("*"); boost::regex_match("foo", exp);])
|
[boost::regex exp("*"); boost::regex_match("foo", exp);],
|
||||||
|
[], [], [$2])
|
||||||
])# BOOST_REGEX
|
])# BOOST_REGEX
|
||||||
|
|
||||||
|
|
||||||
# BOOST_SERIALIZATION([PREFERRED-RT-OPT])
|
# BOOST_SCOPE_EXIT()
|
||||||
|
# ------------
|
||||||
|
# Look for Boost.ScopeExit.
|
||||||
|
BOOST_DEFUN([SCOPE_EXIT],
|
||||||
|
[BOOST_FIND_HEADER([boost/scope_exit.hpp])])
|
||||||
|
|
||||||
|
|
||||||
|
# BOOST_SERIALIZATION([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# ---------------------------------------
|
# ---------------------------------------
|
||||||
# Look for Boost.Serialization. For the documentation of PREFERRED-RT-OPT, see
|
# Look for Boost.Serialization. For the documentation of PREFERRED-RT-OPT, see
|
||||||
# the documentation of BOOST_FIND_LIB above.
|
# the documentation of BOOST_FIND_LIB above.
|
||||||
@@ -1083,18 +1279,20 @@ BOOST_DEFUN([Serialization],
|
|||||||
[BOOST_FIND_LIB([serialization], [$1],
|
[BOOST_FIND_LIB([serialization], [$1],
|
||||||
[boost/archive/text_oarchive.hpp],
|
[boost/archive/text_oarchive.hpp],
|
||||||
[std::ostream* o = 0; // Cheap way to get an ostream...
|
[std::ostream* o = 0; // Cheap way to get an ostream...
|
||||||
boost::archive::text_oarchive t(*o);])
|
boost::archive::text_oarchive t(*o);],
|
||||||
|
[], [], [$2])
|
||||||
])# BOOST_SERIALIZATION
|
])# BOOST_SERIALIZATION
|
||||||
|
|
||||||
|
|
||||||
# BOOST_SIGNALS([PREFERRED-RT-OPT])
|
# BOOST_SIGNALS([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# ---------------------------------
|
# ---------------------------------
|
||||||
# Look for Boost.Signals. For the documentation of PREFERRED-RT-OPT, see the
|
# Look for Boost.Signals. For the documentation of PREFERRED-RT-OPT, see the
|
||||||
# documentation of BOOST_FIND_LIB above.
|
# documentation of BOOST_FIND_LIB above.
|
||||||
BOOST_DEFUN([Signals],
|
BOOST_DEFUN([Signals],
|
||||||
[BOOST_FIND_LIB([signals], [$1],
|
[BOOST_FIND_LIB([signals], [$1],
|
||||||
[boost/signal.hpp],
|
[boost/signal.hpp],
|
||||||
[boost::signal<void ()> s;])
|
[boost::signal<void ()> s;],
|
||||||
|
[], [], [$2])
|
||||||
])# BOOST_SIGNALS
|
])# BOOST_SIGNALS
|
||||||
|
|
||||||
|
|
||||||
@@ -1130,19 +1328,24 @@ BOOST_DEFUN([String_Algo],
|
|||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
# BOOST_SYSTEM([PREFERRED-RT-OPT])
|
# BOOST_SYSTEM([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# --------------------------------
|
# --------------------------------
|
||||||
# Look for Boost.System. For the documentation of PREFERRED-RT-OPT, see the
|
# Look for Boost.System. For the documentation of PREFERRED-RT-OPT, see the
|
||||||
# documentation of BOOST_FIND_LIB above. This library was introduced in Boost
|
# documentation of BOOST_FIND_LIB above. This library was introduced in Boost
|
||||||
# 1.35.0.
|
# 1.35.0 and is header only since 1.70.
|
||||||
BOOST_DEFUN([System],
|
BOOST_DEFUN([System],
|
||||||
[BOOST_FIND_LIB([system], [$1],
|
[
|
||||||
|
if test $boost_major_version -ge 170; then
|
||||||
|
BOOST_FIND_HEADER([boost/system/error_code.hpp])
|
||||||
|
else
|
||||||
|
BOOST_FIND_LIB([system], [$1],
|
||||||
[boost/system/error_code.hpp],
|
[boost/system/error_code.hpp],
|
||||||
[boost::system::error_code e; e.clear();])
|
[boost::system::error_code e; e.clear();], [], [], [$2])
|
||||||
|
fi
|
||||||
])# BOOST_SYSTEM
|
])# BOOST_SYSTEM
|
||||||
|
|
||||||
|
|
||||||
# BOOST_TEST([PREFERRED-RT-OPT])
|
# BOOST_TEST([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# ------------------------------
|
# ------------------------------
|
||||||
# Look for Boost.Test. For the documentation of PREFERRED-RT-OPT, see the
|
# Look for Boost.Test. For the documentation of PREFERRED-RT-OPT, see the
|
||||||
# documentation of BOOST_FIND_LIB above.
|
# documentation of BOOST_FIND_LIB above.
|
||||||
@@ -1152,11 +1355,11 @@ BOOST_FIND_LIB([unit_test_framework], [$1],
|
|||||||
[boost/test/unit_test.hpp], [BOOST_CHECK(2 == 2);],
|
[boost/test/unit_test.hpp], [BOOST_CHECK(2 == 2);],
|
||||||
[using boost::unit_test::test_suite;
|
[using boost::unit_test::test_suite;
|
||||||
test_suite* init_unit_test_suite(int argc, char ** argv)
|
test_suite* init_unit_test_suite(int argc, char ** argv)
|
||||||
{ return NULL; }])
|
{ return NULL; }], [], [$2])
|
||||||
])# BOOST_TEST
|
])# BOOST_TEST
|
||||||
|
|
||||||
|
|
||||||
# BOOST_THREAD([PREFERRED-RT-OPT])
|
# BOOST_THREAD([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# ---------------------------------
|
# ---------------------------------
|
||||||
# Look for Boost.Thread. For the documentation of PREFERRED-RT-OPT, see the
|
# Look for Boost.Thread. For the documentation of PREFERRED-RT-OPT, see the
|
||||||
# documentation of BOOST_FIND_LIB above.
|
# documentation of BOOST_FIND_LIB above.
|
||||||
@@ -1170,7 +1373,7 @@ boost_thread_save_LDFLAGS=$LDFLAGS
|
|||||||
boost_thread_save_CPPFLAGS=$CPPFLAGS
|
boost_thread_save_CPPFLAGS=$CPPFLAGS
|
||||||
# Link-time dependency from thread to system was added as of 1.49.0.
|
# Link-time dependency from thread to system was added as of 1.49.0.
|
||||||
if test $boost_major_version -ge 149; then
|
if test $boost_major_version -ge 149; then
|
||||||
BOOST_SYSTEM([$1])
|
BOOST_SYSTEM([$1], [$2])
|
||||||
fi # end of the Boost.System check.
|
fi # end of the Boost.System check.
|
||||||
m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl
|
m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl
|
||||||
LIBS="$LIBS $BOOST_SYSTEM_LIBS $boost_cv_pthread_flag"
|
LIBS="$LIBS $BOOST_SYSTEM_LIBS $boost_cv_pthread_flag"
|
||||||
@@ -1189,7 +1392,7 @@ if test $boost_major_version -lt 148; then
|
|||||||
fi
|
fi
|
||||||
BOOST_FIND_LIBS([thread], [thread$boost_thread_lib_ext],
|
BOOST_FIND_LIBS([thread], [thread$boost_thread_lib_ext],
|
||||||
[$1],
|
[$1],
|
||||||
[boost/thread.hpp], [boost::thread t; boost::mutex m;])
|
[boost/thread.hpp], [boost::thread t; boost::mutex m;], [], [], [$2])
|
||||||
|
|
||||||
case $host_os in
|
case $host_os in
|
||||||
(*mingw*) boost_thread_w32_socket_link=-lws2_32;;
|
(*mingw*) boost_thread_w32_socket_link=-lws2_32;;
|
||||||
@@ -1265,7 +1468,7 @@ BOOST_FIND_HEADER([boost/ptr_container/ptr_map.hpp])
|
|||||||
])# BOOST_POINTER_CONTAINER
|
])# BOOST_POINTER_CONTAINER
|
||||||
|
|
||||||
|
|
||||||
# BOOST_WAVE([PREFERRED-RT-OPT])
|
# BOOST_WAVE([PREFERRED-RT-OPT], [ERROR_ON_UNUSABLE])
|
||||||
# ------------------------------
|
# ------------------------------
|
||||||
# NOTE: If you intend to use Wave/Spirit with thread support, make sure you
|
# NOTE: If you intend to use Wave/Spirit with thread support, make sure you
|
||||||
# call BOOST_THREAD first.
|
# call BOOST_THREAD first.
|
||||||
@@ -1283,7 +1486,7 @@ LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS $BOOST_FILESYSTEM_LDFLAGS \
|
|||||||
$BOOST_DATE_TIME_LDFLAGS $BOOST_THREAD_LDFLAGS"
|
$BOOST_DATE_TIME_LDFLAGS $BOOST_THREAD_LDFLAGS"
|
||||||
BOOST_FIND_LIB([wave], [$1],
|
BOOST_FIND_LIB([wave], [$1],
|
||||||
[boost/wave.hpp],
|
[boost/wave.hpp],
|
||||||
[boost::wave::token_id id; get_token_name(id);])
|
[boost::wave::token_id id; get_token_name(id);], [], [], [$2])
|
||||||
LIBS=$boost_wave_save_LIBS
|
LIBS=$boost_wave_save_LIBS
|
||||||
LDFLAGS=$boost_wave_save_LDFLAGS
|
LDFLAGS=$boost_wave_save_LDFLAGS
|
||||||
])# BOOST_WAVE
|
])# BOOST_WAVE
|
||||||
@@ -1351,10 +1554,11 @@ AC_CACHE_CHECK([for the flags needed to use pthreads], [boost_cv_pthread_flag],
|
|||||||
-pthreads -mthreads -lpthread --thread-safe -mt";;
|
-pthreads -mthreads -lpthread --thread-safe -mt";;
|
||||||
esac
|
esac
|
||||||
# Generate the test file.
|
# Generate the test file.
|
||||||
AC_LANG_CONFTEST([AC_LANG_PROGRAM([#include <pthread.h>],
|
AC_LANG_CONFTEST([AC_LANG_PROGRAM([#include <pthread.h>
|
||||||
[pthread_t th; pthread_join(th, 0);
|
void *f(void*){ return 0; }],
|
||||||
pthread_attr_init(0); pthread_cleanup_push(0, 0);
|
[pthread_t th; pthread_create(&th,0,f,0); pthread_join(th,0);
|
||||||
pthread_create(0,0,0,0); pthread_cleanup_pop(0);])])
|
pthread_attr_t attr; pthread_attr_init(&attr); pthread_cleanup_push(0, 0);
|
||||||
|
pthread_cleanup_pop(0);])])
|
||||||
for boost_pthread_flag in '' $boost_pthread_flags; do
|
for boost_pthread_flag in '' $boost_pthread_flags; do
|
||||||
boost_pthread_ok=false
|
boost_pthread_ok=false
|
||||||
dnl Re-use the test file already generated.
|
dnl Re-use the test file already generated.
|
||||||
@@ -1416,12 +1620,77 @@ if test x$boost_cv_inc_path != xno; then
|
|||||||
# I'm not sure about my test for `il' (be careful: Intel's ICC pre-defines
|
# I'm not sure about my test for `il' (be careful: Intel's ICC pre-defines
|
||||||
# the same defines as GCC's).
|
# the same defines as GCC's).
|
||||||
for i in \
|
for i in \
|
||||||
|
"defined __clang__ && __clang_major__ == 14 && __clang_minor__ == 0 @ clang140" \
|
||||||
|
"defined __clang__ && __clang_major__ == 13 && __clang_minor__ == 0 @ clang130" \
|
||||||
|
"defined __clang__ && __clang_major__ == 12 && __clang_minor__ == 0 @ clang120" \
|
||||||
|
"defined __clang__ && __clang_major__ == 11 && __clang_minor__ == 1 @ clang111" \
|
||||||
|
"defined __clang__ && __clang_major__ == 11 && __clang_minor__ == 0 @ clang110" \
|
||||||
|
"defined __clang__ && __clang_major__ == 10 && __clang_minor__ == 0 @ clang100" \
|
||||||
|
"defined __clang__ && __clang_major__ == 9 && __clang_minor__ == 0 @ clang90" \
|
||||||
|
"defined __clang__ && __clang_major__ == 8 && __clang_minor__ == 0 @ clang80" \
|
||||||
|
"defined __clang__ && __clang_major__ == 7 && __clang_minor__ == 0 @ clang70" \
|
||||||
|
"defined __clang__ && __clang_major__ == 6 && __clang_minor__ == 0 @ clang60" \
|
||||||
|
"defined __clang__ && __clang_major__ == 5 && __clang_minor__ == 0 @ clang50" \
|
||||||
|
"defined __clang__ && __clang_major__ == 4 && __clang_minor__ == 0 @ clang40" \
|
||||||
|
"defined __clang__ && __clang_major__ == 3 && __clang_minor__ == 9 @ clang39" \
|
||||||
|
"defined __clang__ && __clang_major__ == 3 && __clang_minor__ == 8 @ clang38" \
|
||||||
|
"defined __clang__ && __clang_major__ == 3 && __clang_minor__ == 7 @ clang37" \
|
||||||
|
_BOOST_mingw_test(11, 2) \
|
||||||
|
_BOOST_gcc_test(11, 2) \
|
||||||
|
_BOOST_mingw_test(11, 1) \
|
||||||
|
_BOOST_gcc_test(11, 1) \
|
||||||
|
_BOOST_mingw_test(10, 3) \
|
||||||
|
_BOOST_gcc_test(10, 3) \
|
||||||
|
_BOOST_mingw_test(10, 2) \
|
||||||
|
_BOOST_gcc_test(10, 2) \
|
||||||
|
_BOOST_mingw_test(10, 1) \
|
||||||
|
_BOOST_gcc_test(10, 1) \
|
||||||
|
_BOOST_mingw_test(9, 3) \
|
||||||
|
_BOOST_gcc_test(9, 3) \
|
||||||
|
_BOOST_mingw_test(9, 2) \
|
||||||
|
_BOOST_gcc_test(9, 2) \
|
||||||
|
_BOOST_mingw_test(9, 1) \
|
||||||
|
_BOOST_gcc_test(9, 1) \
|
||||||
|
_BOOST_mingw_test(9, 0) \
|
||||||
|
_BOOST_gcc_test(9, 0) \
|
||||||
|
_BOOST_mingw_test(8, 5) \
|
||||||
|
_BOOST_gcc_test(8, 5) \
|
||||||
|
_BOOST_mingw_test(8, 4) \
|
||||||
|
_BOOST_gcc_test(8, 4) \
|
||||||
|
_BOOST_mingw_test(8, 3) \
|
||||||
|
_BOOST_gcc_test(8, 3) \
|
||||||
|
_BOOST_mingw_test(8, 2) \
|
||||||
|
_BOOST_gcc_test(8, 2) \
|
||||||
|
_BOOST_mingw_test(8, 1) \
|
||||||
|
_BOOST_gcc_test(8, 1) \
|
||||||
|
_BOOST_mingw_test(8, 0) \
|
||||||
|
_BOOST_gcc_test(8, 0) \
|
||||||
|
_BOOST_mingw_test(7, 4) \
|
||||||
|
_BOOST_gcc_test(7, 4) \
|
||||||
|
_BOOST_mingw_test(7, 3) \
|
||||||
|
_BOOST_gcc_test(7, 3) \
|
||||||
|
_BOOST_mingw_test(7, 2) \
|
||||||
|
_BOOST_gcc_test(7, 2) \
|
||||||
|
_BOOST_mingw_test(7, 1) \
|
||||||
|
_BOOST_gcc_test(7, 1) \
|
||||||
|
_BOOST_mingw_test(7, 0) \
|
||||||
|
_BOOST_gcc_test(7, 0) \
|
||||||
|
_BOOST_mingw_test(6, 5) \
|
||||||
|
_BOOST_gcc_test(6, 5) \
|
||||||
|
_BOOST_mingw_test(6, 4) \
|
||||||
|
_BOOST_gcc_test(6, 4) \
|
||||||
|
_BOOST_mingw_test(6, 3) \
|
||||||
|
_BOOST_gcc_test(6, 3) \
|
||||||
_BOOST_mingw_test(6, 2) \
|
_BOOST_mingw_test(6, 2) \
|
||||||
_BOOST_gcc_test(6, 2) \
|
_BOOST_gcc_test(6, 2) \
|
||||||
_BOOST_mingw_test(6, 1) \
|
_BOOST_mingw_test(6, 1) \
|
||||||
_BOOST_gcc_test(6, 1) \
|
_BOOST_gcc_test(6, 1) \
|
||||||
_BOOST_mingw_test(6, 0) \
|
_BOOST_mingw_test(6, 0) \
|
||||||
_BOOST_gcc_test(6, 0) \
|
_BOOST_gcc_test(6, 0) \
|
||||||
|
_BOOST_mingw_test(5, 5) \
|
||||||
|
_BOOST_gcc_test(5, 5) \
|
||||||
|
_BOOST_mingw_test(5, 4) \
|
||||||
|
_BOOST_gcc_test(5, 4) \
|
||||||
_BOOST_mingw_test(5, 3) \
|
_BOOST_mingw_test(5, 3) \
|
||||||
_BOOST_gcc_test(5, 3) \
|
_BOOST_gcc_test(5, 3) \
|
||||||
_BOOST_mingw_test(5, 2) \
|
_BOOST_mingw_test(5, 2) \
|
||||||
|
|||||||
286
src/actions.cpp
286
src/actions.cpp
@@ -20,22 +20,16 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||||
#include <boost/filesystem/operations.hpp>
|
#include <boost/filesystem/operations.hpp>
|
||||||
#include <boost/locale/conversion.hpp>
|
#include <boost/locale/conversion.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <boost/process/child.hpp>
|
|
||||||
#include <boost/process/io.hpp>
|
|
||||||
#include <boost/process/pipe.hpp>
|
|
||||||
#include <boost/process/search_path.hpp>
|
|
||||||
#include <boost/property_tree/exceptions.hpp>
|
|
||||||
#include <boost/property_tree/json_parser.hpp>
|
|
||||||
#include <boost/property_tree/ptree.hpp>
|
|
||||||
#include <boost/property_tree/ptree_fwd.hpp>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <mpd/tag.h>
|
#include <mpd/tag.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include "actions.h"
|
#include "actions.h"
|
||||||
#include "charset.h"
|
#include "charset.h"
|
||||||
@@ -133,18 +127,6 @@ size_t HeaderHeight;
|
|||||||
size_t FooterHeight;
|
size_t FooterHeight;
|
||||||
size_t FooterStartY;
|
size_t FooterStartY;
|
||||||
|
|
||||||
void validateScreenSize()
|
|
||||||
{
|
|
||||||
using Global::MainHeight;
|
|
||||||
|
|
||||||
if (COLS < 30 || MainHeight < 5)
|
|
||||||
{
|
|
||||||
NC::destroyScreen();
|
|
||||||
std::cout << "Screen is too small to handle ncmpcpp correctly\n";
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void initializeScreens()
|
void initializeScreens()
|
||||||
{
|
{
|
||||||
myHelp = new Help;
|
myHelp = new Help;
|
||||||
@@ -230,8 +212,6 @@ void resizeScreen(bool reload_main_window)
|
|||||||
|
|
||||||
MainHeight = std::max(LINES-(Config.design == Design::Alternative ? 7 : 4), 0);
|
MainHeight = std::max(LINES-(Config.design == Design::Alternative ? 7 : 4), 0);
|
||||||
|
|
||||||
validateScreenSize();
|
|
||||||
|
|
||||||
if (!Config.header_visibility)
|
if (!Config.header_visibility)
|
||||||
MainHeight += 2;
|
MainHeight += 2;
|
||||||
if (!Config.statusbar_visibility)
|
if (!Config.statusbar_visibility)
|
||||||
@@ -1769,33 +1749,46 @@ void JumpToPositionInSong::run()
|
|||||||
std::string spos;
|
std::string spos;
|
||||||
{
|
{
|
||||||
Statusbar::ScopedLock slock;
|
Statusbar::ScopedLock slock;
|
||||||
Statusbar::put() << "Position to go (in %/m:ss/seconds(s)): ";
|
Statusbar::put() << "Position to go (in %/h:m:ss/m:ss/seconds(s)): ";
|
||||||
spos = wFooter->prompt();
|
spos = wFooter->prompt();
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::regex rx;
|
boost::regex rx;
|
||||||
boost::smatch what;
|
boost::smatch what;
|
||||||
if (boost::regex_match(spos, what, rx.assign("([0-9]+):([0-9]{2})"))) // mm:ss
|
// mm:ss
|
||||||
|
if (boost::regex_match(spos, what, rx.assign("([0-9]+):([0-9]{2})")))
|
||||||
{
|
{
|
||||||
auto mins = fromString<unsigned>(what[1]);
|
auto mins = fromString<unsigned>(what[1]);
|
||||||
auto secs = fromString<unsigned>(what[2]);
|
auto secs = fromString<unsigned>(what[2]);
|
||||||
boundsCheck(secs, 0u, 60u);
|
boundsCheck(secs, 0u, 60u);
|
||||||
Mpd.Seek(s.getPosition(), mins * 60 + secs);
|
Mpd.Seek(s.getPosition(), mins * 60 + secs);
|
||||||
}
|
}
|
||||||
else if (boost::regex_match(spos, what, rx.assign("([0-9]+)s"))) // position in seconds
|
// position in seconds
|
||||||
|
else if (boost::regex_match(spos, what, rx.assign("([0-9]+)s")))
|
||||||
{
|
{
|
||||||
auto secs = fromString<unsigned>(what[1]);
|
auto secs = fromString<unsigned>(what[1]);
|
||||||
Mpd.Seek(s.getPosition(), secs);
|
Mpd.Seek(s.getPosition(), secs);
|
||||||
}
|
}
|
||||||
else if (boost::regex_match(spos, what, rx.assign("([0-9]+)[%]{0,1}"))) // position in %
|
// position in%
|
||||||
|
else if (boost::regex_match(spos, what, rx.assign("([0-9]+)[%]{0,1}")))
|
||||||
{
|
{
|
||||||
auto percent = fromString<unsigned>(what[1]);
|
auto percent = fromString<unsigned>(what[1]);
|
||||||
boundsCheck(percent, 0u, 100u);
|
boundsCheck(percent, 0u, 100u);
|
||||||
int secs = (percent * s.getDuration()) / 100.0;
|
int secs = (percent * s.getDuration()) / 100.0;
|
||||||
Mpd.Seek(s.getPosition(), secs);
|
Mpd.Seek(s.getPosition(), secs);
|
||||||
}
|
}
|
||||||
|
// position in hh:mm:ss
|
||||||
|
else if (boost::regex_match(spos, what, rx.assign("([0-9]+):([0-9]{2}):([0-9]{2})")))
|
||||||
|
{
|
||||||
|
auto hours = fromString<unsigned>(what[1]);
|
||||||
|
auto mins = fromString<unsigned>(what[2]);
|
||||||
|
auto secs = fromString<unsigned>(what[3]);
|
||||||
|
boundsCheck(mins, 0u, 60u);
|
||||||
|
boundsCheck(secs, 0u, 60u);
|
||||||
|
Mpd.Seek(s.getPosition(), hours * 3600 + mins * 60 + secs);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
Statusbar::print("Invalid format ([m]:[ss], [s]s, [%]%, [%] accepted)");
|
Statusbar::print("Invalid format ([h]:[mm]:[ss], [m]:[ss], [s]s, [%]%, [%] accepted)");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SelectItem::canBeRun()
|
bool SelectItem::canBeRun()
|
||||||
@@ -2008,7 +2001,10 @@ bool ReversePlaylist::canBeRun()
|
|||||||
return false;
|
return false;
|
||||||
m_begin = myPlaylist->main().begin();
|
m_begin = myPlaylist->main().begin();
|
||||||
m_end = myPlaylist->main().end();
|
m_end = myPlaylist->main().end();
|
||||||
return findSelectedRangeAndPrintInfoIfNot(m_begin, m_end);
|
if (m_begin == m_end)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return findSelectedRangeAndPrintInfoIfNot(m_begin, m_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReversePlaylist::run()
|
void ReversePlaylist::run()
|
||||||
@@ -2763,13 +2759,11 @@ bool AddYoutubeDLItem::canBeRun()
|
|||||||
void AddYoutubeDLItem::run()
|
void AddYoutubeDLItem::run()
|
||||||
{
|
{
|
||||||
using Global::wFooter;
|
using Global::wFooter;
|
||||||
namespace bp = boost::process;
|
|
||||||
namespace pt = boost::property_tree;
|
|
||||||
|
|
||||||
std::string url;
|
std::string url;
|
||||||
{
|
{
|
||||||
Statusbar::ScopedLock slock;
|
Statusbar::ScopedLock slock;
|
||||||
Statusbar::put() << "Add via youtube-dl: ";
|
Statusbar::put() << "Add via youtube-dl/yt-dlp: ";
|
||||||
url = wFooter->prompt();
|
url = wFooter->prompt();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2777,74 +2771,192 @@ void AddYoutubeDLItem::run()
|
|||||||
if (url.empty())
|
if (url.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// search the youtube-dl executable in the PATH
|
// Try to find yt-dlp first, fall back to youtube-dl
|
||||||
auto ydl_path = bp::search_path("youtube-dl");
|
std::string ydl_executable;
|
||||||
if (ydl_path.empty()) {
|
{
|
||||||
Statusbar::print("youtube-dl was not found in PATH");
|
FILE *which_pipe = popen("which yt-dlp 2>/dev/null", "r");
|
||||||
|
if (which_pipe)
|
||||||
|
{
|
||||||
|
char path[256];
|
||||||
|
if (fgets(path, sizeof(path), which_pipe) != nullptr)
|
||||||
|
{
|
||||||
|
// Remove trailing newline
|
||||||
|
size_t len = strlen(path);
|
||||||
|
if (len > 0 && path[len-1] == '\n')
|
||||||
|
path[len-1] = '\0';
|
||||||
|
ydl_executable = path;
|
||||||
|
}
|
||||||
|
pclose(which_pipe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to youtube-dl if yt-dlp not found
|
||||||
|
if (ydl_executable.empty())
|
||||||
|
{
|
||||||
|
FILE *which_pipe = popen("which youtube-dl 2>/dev/null", "r");
|
||||||
|
if (which_pipe)
|
||||||
|
{
|
||||||
|
char path[256];
|
||||||
|
if (fgets(path, sizeof(path), which_pipe) != nullptr)
|
||||||
|
{
|
||||||
|
size_t len = strlen(path);
|
||||||
|
if (len > 0 && path[len-1] == '\n')
|
||||||
|
path[len-1] = '\0';
|
||||||
|
ydl_executable = path;
|
||||||
|
}
|
||||||
|
pclose(which_pipe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ydl_executable.empty())
|
||||||
|
{
|
||||||
|
Statusbar::print("Neither yt-dlp nor youtube-dl was found in PATH");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Statusbar::printf("Calling youtube-dl with '%1%' ...", url);
|
Statusbar::printf("Fetching from '%s'...", url.c_str());
|
||||||
|
|
||||||
// start youtube-dl in a child process
|
// Build command with proper shell escaping
|
||||||
// -j: output as JSON, each playlist item on a separate line
|
std::string escaped_url = url;
|
||||||
// -f bestaudio/best: selects the best available audio-only stream, or
|
// Simple shell escape - replace single quotes with '\''
|
||||||
// alternatively the best audio+video stream
|
size_t pos = 0;
|
||||||
bp::ipstream output;
|
while ((pos = escaped_url.find("'", pos)) != std::string::npos)
|
||||||
bp::child child_process(ydl_path, url, "-j", "-f", "bestaudio/best", "--playlist-end", "100, bp::std_out > output,
|
{
|
||||||
bp::std_err > bp::null);
|
escaped_url.replace(pos, 1, "'\\''");
|
||||||
|
pos += 4;
|
||||||
|
}
|
||||||
|
|
||||||
// extract the URL and metadata from a ptree object and add
|
// Use --flat-playlist to get all items, then process each one
|
||||||
auto add_song = [] (const pt::ptree& ptree) {
|
// First get list of video IDs/URLs from playlist
|
||||||
auto download_url = ptree.get<std::string>("url");
|
std::string command = ydl_executable + " --flat-playlist --get-id " +
|
||||||
auto title = ptree.get_optional<std::string>("title");
|
"--playlist-end 100 " +
|
||||||
auto artist = ptree.get_optional<std::string>("creator");
|
"'" + escaped_url + "' 2>/dev/null";
|
||||||
if (!artist.has_value()) {
|
|
||||||
artist = ptree.get_optional<std::string>("uploader");
|
FILE *pipe = popen(command.c_str(), "r");
|
||||||
}
|
if (!pipe)
|
||||||
auto album = ptree.get_optional<std::string>("album");
|
{
|
||||||
auto id = Mpd.AddSong(download_url);
|
Statusbar::print("Failed to execute downloader");
|
||||||
if (id == -1) {
|
return;
|
||||||
return 0;
|
}
|
||||||
}
|
|
||||||
if (title.has_value()) {
|
std::vector<std::string> video_ids;
|
||||||
Mpd.AddTag(id, MPD_TAG_TITLE, *title);
|
char line[4096];
|
||||||
}
|
|
||||||
if (artist.has_value()) {
|
// Collect all video IDs
|
||||||
Mpd.AddTag(id, MPD_TAG_ARTIST, *artist);
|
while (fgets(line, sizeof(line), pipe) != nullptr)
|
||||||
}
|
{
|
||||||
if (album.has_value()) {
|
size_t len = strlen(line);
|
||||||
Mpd.AddTag(id, MPD_TAG_ALBUM, *album);
|
while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r'))
|
||||||
}
|
{
|
||||||
return 1;
|
line[--len] = '\0';
|
||||||
};
|
}
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
video_ids.push_back(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
pclose(pipe);
|
||||||
|
|
||||||
|
if (video_ids.empty())
|
||||||
|
{
|
||||||
|
Statusbar::print("No items found in playlist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Statusbar::printf("Found %u items, fetching URLs...",
|
||||||
|
static_cast<unsigned>(video_ids.size()));
|
||||||
|
|
||||||
std::string line;
|
|
||||||
pt::ptree ptree;
|
|
||||||
unsigned num_songs_added = 0;
|
unsigned num_songs_added = 0;
|
||||||
|
|
||||||
while (std::getline(output, line)) {
|
// Now process each video to get its title and stream URL
|
||||||
try {
|
for (const auto &video_id : video_ids)
|
||||||
std::istringstream line_stream(line);
|
{
|
||||||
pt::read_json(line_stream, ptree);
|
// Build URL for this specific video
|
||||||
num_songs_added += add_song(ptree);
|
std::string video_url;
|
||||||
} catch (pt::ptree_error &e) {
|
if (video_id.find("http") == 0)
|
||||||
Statusbar::print("An error occurred while parsing the output of youtube-dl");
|
{
|
||||||
continue;
|
video_url = video_id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Assume it's a YouTube ID
|
||||||
|
video_url = "https://www.youtube.com/watch?v=" + video_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Escape the video URL
|
||||||
|
std::string escaped_video_url = video_url;
|
||||||
|
pos = 0;
|
||||||
|
while ((pos = escaped_video_url.find("'", pos)) != std::string::npos)
|
||||||
|
{
|
||||||
|
escaped_video_url.replace(pos, 1, "'\\''");
|
||||||
|
pos += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get title and URL for this specific video
|
||||||
|
std::string video_command = ydl_executable + " --get-title --get-url " +
|
||||||
|
"-f bestaudio/best " +
|
||||||
|
"'" + escaped_video_url + "' 2>/dev/null";
|
||||||
|
|
||||||
|
FILE *video_pipe = popen(video_command.c_str(), "r");
|
||||||
|
if (!video_pipe)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::string title;
|
||||||
|
std::string stream_url;
|
||||||
|
int line_num = 0;
|
||||||
|
|
||||||
|
while (fgets(line, sizeof(line), video_pipe) != nullptr)
|
||||||
|
{
|
||||||
|
size_t len = strlen(line);
|
||||||
|
while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r'))
|
||||||
|
{
|
||||||
|
line[--len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (line_num == 0)
|
||||||
|
title = line;
|
||||||
|
else if (line_num == 1)
|
||||||
|
stream_url = line;
|
||||||
|
|
||||||
|
++line_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
pclose(video_pipe);
|
||||||
|
|
||||||
|
// Add to MPD if we got both title and URL
|
||||||
|
if (!stream_url.empty() &&
|
||||||
|
(stream_url.find("http://") == 0 || stream_url.find("https://") == 0))
|
||||||
|
{
|
||||||
|
int id = Mpd.AddSong(stream_url);
|
||||||
|
if (id != -1)
|
||||||
|
{
|
||||||
|
if (!title.empty())
|
||||||
|
Mpd.AddTag(id, MPD_TAG_TITLE, title);
|
||||||
|
|
||||||
|
++num_songs_added;
|
||||||
|
|
||||||
|
std::string display = title.empty() ? video_id : title;
|
||||||
|
if (display.length() > 50)
|
||||||
|
display = display.substr(0, 47) + "...";
|
||||||
|
|
||||||
|
Statusbar::printf("Added: %s (%u/%u)",
|
||||||
|
display.c_str(),
|
||||||
|
num_songs_added,
|
||||||
|
static_cast<unsigned>(video_ids.size()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Statusbar::printf("Added %1% item(s) to playlist", num_songs_added);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child_process.running()) {
|
if (num_songs_added > 0)
|
||||||
child_process.terminate();
|
{
|
||||||
|
Statusbar::printf("Successfully added %u item(s) to playlist", num_songs_added);
|
||||||
}
|
}
|
||||||
child_process.wait();
|
else
|
||||||
|
{
|
||||||
auto ec = child_process.exit_code();
|
Statusbar::print("Failed to add any items");
|
||||||
if (ec == 0) {
|
|
||||||
Statusbar::printf("Added %1% item(s) to playlist", num_songs_added);
|
|
||||||
} else {
|
|
||||||
Statusbar::printf("Added %1% item(s) to playlist (youtube-dl exited with exit code %2%)", num_songs_added, ec);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -156,14 +156,10 @@ bool configure(int argc, char **argv)
|
|||||||
if (vm.count("test-lyrics-fetchers"))
|
if (vm.count("test-lyrics-fetchers"))
|
||||||
{
|
{
|
||||||
std::vector<std::tuple<std::string, std::string, std::string>> fetcher_data = {
|
std::vector<std::tuple<std::string, std::string, std::string>> fetcher_data = {
|
||||||
std::make_tuple("azlyrics", "rihanna", "umbrella"),
|
|
||||||
std::make_tuple("genius", "rihanna", "umbrella"),
|
std::make_tuple("genius", "rihanna", "umbrella"),
|
||||||
std::make_tuple("musixmatch", "rihanna", "umbrella"),
|
|
||||||
std::make_tuple("sing365", "rihanna", "umbrella"),
|
|
||||||
std::make_tuple("metrolyrics", "rihanna", "umbrella"),
|
|
||||||
std::make_tuple("justsomelyrics", "rihanna", "umbrella"),
|
std::make_tuple("justsomelyrics", "rihanna", "umbrella"),
|
||||||
std::make_tuple("jahlyrics", "sean kingston", "dry your eyes"),
|
std::make_tuple("jahlyrics", "sean kingston", "dry your eyes"),
|
||||||
std::make_tuple("plyrics", "offspring", "genocide"),
|
std::make_tuple("plyrics", "rihanna", "umbrella"),
|
||||||
std::make_tuple("tekstowo", "rihanna", "umbrella"),
|
std::make_tuple("tekstowo", "rihanna", "umbrella"),
|
||||||
std::make_tuple("zeneszoveg", "rihanna", "umbrella"),
|
std::make_tuple("zeneszoveg", "rihanna", "umbrella"),
|
||||||
};
|
};
|
||||||
@@ -175,7 +171,7 @@ bool configure(int argc, char **argv)
|
|||||||
<< fetcher->name()
|
<< fetcher->name()
|
||||||
<< " : "
|
<< " : "
|
||||||
<< std::flush;
|
<< std::flush;
|
||||||
auto result = fetcher->fetch(std::get<1>(data), std::get<2>(data));
|
auto result = fetcher->fetch(std::get<1>(data), std::get<2>(data), {});
|
||||||
std::cout << (result.first ? "ok" : "failed")
|
std::cout << (result.first ? "ok" : "failed")
|
||||||
<< "\n";
|
<< "\n";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ CURLcode Curl::perform(std::string &data, const std::string &URL, const std::str
|
|||||||
curl_easy_setopt(c, CURLOPT_WRITEDATA, &data);
|
curl_easy_setopt(c, CURLOPT_WRITEDATA, &data);
|
||||||
curl_easy_setopt(c, CURLOPT_CONNECTTIMEOUT, timeout);
|
curl_easy_setopt(c, CURLOPT_CONNECTTIMEOUT, timeout);
|
||||||
curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1);
|
curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1);
|
||||||
curl_easy_setopt(c, CURLOPT_USERAGENT, "ncmpcpp " VERSION);
|
|
||||||
if (follow_redirect)
|
if (follow_redirect)
|
||||||
curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L);
|
curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
if (!referer.empty())
|
if (!referer.empty())
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ void verifyFormats(const NC::FormattedColor::Formats &formats)
|
|||||||
if (fmt == NC::Format::NoBold
|
if (fmt == NC::Format::NoBold
|
||||||
|| fmt == NC::Format::NoUnderline
|
|| fmt == NC::Format::NoUnderline
|
||||||
|| fmt == NC::Format::NoReverse
|
|| fmt == NC::Format::NoReverse
|
||||||
|| fmt == NC::Format::NoAltCharset)
|
|| fmt == NC::Format::NoAltCharset
|
||||||
|
|| fmt == NC::Format::NoItalic)
|
||||||
throw std::logic_error("FormattedColor can't hold disabling formats");
|
throw std::logic_error("FormattedColor can't hold disabling formats");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,6 +72,9 @@ std::istream &NC::operator>>(std::istream &is, NC::FormattedColor &fc)
|
|||||||
case 'a':
|
case 'a':
|
||||||
formats.push_back(NC::Format::AltCharset);
|
formats.push_back(NC::Format::AltCharset);
|
||||||
break;
|
break;
|
||||||
|
case 'i':
|
||||||
|
formats.push_back(NC::Format::Italic);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
is.setstate(std::ios::failbit);
|
is.setstate(std::ios::failbit);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "utility/readline.h"
|
#include "utility/readline.h"
|
||||||
@@ -198,6 +199,8 @@ int add_base()
|
|||||||
int color_pair_counter;
|
int color_pair_counter;
|
||||||
std::vector<int> color_pair_map;
|
std::vector<int> color_pair_map;
|
||||||
|
|
||||||
|
termios orig_termios;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace NC {
|
namespace NC {
|
||||||
@@ -346,6 +349,10 @@ NC::Format reverseFormat(NC::Format fmt)
|
|||||||
return NC::Format::NoAltCharset;
|
return NC::Format::NoAltCharset;
|
||||||
case NC::Format::NoAltCharset:
|
case NC::Format::NoAltCharset:
|
||||||
return NC::Format::AltCharset;
|
return NC::Format::AltCharset;
|
||||||
|
case NC::Format::Italic:
|
||||||
|
return NC::Format::NoItalic;
|
||||||
|
case NC::Format::NoItalic:
|
||||||
|
return NC::Format::Italic;
|
||||||
}
|
}
|
||||||
// Unreachable, silence GCC.
|
// Unreachable, silence GCC.
|
||||||
return fmt;
|
return fmt;
|
||||||
@@ -396,6 +403,7 @@ int colorCount()
|
|||||||
|
|
||||||
void initScreen(bool enable_colors, bool enable_mouse)
|
void initScreen(bool enable_colors, bool enable_mouse)
|
||||||
{
|
{
|
||||||
|
tcgetattr(STDIN_FILENO, &orig_termios);
|
||||||
initscr();
|
initscr();
|
||||||
if (has_colors() && enable_colors)
|
if (has_colors() && enable_colors)
|
||||||
{
|
{
|
||||||
@@ -477,6 +485,7 @@ void destroyScreen()
|
|||||||
Mouse::disable();
|
Mouse::disable();
|
||||||
curs_set(1);
|
curs_set(1);
|
||||||
endwin();
|
endwin();
|
||||||
|
tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
|
||||||
}
|
}
|
||||||
|
|
||||||
Window::Window(size_t startx, size_t starty, size_t width, size_t height,
|
Window::Window(size_t startx, size_t starty, size_t width, size_t height,
|
||||||
@@ -494,14 +503,9 @@ Window::Window(size_t startx, size_t starty, size_t width, size_t height,
|
|||||||
m_bold_counter(0),
|
m_bold_counter(0),
|
||||||
m_underline_counter(0),
|
m_underline_counter(0),
|
||||||
m_reverse_counter(0),
|
m_reverse_counter(0),
|
||||||
m_alt_charset_counter(0)
|
m_alt_charset_counter(0),
|
||||||
|
m_italic_counter(0)
|
||||||
{
|
{
|
||||||
if (m_start_x > size_t(COLS)
|
|
||||||
|| m_start_y > size_t(LINES)
|
|
||||||
|| m_width+m_start_x > size_t(COLS)
|
|
||||||
|| m_height+m_start_y > size_t(LINES))
|
|
||||||
throw std::logic_error("constructed window doesn't fit into the terminal");
|
|
||||||
|
|
||||||
if (m_border)
|
if (m_border)
|
||||||
{
|
{
|
||||||
++m_start_x;
|
++m_start_x;
|
||||||
@@ -542,6 +546,7 @@ Window::Window(const Window &rhs)
|
|||||||
, m_underline_counter(rhs.m_underline_counter)
|
, m_underline_counter(rhs.m_underline_counter)
|
||||||
, m_reverse_counter(rhs.m_reverse_counter)
|
, m_reverse_counter(rhs.m_reverse_counter)
|
||||||
, m_alt_charset_counter(rhs.m_alt_charset_counter)
|
, m_alt_charset_counter(rhs.m_alt_charset_counter)
|
||||||
|
, m_italic_counter(rhs.m_italic_counter)
|
||||||
{
|
{
|
||||||
setColor(m_color);
|
setColor(m_color);
|
||||||
}
|
}
|
||||||
@@ -566,6 +571,7 @@ Window::Window(Window &&rhs)
|
|||||||
, m_underline_counter(rhs.m_underline_counter)
|
, m_underline_counter(rhs.m_underline_counter)
|
||||||
, m_reverse_counter(rhs.m_reverse_counter)
|
, m_reverse_counter(rhs.m_reverse_counter)
|
||||||
, m_alt_charset_counter(rhs.m_alt_charset_counter)
|
, m_alt_charset_counter(rhs.m_alt_charset_counter)
|
||||||
|
, m_italic_counter(rhs.m_italic_counter)
|
||||||
{
|
{
|
||||||
rhs.m_window = nullptr;
|
rhs.m_window = nullptr;
|
||||||
}
|
}
|
||||||
@@ -591,6 +597,7 @@ Window &Window::operator=(Window rhs)
|
|||||||
std::swap(m_underline_counter, rhs.m_underline_counter);
|
std::swap(m_underline_counter, rhs.m_underline_counter);
|
||||||
std::swap(m_reverse_counter, rhs.m_reverse_counter);
|
std::swap(m_reverse_counter, rhs.m_reverse_counter);
|
||||||
std::swap(m_alt_charset_counter, rhs.m_alt_charset_counter);
|
std::swap(m_alt_charset_counter, rhs.m_alt_charset_counter);
|
||||||
|
std::swap(m_italic_counter, rhs.m_italic_counter);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -682,13 +689,16 @@ void Window::moveTo(size_t new_x, size_t new_y)
|
|||||||
|
|
||||||
void Window::adjustDimensions(size_t width, size_t height)
|
void Window::adjustDimensions(size_t width, size_t height)
|
||||||
{
|
{
|
||||||
|
// NOTE: when dimensions get small, integer overflow will cause calls to
|
||||||
|
// `Menu<T>::refresh()` to run for a very long time.
|
||||||
|
|
||||||
if (m_border)
|
if (m_border)
|
||||||
{
|
{
|
||||||
width -= 2;
|
width -= width >= 2 ? 2 : 0;
|
||||||
height -= 2;
|
height -= height >= 2 ? 2 : 0;
|
||||||
}
|
}
|
||||||
if (!m_title.empty())
|
if (!m_title.empty())
|
||||||
height -= 2;
|
height -= height >= 2 ? 2 : 0;
|
||||||
m_height = height;
|
m_height = height;
|
||||||
m_width = width;
|
m_width = width;
|
||||||
}
|
}
|
||||||
@@ -777,6 +787,11 @@ void Window::altCharset(bool altcharset_state) const
|
|||||||
(altcharset_state ? wattron : wattroff)(m_window, A_ALTCHARSET);
|
(altcharset_state ? wattron : wattroff)(m_window, A_ALTCHARSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::italic(bool italic_state) const
|
||||||
|
{
|
||||||
|
(italic_state ? wattron : wattroff)(m_window, A_ITALIC);
|
||||||
|
}
|
||||||
|
|
||||||
void Window::setTimeout(int timeout)
|
void Window::setTimeout(int timeout)
|
||||||
{
|
{
|
||||||
m_window_timeout = timeout;
|
m_window_timeout = timeout;
|
||||||
@@ -1410,6 +1425,12 @@ Window &Window::operator<<(Format format)
|
|||||||
case Format::NoAltCharset:
|
case Format::NoAltCharset:
|
||||||
decrease_flag(*this, m_alt_charset_counter, &Window::altCharset);
|
decrease_flag(*this, m_alt_charset_counter, &Window::altCharset);
|
||||||
break;
|
break;
|
||||||
|
case Format::Italic:
|
||||||
|
increase_flag(*this, m_italic_counter, &Window::italic);
|
||||||
|
break;
|
||||||
|
case Format::NoItalic:
|
||||||
|
decrease_flag(*this, m_italic_counter, &Window::italic);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "curses.h"
|
#include "curses.h"
|
||||||
#include "gcc.h"
|
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -200,7 +199,8 @@ enum class Format {
|
|||||||
Bold, NoBold,
|
Bold, NoBold,
|
||||||
Underline, NoUnderline,
|
Underline, NoUnderline,
|
||||||
Reverse, NoReverse,
|
Reverse, NoReverse,
|
||||||
AltCharset, NoAltCharset
|
AltCharset, NoAltCharset,
|
||||||
|
Italic, NoItalic
|
||||||
};
|
};
|
||||||
|
|
||||||
NC::Format reverseFormat(NC::Format fmt);
|
NC::Format reverseFormat(NC::Format fmt);
|
||||||
@@ -531,6 +531,11 @@ private:
|
|||||||
/// @param altcharset_state state of altcharset attribute
|
/// @param altcharset_state state of altcharset attribute
|
||||||
///
|
///
|
||||||
void altCharset(bool altcharset_state) const;
|
void altCharset(bool altcharset_state) const;
|
||||||
|
|
||||||
|
/// Sets state of italic attribute (internal use only)
|
||||||
|
/// @param italic_state state of italic attribute
|
||||||
|
///
|
||||||
|
void italic(bool italic_state) const;
|
||||||
|
|
||||||
/// pointer to helper function used by getString()
|
/// pointer to helper function used by getString()
|
||||||
/// @see getString()
|
/// @see getString()
|
||||||
@@ -562,6 +567,7 @@ private:
|
|||||||
int m_underline_counter;
|
int m_underline_counter;
|
||||||
int m_reverse_counter;
|
int m_reverse_counter;
|
||||||
int m_alt_charset_counter;
|
int m_alt_charset_counter;
|
||||||
|
int m_italic_counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ const wchar_t *toColumnName(char c)
|
|||||||
return L"Filename";
|
return L"Filename";
|
||||||
case 'D':
|
case 'D':
|
||||||
return L"Directory";
|
return L"Directory";
|
||||||
|
case 'F':
|
||||||
|
return L"Filepath";
|
||||||
case 'a':
|
case 'a':
|
||||||
return L"Artist";
|
return L"Artist";
|
||||||
case 'A':
|
case 'A':
|
||||||
@@ -92,9 +94,9 @@ void setProperties(NC::Menu<T> &menu, const MPD::Song &s, const SongList &list,
|
|||||||
{
|
{
|
||||||
// Draw a separator when the next album is different than the current
|
// Draw a separator when the next album is different than the current
|
||||||
// one. In case there are two albums with the same name, but a different
|
// one. In case there are two albums with the same name, but a different
|
||||||
// artist, compare also artists.
|
// album artist, compare also album artists.
|
||||||
separate_albums = next->song()->getAlbum() != s.getAlbum()
|
separate_albums = next->song()->getAlbum() != s.getAlbum()
|
||||||
|| next->song()->getArtist() != s.getArtist();
|
|| next->song()->getAlbumArtist() != s.getAlbumArtist();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,6 +192,8 @@ expressions<CharT> parseBracket(const string<CharT> &s,
|
|||||||
result.push_back(NC::Format::AltCharset);
|
result.push_back(NC::Format::AltCharset);
|
||||||
else if (flags & Format::Flags::Format && *it == 'r')
|
else if (flags & Format::Flags::Format && *it == 'r')
|
||||||
result.push_back(NC::Format::Reverse);
|
result.push_back(NC::Format::Reverse);
|
||||||
|
else if (flags & Format::Flags::Format && *it == 'i')
|
||||||
|
result.push_back(NC::Format::Italic);
|
||||||
else if (flags & Format::Flags::Format && *it == '/')
|
else if (flags & Format::Flags::Format && *it == '/')
|
||||||
{
|
{
|
||||||
++it;
|
++it;
|
||||||
@@ -204,6 +206,8 @@ expressions<CharT> parseBracket(const string<CharT> &s,
|
|||||||
result.push_back(NC::Format::NoAltCharset);
|
result.push_back(NC::Format::NoAltCharset);
|
||||||
else if (*it == 'r')
|
else if (*it == 'r')
|
||||||
result.push_back(NC::Format::NoReverse);
|
result.push_back(NC::Format::NoReverse);
|
||||||
|
else if (*it == 'i')
|
||||||
|
result.push_back(NC::Format::NoItalic);
|
||||||
else
|
else
|
||||||
throwError(s, it, invalidCharacter(*it));
|
throwError(s, it, invalidCharacter(*it));
|
||||||
}
|
}
|
||||||
|
|||||||
29
src/gcc.h
29
src/gcc.h
@@ -1,29 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008-2021 by Andrzej Rybczak *
|
|
||||||
* andrzej@rybczak.net *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License as published by *
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
|
||||||
* (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This program is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
||||||
* GNU General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && __GNUC__ >= 3
|
|
||||||
# define GNUC_NORETURN __attribute__((noreturn))
|
|
||||||
# define GNUC_UNUSED __attribute__((unused))
|
|
||||||
# define GNUC_PRINTF(a, b) __attribute__((format(printf, a, b)))
|
|
||||||
#else
|
|
||||||
# define GNUC_NORETURN
|
|
||||||
# define GNUC_UNUSED
|
|
||||||
# define GNUC_PRINTF(a, b)
|
|
||||||
#endif
|
|
||||||
@@ -46,8 +46,8 @@ SongIterator makeSongIterator(IteratorT it)
|
|||||||
> Extractor;
|
> Extractor;
|
||||||
static_assert(
|
static_assert(
|
||||||
std::is_convertible<
|
std::is_convertible<
|
||||||
typename std::result_of<Extractor(typename IteratorT::reference)>::type,
|
std::invoke_result_t<Extractor, typename IteratorT::reference>,
|
||||||
SongProperties &
|
SongProperties &
|
||||||
>::value, "invalid result type of SongPropertiesExtractor");
|
>::value, "invalid result type of SongPropertiesExtractor");
|
||||||
return SongIterator(boost::make_transform_iterator(it, Extractor{}));
|
return SongIterator(boost::make_transform_iterator(it, Extractor{}));
|
||||||
}
|
}
|
||||||
@@ -60,8 +60,8 @@ ConstSongIterator makeConstSongIterator(ConstIteratorT it)
|
|||||||
> Extractor;
|
> Extractor;
|
||||||
static_assert(
|
static_assert(
|
||||||
std::is_convertible<
|
std::is_convertible<
|
||||||
typename std::result_of<Extractor(typename ConstIteratorT::reference)>::type,
|
std::invoke_result_t<Extractor, typename ConstIteratorT::reference>,
|
||||||
const SongProperties &
|
const SongProperties &
|
||||||
>::value, "invalid result type of SongPropertiesExtractor");
|
>::value, "invalid result type of SongPropertiesExtractor");
|
||||||
return ConstSongIterator(boost::make_transform_iterator(it, Extractor{}));
|
return ConstSongIterator(boost::make_transform_iterator(it, Extractor{}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include <boost/tuple/tuple.hpp>
|
#include <boost/tuple/tuple.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "enums.h"
|
#include "enums.h"
|
||||||
#include "gcc.h"
|
|
||||||
#include "screens/screen.h"
|
#include "screens/screen.h"
|
||||||
#include "song.h"
|
#include "song.h"
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "curl_handle.h"
|
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -29,8 +28,15 @@
|
|||||||
#include <boost/algorithm/string/trim.hpp>
|
#include <boost/algorithm/string/trim.hpp>
|
||||||
#include <boost/regex.hpp>
|
#include <boost/regex.hpp>
|
||||||
|
|
||||||
|
#ifdef HAVE_TAGLIB_H
|
||||||
|
#include <fileref.h>
|
||||||
|
#include <tpropertymap.h>
|
||||||
|
#endif // HAVE_TAGLIB_H
|
||||||
|
|
||||||
#include "charset.h"
|
#include "charset.h"
|
||||||
|
#include "curl_handle.h"
|
||||||
#include "lyrics_fetcher.h"
|
#include "lyrics_fetcher.h"
|
||||||
|
#include "settings.h"
|
||||||
#include "utility/html.h"
|
#include "utility/html.h"
|
||||||
#include "utility/string.h"
|
#include "utility/string.h"
|
||||||
|
|
||||||
@@ -38,16 +44,8 @@ std::istream &operator>>(std::istream &is, LyricsFetcher_ &fetcher)
|
|||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
is >> s;
|
is >> s;
|
||||||
if (s == "azlyrics")
|
if (s == "genius")
|
||||||
fetcher = std::make_unique<AzLyricsFetcher>();
|
|
||||||
else if (s == "genius")
|
|
||||||
fetcher = std::make_unique<GeniusFetcher>();
|
fetcher = std::make_unique<GeniusFetcher>();
|
||||||
else if (s == "musixmatch")
|
|
||||||
fetcher = std::make_unique<MusixmatchFetcher>();
|
|
||||||
else if (s == "sing365")
|
|
||||||
fetcher = std::make_unique<Sing365Fetcher>();
|
|
||||||
else if (s == "metrolyrics")
|
|
||||||
fetcher = std::make_unique<MetrolyricsFetcher>();
|
|
||||||
else if (s == "justsomelyrics")
|
else if (s == "justsomelyrics")
|
||||||
fetcher = std::make_unique<JustSomeLyricsFetcher>();
|
fetcher = std::make_unique<JustSomeLyricsFetcher>();
|
||||||
else if (s == "jahlyrics")
|
else if (s == "jahlyrics")
|
||||||
@@ -60,6 +58,10 @@ std::istream &operator>>(std::istream &is, LyricsFetcher_ &fetcher)
|
|||||||
fetcher = std::make_unique<ZeneszovegFetcher>();
|
fetcher = std::make_unique<ZeneszovegFetcher>();
|
||||||
else if (s == "internet")
|
else if (s == "internet")
|
||||||
fetcher = std::make_unique<InternetLyricsFetcher>();
|
fetcher = std::make_unique<InternetLyricsFetcher>();
|
||||||
|
#ifdef HAVE_TAGLIB_H
|
||||||
|
else if (s == "tags")
|
||||||
|
fetcher = std::make_unique<TagsLyricsFetcher>();
|
||||||
|
#endif // HAVE_TAGLIB_H
|
||||||
else
|
else
|
||||||
is.setstate(std::ios::failbit);
|
is.setstate(std::ios::failbit);
|
||||||
return is;
|
return is;
|
||||||
@@ -68,7 +70,8 @@ std::istream &operator>>(std::istream &is, LyricsFetcher_ &fetcher)
|
|||||||
const char LyricsFetcher::msgNotFound[] = "Not found";
|
const char LyricsFetcher::msgNotFound[] = "Not found";
|
||||||
|
|
||||||
LyricsFetcher::Result LyricsFetcher::fetch(const std::string &artist,
|
LyricsFetcher::Result LyricsFetcher::fetch(const std::string &artist,
|
||||||
const std::string &title)
|
const std::string &title,
|
||||||
|
[[maybe_unused]] const MPD::Song &song)
|
||||||
{
|
{
|
||||||
Result result;
|
Result result;
|
||||||
result.first = false;
|
result.first = false;
|
||||||
@@ -76,7 +79,7 @@ LyricsFetcher::Result LyricsFetcher::fetch(const std::string &artist,
|
|||||||
std::string url = urlTemplate();
|
std::string url = urlTemplate();
|
||||||
boost::replace_all(url, "%artist%", Curl::escape(artist));
|
boost::replace_all(url, "%artist%", Curl::escape(artist));
|
||||||
boost::replace_all(url, "%title%", Curl::escape(title));
|
boost::replace_all(url, "%title%", Curl::escape(title));
|
||||||
|
|
||||||
std::string data;
|
std::string data;
|
||||||
CURLcode code = Curl::perform(data, url, "", true);
|
CURLcode code = Curl::perform(data, url, "", true);
|
||||||
|
|
||||||
@@ -88,9 +91,11 @@ LyricsFetcher::Result LyricsFetcher::fetch(const std::string &artist,
|
|||||||
|
|
||||||
auto lyrics = getContent(regex(), data);
|
auto lyrics = getContent(regex(), data);
|
||||||
|
|
||||||
|
//std::cerr << "URL: " << url << "\n";
|
||||||
|
//std::cerr << "Data: " << data << "\n";
|
||||||
|
|
||||||
if (lyrics.empty() || notLyrics(data))
|
if (lyrics.empty() || notLyrics(data))
|
||||||
{
|
{
|
||||||
//std::cerr << "Data: " << data << "\n";
|
|
||||||
//std::cerr << "Empty: " << lyrics.empty() << "\n";
|
//std::cerr << "Empty: " << lyrics.empty() << "\n";
|
||||||
//std::cerr << "Not Lyrics: " << notLyrics(data) << "\n";
|
//std::cerr << "Not Lyrics: " << notLyrics(data) << "\n";
|
||||||
result.second = msgNotFound;
|
result.second = msgNotFound;
|
||||||
@@ -137,12 +142,14 @@ void LyricsFetcher::postProcess(std::string &data) const
|
|||||||
stripHtmlTags(data);
|
stripHtmlTags(data);
|
||||||
// Remove indentation from each line and collapse multiple newlines into one.
|
// Remove indentation from each line and collapse multiple newlines into one.
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
boost::split(lines, data, boost::is_any_of("\n"));
|
boost::split(lines, data, boost::is_any_of("\r\n"));
|
||||||
for (auto &line : lines)
|
for (auto &line : lines)
|
||||||
boost::trim(line);
|
boost::trim(line);
|
||||||
std::unique(lines.begin(), lines.end(), [](std::string &a, std::string &b) {
|
auto last = std::unique(
|
||||||
return a.empty() && b.empty();
|
lines.begin(),
|
||||||
});
|
lines.end(),
|
||||||
|
[](std::string &a, std::string &b) { return a.empty() && b.empty(); });
|
||||||
|
lines.erase(last, lines.end());
|
||||||
data = boost::algorithm::join(lines, "\n");
|
data = boost::algorithm::join(lines, "\n");
|
||||||
boost::trim(data);
|
boost::trim(data);
|
||||||
}
|
}
|
||||||
@@ -150,7 +157,8 @@ void LyricsFetcher::postProcess(std::string &data) const
|
|||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
LyricsFetcher::Result GoogleLyricsFetcher::fetch(const std::string &artist,
|
LyricsFetcher::Result GoogleLyricsFetcher::fetch(const std::string &artist,
|
||||||
const std::string &title)
|
const std::string &title,
|
||||||
|
const MPD::Song &song)
|
||||||
{
|
{
|
||||||
Result result;
|
Result result;
|
||||||
result.first = false;
|
result.first = false;
|
||||||
@@ -192,7 +200,7 @@ LyricsFetcher::Result GoogleLyricsFetcher::fetch(const std::string &artist,
|
|||||||
data = unescapeHtmlUtf8(urls[0]);
|
data = unescapeHtmlUtf8(urls[0]);
|
||||||
|
|
||||||
URL = data.c_str();
|
URL = data.c_str();
|
||||||
return LyricsFetcher::fetch("", "");
|
return LyricsFetcher::fetch("", "", song);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GoogleLyricsFetcher::isURLOk(const std::string &url)
|
bool GoogleLyricsFetcher::isURLOk(const std::string &url)
|
||||||
@@ -202,18 +210,11 @@ bool GoogleLyricsFetcher::isURLOk(const std::string &url)
|
|||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
bool MetrolyricsFetcher::isURLOk(const std::string &url)
|
|
||||||
{
|
|
||||||
// it sometimes return link to sitemap.xml, which is huge so we need to discard it
|
|
||||||
return GoogleLyricsFetcher::isURLOk(url) && url.find("sitemap") == std::string::npos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**********************************************************************/
|
|
||||||
|
|
||||||
LyricsFetcher::Result InternetLyricsFetcher::fetch(const std::string &artist,
|
LyricsFetcher::Result InternetLyricsFetcher::fetch(const std::string &artist,
|
||||||
const std::string &title)
|
const std::string &title,
|
||||||
|
const MPD::Song &song)
|
||||||
{
|
{
|
||||||
GoogleLyricsFetcher::fetch(artist, title);
|
GoogleLyricsFetcher::fetch(artist, title, song);
|
||||||
LyricsFetcher::Result result;
|
LyricsFetcher::Result result;
|
||||||
result.first = false;
|
result.first = false;
|
||||||
result.second = "The following site may contain lyrics for this song: ";
|
result.second = "The following site may contain lyrics for this song: ";
|
||||||
@@ -226,3 +227,42 @@ bool InternetLyricsFetcher::isURLOk(const std::string &url)
|
|||||||
URL = url;
|
URL = url;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_TAGLIB_H
|
||||||
|
LyricsFetcher::Result TagsLyricsFetcher::fetch([[maybe_unused]] const std::string &artist,
|
||||||
|
[[maybe_unused]] const std::string &title,
|
||||||
|
const MPD::Song &song)
|
||||||
|
{
|
||||||
|
LyricsFetcher::Result result;
|
||||||
|
result.first = false;
|
||||||
|
|
||||||
|
std::string path;
|
||||||
|
if (song.isFromDatabase())
|
||||||
|
path += Config.mpd_music_dir;
|
||||||
|
path += song.getURI();
|
||||||
|
|
||||||
|
TagLib::FileRef f(path.c_str());
|
||||||
|
if (f.isNull())
|
||||||
|
{
|
||||||
|
result.second = "Could not open file";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::PropertyMap properties = f.file()->properties();
|
||||||
|
|
||||||
|
if (properties.contains("LYRICS"))
|
||||||
|
{
|
||||||
|
result.first = true;
|
||||||
|
result.second = properties["LYRICS"].toString("\n\n").to8Bit(true);
|
||||||
|
}
|
||||||
|
else if (properties.contains("UNSYNCEDLYRICS"))
|
||||||
|
{
|
||||||
|
result.first = true;
|
||||||
|
result.second = properties["UNSYNCEDLYRICS"].toString("\n\n").to8Bit(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result.second = "No lyrics in tags";
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif // HAVE_TAGLIB_H
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "song.h"
|
||||||
|
|
||||||
struct LyricsFetcher
|
struct LyricsFetcher
|
||||||
{
|
{
|
||||||
typedef std::pair<bool, std::string> Result;
|
typedef std::pair<bool, std::string> Result;
|
||||||
@@ -33,7 +35,7 @@ struct LyricsFetcher
|
|||||||
virtual ~LyricsFetcher() { }
|
virtual ~LyricsFetcher() { }
|
||||||
|
|
||||||
virtual const char *name() const = 0;
|
virtual const char *name() const = 0;
|
||||||
virtual Result fetch(const std::string &artist, const std::string &title);
|
virtual Result fetch(const std::string &artist, const std::string &title, const MPD::Song &song);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual const char *urlTemplate() const = 0;
|
virtual const char *urlTemplate() const = 0;
|
||||||
@@ -57,7 +59,7 @@ std::istream &operator>>(std::istream &is, LyricsFetcher_ &fetcher);
|
|||||||
|
|
||||||
struct GoogleLyricsFetcher : public LyricsFetcher
|
struct GoogleLyricsFetcher : public LyricsFetcher
|
||||||
{
|
{
|
||||||
virtual Result fetch(const std::string &artist, const std::string &title);
|
virtual Result fetch(const std::string &artist, const std::string &title, const MPD::Song &song);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual const char *urlTemplate() const { return URL; }
|
virtual const char *urlTemplate() const { return URL; }
|
||||||
@@ -69,34 +71,6 @@ private:
|
|||||||
const char *URL;
|
const char *URL;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MusixmatchFetcher : public GoogleLyricsFetcher
|
|
||||||
{
|
|
||||||
virtual const char *name() const override { return "musixmatch.com"; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual const char *regex() const override { return "<span class=\"lyrics__content__.*?>(.*?)</span>"; }
|
|
||||||
|
|
||||||
virtual void postProcess(std::string &) const override { }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MetrolyricsFetcher : public GoogleLyricsFetcher
|
|
||||||
{
|
|
||||||
virtual const char *name() const override { return "metrolyrics.com"; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual const char *regex() const override { return "<div class=\"lyrics-body\">(.*?)<!--WIDGET.*?<!-- Second Section -->(.*?)<!--WIDGET.*?<!-- Third Section -->(.*?)</div>"; }
|
|
||||||
|
|
||||||
virtual bool isURLOk(const std::string &url) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Sing365Fetcher : public GoogleLyricsFetcher
|
|
||||||
{
|
|
||||||
virtual const char *name() const override { return "lyrics007.com"; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual const char *regex() const override { return "<div class=\"lyrics\">(.*?)</div>"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct JustSomeLyricsFetcher : public GoogleLyricsFetcher
|
struct JustSomeLyricsFetcher : public GoogleLyricsFetcher
|
||||||
{
|
{
|
||||||
virtual const char *name() const override { return "justsomelyrics.com"; }
|
virtual const char *name() const override { return "justsomelyrics.com"; }
|
||||||
@@ -105,20 +79,12 @@ protected:
|
|||||||
virtual const char *regex() const override { return "<div class=\"content.*?</div>(.*?)See also"; }
|
virtual const char *regex() const override { return "<div class=\"content.*?</div>(.*?)See also"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AzLyricsFetcher : public GoogleLyricsFetcher
|
|
||||||
{
|
|
||||||
virtual const char *name() const override { return "azlyrics.com"; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual const char *regex() const override { return "<div class=\"lyricsh\">.*?</h2>.*<div>(.*?)</div>"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GeniusFetcher : public GoogleLyricsFetcher
|
struct GeniusFetcher : public GoogleLyricsFetcher
|
||||||
{
|
{
|
||||||
virtual const char *name() const override { return "genius.com"; }
|
virtual const char *name() const override { return "genius.com"; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual const char *regex() const override { return "<div class=\"[Ll]yrics.*?>(.*?)</div>"; }
|
virtual const char *regex() const override { return "<div data-lyrics-container.*?>(.*?)</div>"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JahLyricsFetcher : public GoogleLyricsFetcher
|
struct JahLyricsFetcher : public GoogleLyricsFetcher
|
||||||
@@ -142,7 +108,7 @@ struct TekstowoFetcher : public GoogleLyricsFetcher
|
|||||||
virtual const char *name() const override { return "tekstowo.pl"; }
|
virtual const char *name() const override { return "tekstowo.pl"; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual const char *regex() const override { return "<div class=\"song-text\".*?>.*?</h2>(.*?)<a"; }
|
virtual const char *regex() const override { return "<div class=\"inner-text\">(.*?)</div>"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ZeneszovegFetcher : public GoogleLyricsFetcher
|
struct ZeneszovegFetcher : public GoogleLyricsFetcher
|
||||||
@@ -150,13 +116,13 @@ struct ZeneszovegFetcher : public GoogleLyricsFetcher
|
|||||||
virtual const char *name() const override { return "zeneszoveg.hu"; }
|
virtual const char *name() const override { return "zeneszoveg.hu"; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual const char *regex() const override { return "<div class=\"lyrics-plain-text.*?\">(.*?)</div>"; }
|
virtual const char *regex() const override { return "<div class=\"lyrics-plain-text trans_original\">(.*?)</div>"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InternetLyricsFetcher : public GoogleLyricsFetcher
|
struct InternetLyricsFetcher : public GoogleLyricsFetcher
|
||||||
{
|
{
|
||||||
virtual const char *name() const override { return "the Internet"; }
|
virtual const char *name() const override { return "the Internet"; }
|
||||||
virtual Result fetch(const std::string &artist, const std::string &title) override;
|
virtual Result fetch(const std::string &artist, const std::string &title, const MPD::Song &song) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual const char *siteKeyword() const override { return nullptr; }
|
virtual const char *siteKeyword() const override { return nullptr; }
|
||||||
@@ -168,4 +134,16 @@ private:
|
|||||||
std::string URL;
|
std::string URL;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef HAVE_TAGLIB_H
|
||||||
|
struct TagsLyricsFetcher : public LyricsFetcher
|
||||||
|
{
|
||||||
|
virtual const char *name() const override { return "tags"; }
|
||||||
|
virtual Result fetch(const std::string &artist, const std::string &title, const MPD::Song &song) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual const char *urlTemplate() const override { return ""; }
|
||||||
|
virtual const char *regex() const override { return ""; }
|
||||||
|
};
|
||||||
|
#endif // HAVE_TAGLIB_H
|
||||||
|
|
||||||
#endif // NCMPCPP_LYRICS_FETCHER_H
|
#endif // NCMPCPP_LYRICS_FETCHER_H
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ unsigned Connection::Version() const
|
|||||||
void Connection::SetHostname(const std::string &host)
|
void Connection::SetHostname(const std::string &host)
|
||||||
{
|
{
|
||||||
size_t at = host.find("@");
|
size_t at = host.find("@");
|
||||||
if (at != std::string::npos)
|
if (at != 0 && at != std::string::npos)
|
||||||
{
|
{
|
||||||
m_password = host.substr(0, at);
|
m_password = host.substr(0, at);
|
||||||
m_host = host.substr(at+1);
|
m_host = host.substr(at+1);
|
||||||
|
|||||||
@@ -353,8 +353,14 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename ObjectT>
|
template <typename ObjectT>
|
||||||
struct Iterator: std::iterator<std::input_iterator_tag, ObjectT>
|
struct Iterator
|
||||||
{
|
{
|
||||||
|
using iterator_category = std::input_iterator_tag;
|
||||||
|
using value_type = ObjectT;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using pointer = ObjectT *;
|
||||||
|
using reference = ObjectT &;
|
||||||
|
|
||||||
// shared state of the iterator
|
// shared state of the iterator
|
||||||
struct State
|
struct State
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -121,7 +121,6 @@ int main(int argc, char **argv)
|
|||||||
Config.statusbar_visibility = 0;
|
Config.statusbar_visibility = 0;
|
||||||
|
|
||||||
Actions::setWindowsDimensions();
|
Actions::setWindowsDimensions();
|
||||||
Actions::validateScreenSize();
|
|
||||||
Actions::initializeScreens();
|
Actions::initializeScreens();
|
||||||
|
|
||||||
wHeader = new NC::Window(0, 0, COLS, Actions::HeaderHeight, "", Config.header_color, NC::Border());
|
wHeader = new NC::Window(0, 0, COLS, Actions::HeaderHeight, "", Config.header_color, NC::Border());
|
||||||
@@ -220,7 +219,10 @@ int main(int argc, char **argv)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto k = Bindings.get(input);
|
auto k = Bindings.get(input);
|
||||||
std::any_of(k.first, k.second, std::bind(&Binding::execute, ph::_1));
|
[[maybe_unused]] bool executed = std::any_of(
|
||||||
|
k.first,
|
||||||
|
k.second,
|
||||||
|
std::bind(&Binding::execute, ph::_1));
|
||||||
}
|
}
|
||||||
catch (ConversionError &e)
|
catch (ConversionError &e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ boost::optional<std::string> downloadLyrics(
|
|||||||
<< NC::Format::NoBold << "... ";
|
<< NC::Format::NoBold << "... ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto result_ = fetcher_->fetch(s_artist, s_title);
|
auto result_ = fetcher_->fetch(s_artist, s_title, s);
|
||||||
if (result_.first == false)
|
if (result_.first == false)
|
||||||
{
|
{
|
||||||
if (shared_buffer)
|
if (shared_buffer)
|
||||||
@@ -361,6 +361,25 @@ void Lyrics::toggleFetcher()
|
|||||||
Statusbar::print("Using all lyrics fetchers");
|
Statusbar::print("Using all lyrics fetchers");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For HTTP(S) streams, fetchInBackground makes ncmpcpp crash: the lyrics_file
|
||||||
|
* gets set to the stream URL, which is too long, hence
|
||||||
|
* boost::filesystem::exists() fails.
|
||||||
|
* Possible solutions:
|
||||||
|
* - truncate the URL and use that as a filename. Problem: resulting filename
|
||||||
|
* might not be unique.
|
||||||
|
* - generate filenames in a different way for streams. Problem: what is a good
|
||||||
|
* method for this? Perhaps hashing -- but then the lyrics filenames are not
|
||||||
|
* informative.
|
||||||
|
* - skip fetching lyrics for streams with URLs that are too long. Problem:
|
||||||
|
* this leads to inconsistent behavior since lyrics will be fetched for some
|
||||||
|
* streams but not others.
|
||||||
|
* - avoid fetching lyrics for streams altogether.
|
||||||
|
*
|
||||||
|
* We choose the last solution, and ignore streams when fetching lyrics. This
|
||||||
|
* is because fetching lyrics for a stream may not be accurate (streams do not
|
||||||
|
* always provide the necessary metadata to look up lyrics reliably).
|
||||||
|
* Furthermore, fetching lyrics for streams is not necessarily desirable.
|
||||||
|
*/
|
||||||
void Lyrics::fetchInBackground(const MPD::Song &s, bool notify_)
|
void Lyrics::fetchInBackground(const MPD::Song &s, bool notify_)
|
||||||
{
|
{
|
||||||
auto consumer_impl = [this] {
|
auto consumer_impl = [this] {
|
||||||
@@ -377,7 +396,10 @@ void Lyrics::fetchInBackground(const MPD::Song &s, bool notify_)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
lyrics_file = lyricsFilename(consumer->songs.front().song());
|
lyrics_file = lyricsFilename(consumer->songs.front().song());
|
||||||
if (!boost::filesystem::exists(lyrics_file))
|
|
||||||
|
// For long filenames (e.g. http(s) stream URLs), boost::filesystem::exists() fails.
|
||||||
|
// This if condition is fine, because evaluation order is guaranteed.
|
||||||
|
if (!consumer->songs.front().song().isStream() && !boost::filesystem::exists(lyrics_file))
|
||||||
{
|
{
|
||||||
cs = consumer->songs.front();
|
cs = consumer->songs.front();
|
||||||
if (cs.notify())
|
if (cs.notify())
|
||||||
@@ -389,7 +411,7 @@ void Lyrics::fetchInBackground(const MPD::Song &s, bool notify_)
|
|||||||
}
|
}
|
||||||
consumer->songs.pop();
|
consumer->songs.pop();
|
||||||
}
|
}
|
||||||
if (!cs.song().empty())
|
if (!cs.song().empty() && !cs.song().isStream())
|
||||||
{
|
{
|
||||||
auto lyrics = downloadLyrics(cs.song(), nullptr, nullptr, m_fetcher);
|
auto lyrics = downloadLyrics(cs.song(), nullptr, nullptr, m_fetcher);
|
||||||
if (lyrics)
|
if (lyrics)
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ bool MoveToAlbum(NC::Menu<AlbumEntry> &albums, const std::string &primary_tag, c
|
|||||||
struct SortSongs {
|
struct SortSongs {
|
||||||
typedef NC::Menu<MPD::Song>::Item SongItem;
|
typedef NC::Menu<MPD::Song>::Item SongItem;
|
||||||
|
|
||||||
static const std::array<MPD::Song::GetFunction, 3> GetFuns;
|
static const std::array<MPD::Song::GetFunction, 4> GetFuns;
|
||||||
|
|
||||||
LocaleStringComparison m_cmp;
|
LocaleStringComparison m_cmp;
|
||||||
|
|
||||||
@@ -117,26 +117,16 @@ public:
|
|||||||
return ret < 0;
|
return ret < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort by track numbers.
|
|
||||||
try {
|
|
||||||
ret = boost::lexical_cast<int>(a.getTags(&MPD::Song::getTrackNumber))
|
|
||||||
- boost::lexical_cast<int>(b.getTags(&MPD::Song::getTrackNumber));
|
|
||||||
} catch (boost::bad_lexical_cast &) {
|
|
||||||
ret = a.getTrackNumber().compare(b.getTrackNumber());
|
|
||||||
}
|
|
||||||
if (ret != 0)
|
|
||||||
return ret < 0;
|
|
||||||
|
|
||||||
// If track numbers are equal, sort by the display format.
|
|
||||||
return Format::stringify<char>(Config.song_library_format, &a)
|
return Format::stringify<char>(Config.song_library_format, &a)
|
||||||
< Format::stringify<char>(Config.song_library_format, &b);
|
< Format::stringify<char>(Config.song_library_format, &b);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::array<MPD::Song::GetFunction, 3> SortSongs::GetFuns = {{
|
const std::array<MPD::Song::GetFunction, 4> SortSongs::GetFuns = {{
|
||||||
&MPD::Song::getDate,
|
&MPD::Song::getDate,
|
||||||
&MPD::Song::getAlbum,
|
&MPD::Song::getAlbum,
|
||||||
&MPD::Song::getDisc
|
&MPD::Song::getDisc,
|
||||||
|
&MPD::Song::getTrackNumber,
|
||||||
}};
|
}};
|
||||||
|
|
||||||
class SortAlbumEntries {
|
class SortAlbumEntries {
|
||||||
@@ -191,11 +181,16 @@ MediaLibrary::MediaLibrary()
|
|||||||
{
|
{
|
||||||
hasTwoColumns = 0;
|
hasTwoColumns = 0;
|
||||||
isAlbumOnly = 0;
|
isAlbumOnly = 0;
|
||||||
itsLeftColWidth = COLS/3-1;
|
|
||||||
itsMiddleColWidth = COLS/3;
|
size_t ra = Config.media_library_column_width_ratio_three[0];
|
||||||
|
size_t rb = Config.media_library_column_width_ratio_three[1];
|
||||||
|
size_t rc = Config.media_library_column_width_ratio_three[2];
|
||||||
|
|
||||||
|
itsLeftColWidth = COLS*ra/(ra+rb+rc)-1;
|
||||||
itsMiddleColStartX = itsLeftColWidth+1;
|
itsMiddleColStartX = itsLeftColWidth+1;
|
||||||
itsRightColWidth = COLS-COLS/3*2-1;
|
itsMiddleColWidth = COLS*rb/(ra+rb+rc);
|
||||||
itsRightColStartX = itsLeftColWidth+itsMiddleColWidth+2;
|
itsRightColStartX = itsMiddleColStartX+itsMiddleColWidth+1;
|
||||||
|
itsRightColWidth = COLS-itsLeftColWidth-itsMiddleColWidth-2;
|
||||||
|
|
||||||
Tags = NC::Menu<PrimaryTag>(0, MainStartY, itsLeftColWidth, MainHeight, Config.titles_visibility ? tagTypeToString(Config.media_lib_primary_tag) + "s" : "", Config.main_color, NC::Border());
|
Tags = NC::Menu<PrimaryTag>(0, MainStartY, itsLeftColWidth, MainHeight, Config.titles_visibility ? tagTypeToString(Config.media_lib_primary_tag) + "s" : "", Config.main_color, NC::Border());
|
||||||
setHighlightFixes(Tags);
|
setHighlightFixes(Tags);
|
||||||
@@ -240,18 +235,25 @@ void MediaLibrary::resize()
|
|||||||
getWindowResizeParams(x_offset, width);
|
getWindowResizeParams(x_offset, width);
|
||||||
if (!hasTwoColumns)
|
if (!hasTwoColumns)
|
||||||
{
|
{
|
||||||
|
size_t ra = Config.media_library_column_width_ratio_three[0];
|
||||||
|
size_t rb = Config.media_library_column_width_ratio_three[1];
|
||||||
|
size_t rc = Config.media_library_column_width_ratio_three[2];
|
||||||
|
|
||||||
itsLeftColStartX = x_offset;
|
itsLeftColStartX = x_offset;
|
||||||
itsLeftColWidth = width/3-1;
|
itsLeftColWidth = width*ra/(ra+rb+rc)-1;
|
||||||
itsMiddleColStartX = itsLeftColStartX+itsLeftColWidth+1;
|
itsMiddleColStartX = itsLeftColStartX+itsLeftColWidth+1;
|
||||||
itsMiddleColWidth = width/3;
|
itsMiddleColWidth = width*rb/(ra+rb+rc);
|
||||||
itsRightColStartX = itsMiddleColStartX+itsMiddleColWidth+1;
|
itsRightColStartX = itsMiddleColStartX+itsMiddleColWidth+1;
|
||||||
itsRightColWidth = width-width/3*2-1;
|
itsRightColWidth = width-itsLeftColWidth-itsMiddleColWidth-2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
size_t ra = Config.media_library_column_width_ratio_two[0];
|
||||||
|
size_t rb = Config.media_library_column_width_ratio_two[1];
|
||||||
|
|
||||||
itsMiddleColStartX = x_offset;
|
itsMiddleColStartX = x_offset;
|
||||||
itsMiddleColWidth = width/2;
|
itsMiddleColWidth = width*ra/(ra+rb);
|
||||||
itsRightColStartX = x_offset+itsMiddleColWidth+1;
|
itsRightColStartX = itsMiddleColStartX+itsMiddleColWidth+1;
|
||||||
itsRightColWidth = width-itsMiddleColWidth-1;
|
itsRightColWidth = width-itsMiddleColWidth-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,9 +336,9 @@ void MediaLibrary::update()
|
|||||||
for (const auto &album : albums)
|
for (const auto &album : albums)
|
||||||
{
|
{
|
||||||
auto entry = AlbumEntry(
|
auto entry = AlbumEntry(
|
||||||
Album(std::move(std::get<0>(album.first)),
|
Album(std::get<0>(album.first),
|
||||||
std::move(std::get<1>(album.first)),
|
std::get<1>(album.first),
|
||||||
std::move(std::get<2>(album.first)),
|
std::get<2>(album.first),
|
||||||
album.second));
|
album.second));
|
||||||
if (idx < Albums.size())
|
if (idx < Albums.size())
|
||||||
Albums[idx].value() = std::move(entry);
|
Albums[idx].value() = std::move(entry);
|
||||||
@@ -433,8 +435,8 @@ void MediaLibrary::update()
|
|||||||
{
|
{
|
||||||
auto entry = AlbumEntry(
|
auto entry = AlbumEntry(
|
||||||
Album(primary_tag,
|
Album(primary_tag,
|
||||||
std::move(std::get<0>(album.first)),
|
std::get<0>(album.first),
|
||||||
std::move(std::get<1>(album.first)),
|
std::get<1>(album.first),
|
||||||
album.second));
|
album.second));
|
||||||
if (idx < Albums.size())
|
if (idx < Albums.size())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -66,10 +66,14 @@ PlaylistEditor::PlaylistEditor()
|
|||||||
, m_window_timeout(Config.data_fetching_delay ? 250 : BaseScreen::defaultWindowTimeout)
|
, m_window_timeout(Config.data_fetching_delay ? 250 : BaseScreen::defaultWindowTimeout)
|
||||||
, m_fetching_delay(boost::posix_time::milliseconds(Config.data_fetching_delay ? 250 : -1))
|
, m_fetching_delay(boost::posix_time::milliseconds(Config.data_fetching_delay ? 250 : -1))
|
||||||
{
|
{
|
||||||
LeftColumnWidth = COLS/3-1;
|
size_t ra = Config.playlist_editor_column_width_ratio[0];
|
||||||
|
size_t rb = Config.playlist_editor_column_width_ratio[1];
|
||||||
|
|
||||||
|
LeftColumnWidth = COLS*ra/(ra+rb)-1;
|
||||||
RightColumnStartX = LeftColumnWidth+1;
|
RightColumnStartX = LeftColumnWidth+1;
|
||||||
RightColumnWidth = COLS-LeftColumnWidth-1;
|
RightColumnWidth = COLS-LeftColumnWidth-1;
|
||||||
|
|
||||||
|
|
||||||
Playlists = NC::Menu<MPD::Playlist>(0, MainStartY, LeftColumnWidth, MainHeight, Config.titles_visibility ? "Playlists" : "", Config.main_color, NC::Border());
|
Playlists = NC::Menu<MPD::Playlist>(0, MainStartY, LeftColumnWidth, MainHeight, Config.titles_visibility ? "Playlists" : "", Config.main_color, NC::Border());
|
||||||
setHighlightFixes(Playlists);
|
setHighlightFixes(Playlists);
|
||||||
Playlists.cyclicScrolling(Config.use_cyclic_scrolling);
|
Playlists.cyclicScrolling(Config.use_cyclic_scrolling);
|
||||||
@@ -108,11 +112,14 @@ void PlaylistEditor::resize()
|
|||||||
size_t x_offset, width;
|
size_t x_offset, width;
|
||||||
getWindowResizeParams(x_offset, width);
|
getWindowResizeParams(x_offset, width);
|
||||||
|
|
||||||
|
size_t ra = Config.playlist_editor_column_width_ratio[0];
|
||||||
|
size_t rb = Config.playlist_editor_column_width_ratio[1];
|
||||||
|
|
||||||
LeftColumnStartX = x_offset;
|
LeftColumnStartX = x_offset;
|
||||||
LeftColumnWidth = width/3-1;
|
LeftColumnWidth = width*ra/(ra+rb)-1;
|
||||||
RightColumnStartX = LeftColumnStartX+LeftColumnWidth+1;
|
RightColumnStartX = LeftColumnStartX+LeftColumnWidth+1;
|
||||||
RightColumnWidth = width-LeftColumnWidth-1;
|
RightColumnWidth = width-LeftColumnWidth-1;
|
||||||
|
|
||||||
Playlists.resize(LeftColumnWidth, MainHeight);
|
Playlists.resize(LeftColumnWidth, MainHeight);
|
||||||
Content.resize(RightColumnWidth, MainHeight);
|
Content.resize(RightColumnWidth, MainHeight);
|
||||||
|
|
||||||
@@ -162,10 +169,7 @@ void PlaylistEditor::update()
|
|||||||
}
|
}
|
||||||
catch (MPD::ServerError &e)
|
catch (MPD::ServerError &e)
|
||||||
{
|
{
|
||||||
if (e.code() == MPD_SERVER_ERROR_SYSTEM) // no playlists directory
|
Status::handleServerError(e);
|
||||||
Statusbar::print(e.what());
|
|
||||||
else
|
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
if (idx < Playlists.size())
|
if (idx < Playlists.size())
|
||||||
Playlists.resizeList(idx);
|
Playlists.resizeList(idx);
|
||||||
|
|||||||
@@ -798,13 +798,16 @@ void TagEditor::runAction()
|
|||||||
Statusbar::print("Writing changes...");
|
Statusbar::print("Writing changes...");
|
||||||
for (auto it = EditedSongs.begin(); it != EditedSongs.end(); ++it)
|
for (auto it = EditedSongs.begin(); it != EditedSongs.end(); ++it)
|
||||||
{
|
{
|
||||||
Statusbar::printf("Writing tags in \"%1%\"...", (*it)->getName());
|
if ((*it)->isModified())
|
||||||
if (!Tags::write(**it))
|
|
||||||
{
|
{
|
||||||
Statusbar::printf("Error while writing tags to \"%1%\": %2%",
|
Statusbar::printf("Writing tags in \"%1%\"...", (*it)->getName());
|
||||||
(*it)->getName(), strerror(errno));
|
if (!Tags::write(**it))
|
||||||
success = 0;
|
{
|
||||||
break;
|
Statusbar::printf("Error while writing tags to \"%1%\": %2%",
|
||||||
|
(*it)->getName(), strerror(errno));
|
||||||
|
success = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (success)
|
if (success)
|
||||||
|
|||||||
@@ -83,7 +83,8 @@ Visualizer::Visualizer()
|
|||||||
HZ_MIN(Config.visualizer_spectrum_hz_min),
|
HZ_MIN(Config.visualizer_spectrum_hz_min),
|
||||||
HZ_MAX(Config.visualizer_spectrum_hz_max),
|
HZ_MAX(Config.visualizer_spectrum_hz_max),
|
||||||
GAIN(Config.visualizer_spectrum_gain),
|
GAIN(Config.visualizer_spectrum_gain),
|
||||||
SMOOTH_CHARS(ToWString("▁▂▃▄▅▆▇█"))
|
SMOOTH_CHARS(ToWString("▁▂▃▄▅▆▇█")),
|
||||||
|
SMOOTH_CHARS_FLIPPED(ToWString("▔🮂🮃🮄🬎🮅🮆█")) // https://unicode.org/charts/PDF/U1FB00.pdf
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
InitDataSource();
|
InitDataSource();
|
||||||
@@ -95,7 +96,7 @@ Visualizer::Visualizer()
|
|||||||
memset(m_fftw_input, 0, sizeof(double)*DFT_TOTAL_SIZE);
|
memset(m_fftw_input, 0, sizeof(double)*DFT_TOTAL_SIZE);
|
||||||
m_fftw_output = static_cast<fftw_complex *>(fftw_malloc(sizeof(fftw_complex)*m_fftw_results));
|
m_fftw_output = static_cast<fftw_complex *>(fftw_malloc(sizeof(fftw_complex)*m_fftw_results));
|
||||||
m_fftw_plan = fftw_plan_dft_r2c_1d(DFT_TOTAL_SIZE, m_fftw_input, m_fftw_output, FFTW_ESTIMATE);
|
m_fftw_plan = fftw_plan_dft_r2c_1d(DFT_TOTAL_SIZE, m_fftw_input, m_fftw_output, FFTW_ESTIMATE);
|
||||||
m_dft_logspace.reserve(500);
|
m_dft_freqspace.reserve(500);
|
||||||
m_bar_heights.reserve(100);
|
m_bar_heights.reserve(100);
|
||||||
# endif // HAVE_FFTW3_H
|
# endif // HAVE_FFTW3_H
|
||||||
}
|
}
|
||||||
@@ -107,7 +108,7 @@ void Visualizer::switchTo()
|
|||||||
m_reset_output = true;
|
m_reset_output = true;
|
||||||
drawHeader();
|
drawHeader();
|
||||||
# ifdef HAVE_FFTW3_H
|
# ifdef HAVE_FFTW3_H
|
||||||
GenLogspace();
|
GenFreqSpace();
|
||||||
m_bar_heights.reserve(w.getWidth());
|
m_bar_heights.reserve(w.getWidth());
|
||||||
# endif // HAVE_FFTW3_H
|
# endif // HAVE_FFTW3_H
|
||||||
}
|
}
|
||||||
@@ -121,7 +122,7 @@ void Visualizer::resize()
|
|||||||
hasToBeResized = 0;
|
hasToBeResized = 0;
|
||||||
InitVisualization();
|
InitVisualization();
|
||||||
# ifdef HAVE_FFTW3_H
|
# ifdef HAVE_FFTW3_H
|
||||||
GenLogspace();
|
GenFreqSpace();
|
||||||
m_bar_heights.reserve(w.getWidth());
|
m_bar_heights.reserve(w.getWidth());
|
||||||
# endif // HAVE_FFTW3_H
|
# endif // HAVE_FFTW3_H
|
||||||
}
|
}
|
||||||
@@ -420,7 +421,7 @@ void Visualizer::DrawSoundEllipseStereo(const int16_t *buf_left, const int16_t *
|
|||||||
auto c = toColor(sqrt(x*x + 4*y*y), radius, true);
|
auto c = toColor(sqrt(x*x + 4*y*y), radius, true);
|
||||||
w << NC::XY(left_half_width + x, top_half_height + y)
|
w << NC::XY(left_half_width + x, top_half_height + y)
|
||||||
<< c
|
<< c
|
||||||
<< Config.visualizer_chars[1]
|
<< Config.visualizer_chars[0]
|
||||||
<< NC::FormattedColor::End<>(c);
|
<< NC::FormattedColor::End<>(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -449,7 +450,7 @@ void Visualizer::DrawFrequencySpectrum(const int16_t *buf, ssize_t samples, size
|
|||||||
const size_t win_width = w.getWidth();
|
const size_t win_width = w.getWidth();
|
||||||
|
|
||||||
size_t cur_bin = 0;
|
size_t cur_bin = 0;
|
||||||
while (cur_bin < m_fftw_results && Bin2Hz(cur_bin) < m_dft_logspace[0])
|
while (cur_bin < m_fftw_results && Bin2Hz(cur_bin) < m_dft_freqspace[0])
|
||||||
++cur_bin;
|
++cur_bin;
|
||||||
for (size_t x = 0; x < win_width; ++x)
|
for (size_t x = 0; x < win_width; ++x)
|
||||||
{
|
{
|
||||||
@@ -458,10 +459,10 @@ void Visualizer::DrawFrequencySpectrum(const int16_t *buf, ssize_t samples, size
|
|||||||
// accumulate bins
|
// accumulate bins
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
// check right bound
|
// check right bound
|
||||||
while (cur_bin < m_fftw_results && Bin2Hz(cur_bin) < m_dft_logspace[x])
|
while (cur_bin < m_fftw_results && Bin2Hz(cur_bin) < m_dft_freqspace[x])
|
||||||
{
|
{
|
||||||
// check left bound if not first index
|
// check left bound if not first index
|
||||||
if (x == 0 || Bin2Hz(cur_bin) >= m_dft_logspace[x-1])
|
if (x == 0 || Bin2Hz(cur_bin) >= m_dft_freqspace[x-1])
|
||||||
{
|
{
|
||||||
bar_height += m_freq_magnitudes[cur_bin];
|
bar_height += m_freq_magnitudes[cur_bin];
|
||||||
++count;
|
++count;
|
||||||
@@ -475,8 +476,19 @@ void Visualizer::DrawFrequencySpectrum(const int16_t *buf, ssize_t samples, size
|
|||||||
// average bins
|
// average bins
|
||||||
bar_height /= count;
|
bar_height /= count;
|
||||||
|
|
||||||
// log scale bar heights
|
// apply scaling to bar heights
|
||||||
bar_height = (20 * log10(bar_height) + DYNAMIC_RANGE + GAIN) / DYNAMIC_RANGE;
|
if (Config.visualizer_spectrum_log_scale_y) {
|
||||||
|
bar_height = (20 * log10(bar_height) + DYNAMIC_RANGE + GAIN) / DYNAMIC_RANGE;
|
||||||
|
} else {
|
||||||
|
// apply gain
|
||||||
|
bar_height *= pow(10, 1.8 + GAIN / 20);
|
||||||
|
// buff higher frequencies
|
||||||
|
bar_height *= log2(2 + x) * 80.0/win_width;
|
||||||
|
// moderately normalize the heights
|
||||||
|
bar_height = pow(bar_height, 0.65);
|
||||||
|
|
||||||
|
//bar_height = pow(10, 1 + GAIN / 20) * bar_height;
|
||||||
|
}
|
||||||
// Scale bar height between 0 and height
|
// Scale bar height between 0 and height
|
||||||
bar_height = bar_height > 0 ? bar_height * height : 0;
|
bar_height = bar_height > 0 ? bar_height * height : 0;
|
||||||
bar_height = bar_height > height ? height : bar_height;
|
bar_height = bar_height > height ? height : bar_height;
|
||||||
@@ -498,7 +510,12 @@ void Visualizer::DrawFrequencySpectrum(const int16_t *buf, ssize_t samples, size
|
|||||||
++h_idx;
|
++h_idx;
|
||||||
} else {
|
} else {
|
||||||
// data point does not exist, need to interpolate
|
// data point does not exist, need to interpolate
|
||||||
h = Interpolate(x, h_idx);
|
if (Config.visualizer_spectrum_log_scale_x) {
|
||||||
|
h = InterpolateCubic(x, h_idx);
|
||||||
|
} else {
|
||||||
|
h = std::min(InterpolateLinear(x, h_idx), height / 1.0);
|
||||||
|
//h = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t j = 0; j < h; ++j)
|
for (size_t j = 0; j < h; ++j)
|
||||||
@@ -518,8 +535,12 @@ void Visualizer::DrawFrequencySpectrum(const int16_t *buf, ssize_t samples, size
|
|||||||
} else {
|
} else {
|
||||||
// fractional height
|
// fractional height
|
||||||
if (flipped) {
|
if (flipped) {
|
||||||
ch = SMOOTH_CHARS[size-idx-2];
|
if (Config.visualizer_spectrum_smooth_look_legacy_chars) {
|
||||||
color = NC::FormattedColor(color.color(), {NC::Format::Reverse});
|
ch = SMOOTH_CHARS_FLIPPED[idx];
|
||||||
|
} else {
|
||||||
|
ch = SMOOTH_CHARS[size-idx-2];
|
||||||
|
color = NC::FormattedColor(color.color(), {NC::Format::Reverse});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ch = SMOOTH_CHARS[idx];
|
ch = SMOOTH_CHARS[idx];
|
||||||
}
|
}
|
||||||
@@ -544,7 +565,7 @@ void Visualizer::DrawFrequencySpectrumStereo(const int16_t *buf_left, const int1
|
|||||||
DrawFrequencySpectrum(buf_right, samples, height, w.getHeight() - height);
|
DrawFrequencySpectrum(buf_right, samples, height, w.getHeight() - height);
|
||||||
}
|
}
|
||||||
|
|
||||||
double Visualizer::Interpolate(size_t x, size_t h_idx)
|
double Visualizer::InterpolateCubic(size_t x, size_t h_idx)
|
||||||
{
|
{
|
||||||
const double x_next = m_bar_heights[h_idx].first;
|
const double x_next = m_bar_heights[h_idx].first;
|
||||||
const double h_next = m_bar_heights[h_idx].second;
|
const double h_next = m_bar_heights[h_idx].second;
|
||||||
@@ -589,6 +610,33 @@ double Visualizer::Interpolate(size_t x, size_t h_idx)
|
|||||||
return h_next;
|
return h_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double Visualizer::InterpolateLinear(size_t x, size_t h_idx)
|
||||||
|
{
|
||||||
|
const double x_next = m_bar_heights[h_idx].first;
|
||||||
|
const double h_next = m_bar_heights[h_idx].second;
|
||||||
|
|
||||||
|
double dh = 0;
|
||||||
|
if (h_idx == 0) {
|
||||||
|
// no data points on the left, linear extrapolation
|
||||||
|
if (h_idx < m_bar_heights.size()) {
|
||||||
|
const double x_next2 = m_bar_heights[h_idx+1].first;
|
||||||
|
const double h_next2 = m_bar_heights[h_idx+1].second;
|
||||||
|
dh = (h_next2 - h_next) / (x_next2 - x_next);
|
||||||
|
}
|
||||||
|
return h_next - dh * (x_next - x);
|
||||||
|
} else if (h_idx < m_bar_heights.size()) {
|
||||||
|
// simple linear interpolation
|
||||||
|
const double x_prev = m_bar_heights[h_idx-1].first;
|
||||||
|
const double h_prev = m_bar_heights[h_idx-1].second;
|
||||||
|
|
||||||
|
const double m = (h_next - h_prev) / (x_next - x_prev);
|
||||||
|
return h_prev + m * (x - x_prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
// no data points on the right: don't interpolate
|
||||||
|
return h_next;
|
||||||
|
}
|
||||||
|
|
||||||
void Visualizer::ApplyWindow(double *output, const int16_t *input, ssize_t samples)
|
void Visualizer::ApplyWindow(double *output, const int16_t *input, ssize_t samples)
|
||||||
{
|
{
|
||||||
// Use Blackman window for low sidelobes and fast sidelobe rolloff
|
// Use Blackman window for low sidelobes and fast sidelobe rolloff
|
||||||
@@ -617,10 +665,36 @@ void Visualizer::GenLogspace()
|
|||||||
const size_t win_width = w.getWidth();
|
const size_t win_width = w.getWidth();
|
||||||
const size_t left_bins = (log10(HZ_MIN) - win_width*log10(HZ_MIN)) / (log10(HZ_MIN) - log10(HZ_MAX));
|
const size_t left_bins = (log10(HZ_MIN) - win_width*log10(HZ_MIN)) / (log10(HZ_MIN) - log10(HZ_MAX));
|
||||||
// Generate logspaced frequencies
|
// Generate logspaced frequencies
|
||||||
m_dft_logspace.resize(win_width);
|
m_dft_freqspace.resize(win_width);
|
||||||
const double log_scale = log10(HZ_MAX) / (left_bins + m_dft_logspace.size() - 1);
|
const double log_scale = log10(HZ_MAX) / (left_bins + m_dft_freqspace.size() - 1);
|
||||||
for (size_t i = left_bins; i < m_dft_logspace.size() + left_bins; ++i) {
|
for (size_t i = left_bins; i < m_dft_freqspace.size() + left_bins; ++i) {
|
||||||
m_dft_logspace[i - left_bins] = pow(10, i * log_scale);
|
m_dft_freqspace[i - left_bins] = pow(10, i * log_scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate vector of linearly-spaced frequencies from HZ_MIN to HZ_MAX
|
||||||
|
void Visualizer::GenLinspace()
|
||||||
|
{
|
||||||
|
// Calculate number of extra bins needed between 0 HZ and HZ_MIN
|
||||||
|
const size_t win_width = w.getWidth();
|
||||||
|
const size_t left_bins = (HZ_MIN - win_width * HZ_MIN) / (HZ_MIN - HZ_MAX);
|
||||||
|
// Generate linspaced frequencies
|
||||||
|
m_dft_freqspace.resize(win_width);
|
||||||
|
const double lin_scale = HZ_MAX / (left_bins + m_dft_freqspace.size() - 1);
|
||||||
|
for (size_t i = left_bins; i < m_dft_freqspace.size() + left_bins; ++i) {
|
||||||
|
m_dft_freqspace[i - left_bins] = i * lin_scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate vector of spectrum frequencies from HZ_MIN to HZ_MAX
|
||||||
|
// Frequencies are (not) log-scaled depending on
|
||||||
|
// Config.visualizer_spectrum_log_scale_x
|
||||||
|
void Visualizer::GenFreqSpace()
|
||||||
|
{
|
||||||
|
if (Config.visualizer_spectrum_log_scale_x) {
|
||||||
|
GenLogspace();
|
||||||
|
} else {
|
||||||
|
GenLinspace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // HAVE_FFTW3_H
|
#endif // HAVE_FFTW3_H
|
||||||
|
|||||||
@@ -76,8 +76,11 @@ private:
|
|||||||
void DrawFrequencySpectrumStereo(const int16_t *, const int16_t *, ssize_t, size_t);
|
void DrawFrequencySpectrumStereo(const int16_t *, const int16_t *, ssize_t, size_t);
|
||||||
void ApplyWindow(double *, const int16_t *, ssize_t);
|
void ApplyWindow(double *, const int16_t *, ssize_t);
|
||||||
void GenLogspace();
|
void GenLogspace();
|
||||||
|
void GenLinspace();
|
||||||
|
void GenFreqSpace();
|
||||||
double Bin2Hz(size_t);
|
double Bin2Hz(size_t);
|
||||||
double Interpolate(size_t, size_t);
|
double InterpolateCubic(size_t, size_t);
|
||||||
|
double InterpolateLinear(size_t, size_t);
|
||||||
# endif // HAVE_FFTW3_H
|
# endif // HAVE_FFTW3_H
|
||||||
|
|
||||||
void InitDataSource();
|
void InitDataSource();
|
||||||
@@ -113,7 +116,8 @@ private:
|
|||||||
const double HZ_MAX;
|
const double HZ_MAX;
|
||||||
const double GAIN;
|
const double GAIN;
|
||||||
const std::wstring SMOOTH_CHARS;
|
const std::wstring SMOOTH_CHARS;
|
||||||
std::vector<double> m_dft_logspace;
|
const std::wstring SMOOTH_CHARS_FLIPPED;
|
||||||
|
std::vector<double> m_dft_freqspace;
|
||||||
std::vector<std::pair<size_t, double>> m_bar_heights;
|
std::vector<std::pair<size_t, double>> m_bar_heights;
|
||||||
|
|
||||||
std::vector<double> m_freq_magnitudes;
|
std::vector<double> m_freq_magnitudes;
|
||||||
|
|||||||
@@ -212,28 +212,6 @@ void deprecated(const char *option, const char *version_removal,
|
|||||||
bool Configuration::read(const std::vector<std::string> &config_paths, bool ignore_errors)
|
bool Configuration::read(const std::vector<std::string> &config_paths, bool ignore_errors)
|
||||||
{
|
{
|
||||||
option_parser p;
|
option_parser p;
|
||||||
|
|
||||||
// Deprecated options.
|
|
||||||
p.add("visualizer_fifo_path", &visualizer_fifo_path, "", [](std::string v) {
|
|
||||||
if (!v.empty())
|
|
||||||
{
|
|
||||||
deprecated("visualizer_fifo_path",
|
|
||||||
"0.10",
|
|
||||||
"replaced by visualizer_data_source");
|
|
||||||
}
|
|
||||||
return adjust_path(v);
|
|
||||||
});
|
|
||||||
p.add<void>("visualizer_sync_interval", nullptr, "", [](std::string v) {
|
|
||||||
if (!v.empty())
|
|
||||||
{
|
|
||||||
deprecated("visualizer_sync_interval",
|
|
||||||
"0.10",
|
|
||||||
"set 'buffer_time' parameter of your MPD audio output to '100000' "
|
|
||||||
"(100ms) or lower if you experience synchronization issues "
|
|
||||||
"between audio and visualization");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// keep the same order of variables as in configuration file
|
// keep the same order of variables as in configuration file
|
||||||
p.add("ncmpcpp_directory", &ncmpcpp_directory, "~/.config/ncmpcpp/", adjust_directory);
|
p.add("ncmpcpp_directory", &ncmpcpp_directory, "~/.config/ncmpcpp/", adjust_directory);
|
||||||
p.add("lyrics_directory", &lyrics_directory, "~/.lyrics/", adjust_directory);
|
p.add("lyrics_directory", &lyrics_directory, "~/.lyrics/", adjust_directory);
|
||||||
@@ -270,11 +248,12 @@ bool Configuration::read(const std::vector<std::string> &config_paths, bool igno
|
|||||||
p.add("visualizer_fps", &visualizer_fps,
|
p.add("visualizer_fps", &visualizer_fps,
|
||||||
"60", [](std::string v) {
|
"60", [](std::string v) {
|
||||||
uint32_t result = verbose_lexical_cast<uint32_t>(v);
|
uint32_t result = verbose_lexical_cast<uint32_t>(v);
|
||||||
boundsCheck<uint32_t>(result, 30, 144);
|
boundsCheck<uint32_t>(result, 30, 1000);
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
p.add("visualizer_autoscale", &visualizer_autoscale, "no", yes_no);
|
p.add("visualizer_autoscale", &visualizer_autoscale, "no", yes_no);
|
||||||
p.add("visualizer_spectrum_smooth_look", &visualizer_spectrum_smooth_look, "yes", yes_no);
|
p.add("visualizer_spectrum_smooth_look", &visualizer_spectrum_smooth_look, "yes", yes_no);
|
||||||
|
p.add("visualizer_spectrum_smooth_look_legacy_chars", &visualizer_spectrum_smooth_look_legacy_chars, "yes", yes_no);
|
||||||
p.add("visualizer_spectrum_dft_size", &visualizer_spectrum_dft_size,
|
p.add("visualizer_spectrum_dft_size", &visualizer_spectrum_dft_size,
|
||||||
"2", [](std::string v) {
|
"2", [](std::string v) {
|
||||||
auto result = verbose_lexical_cast<size_t>(v);
|
auto result = verbose_lexical_cast<size_t>(v);
|
||||||
@@ -299,6 +278,8 @@ bool Configuration::read(const std::vector<std::string> &config_paths, bool igno
|
|||||||
lowerBoundCheck<double>(result, Config.visualizer_spectrum_hz_min+1);
|
lowerBoundCheck<double>(result, Config.visualizer_spectrum_hz_min+1);
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
p.add("visualizer_spectrum_log_scale_x", &visualizer_spectrum_log_scale_x, "yes", yes_no);
|
||||||
|
p.add("visualizer_spectrum_log_scale_y", &visualizer_spectrum_log_scale_y, "yes", yes_no);
|
||||||
p.add("visualizer_color", &visualizer_colors,
|
p.add("visualizer_color", &visualizer_colors,
|
||||||
"blue, cyan, green, yellow, magenta, red", list_of<NC::FormattedColor>);
|
"blue, cyan, green, yellow, magenta, red", list_of<NC::FormattedColor>);
|
||||||
p.add("system_encoding", &system_encoding, "", [](std::string encoding) {
|
p.add("system_encoding", &system_encoding, "", [](std::string encoding) {
|
||||||
@@ -480,9 +461,27 @@ bool Configuration::read(const std::vector<std::string> &config_paths, bool igno
|
|||||||
p.add("titles_visibility", &titles_visibility, "yes", yes_no);
|
p.add("titles_visibility", &titles_visibility, "yes", yes_no);
|
||||||
p.add("header_text_scrolling", &header_text_scrolling, "yes", yes_no);
|
p.add("header_text_scrolling", &header_text_scrolling, "yes", yes_no);
|
||||||
p.add("cyclic_scrolling", &use_cyclic_scrolling, "no", yes_no);
|
p.add("cyclic_scrolling", &use_cyclic_scrolling, "no", yes_no);
|
||||||
p.add("lyrics_fetchers", &lyrics_fetchers,
|
p.add<void>("lyrics_fetchers", nullptr,
|
||||||
"azlyrics, genius, musixmatch, sing365, metrolyrics, justsomelyrics, jahlyrics, plyrics, tekstowo, zeneszoveg, internet",
|
#ifdef HAVE_TAGLIB_H
|
||||||
list_of<LyricsFetcher_>);
|
"tags, "
|
||||||
|
#endif
|
||||||
|
"genius, tekstowo, plyrics, justsomelyrics, jahlyrics, zeneszoveg, internet", [this](std::string v) {
|
||||||
|
lyrics_fetchers = list_of<LyricsFetcher_>(v, [](std::string s) {
|
||||||
|
LyricsFetcher_ fetcher;
|
||||||
|
try {
|
||||||
|
fetcher = boost::lexical_cast<LyricsFetcher_>(s);
|
||||||
|
} catch (boost::bad_lexical_cast &) {
|
||||||
|
std::clog << "Unknown lyrics fetcher: " << s << "\n";
|
||||||
|
}
|
||||||
|
return fetcher;
|
||||||
|
});
|
||||||
|
auto last = std::remove_if(
|
||||||
|
lyrics_fetchers.begin(), lyrics_fetchers.end(),
|
||||||
|
[](const auto &f) { return f.get() == nullptr; });
|
||||||
|
lyrics_fetchers.erase(last, lyrics_fetchers.end());
|
||||||
|
if (lyrics_fetchers.empty())
|
||||||
|
invalid_value(v);
|
||||||
|
});
|
||||||
p.add("follow_now_playing_lyrics", &now_playing_lyrics, "no", yes_no);
|
p.add("follow_now_playing_lyrics", &now_playing_lyrics, "no", yes_no);
|
||||||
p.add("fetch_lyrics_for_current_song_in_background", &fetch_lyrics_in_background,
|
p.add("fetch_lyrics_for_current_song_in_background", &fetch_lyrics_in_background,
|
||||||
"no", yes_no);
|
"no", yes_no);
|
||||||
@@ -534,6 +533,12 @@ bool Configuration::read(const std::vector<std::string> &config_paths, bool igno
|
|||||||
});
|
});
|
||||||
p.add("ask_for_locked_screen_width_part", &ask_for_locked_screen_width_part,
|
p.add("ask_for_locked_screen_width_part", &ask_for_locked_screen_width_part,
|
||||||
"yes", yes_no);
|
"yes", yes_no);
|
||||||
|
p.add("media_library_column_width_ratio_two", &media_library_column_width_ratio_two,
|
||||||
|
"1:1", std::bind(parse_ratio, ph::_1, 2));
|
||||||
|
p.add("media_library_column_width_ratio_three", &media_library_column_width_ratio_three,
|
||||||
|
"1:1:1", std::bind(parse_ratio, ph::_1, 3));
|
||||||
|
p.add("playlist_editor_column_width_ratio", &playlist_editor_column_width_ratio,
|
||||||
|
"1:2", std::bind(parse_ratio, ph::_1, 2));
|
||||||
p.add("jump_to_now_playing_song_at_start", &jump_to_now_playing_song_at_start,
|
p.add("jump_to_now_playing_song_at_start", &jump_to_now_playing_song_at_start,
|
||||||
"yes", yes_no);
|
"yes", yes_no);
|
||||||
p.add("ask_before_clearing_playlists", &ask_before_clearing_playlists,
|
p.add("ask_before_clearing_playlists", &ask_before_clearing_playlists,
|
||||||
@@ -549,6 +554,7 @@ bool Configuration::read(const std::vector<std::string> &config_paths, bool igno
|
|||||||
return boost::regex::icase | boost::regex::literal;
|
return boost::regex::icase | boost::regex::literal;
|
||||||
else if (v == "basic")
|
else if (v == "basic")
|
||||||
return boost::regex::icase | boost::regex::basic;
|
return boost::regex::icase | boost::regex::basic;
|
||||||
|
|
||||||
else if (v == "extended")
|
else if (v == "extended")
|
||||||
return boost::regex::icase | boost::regex::extended;
|
return boost::regex::icase | boost::regex::extended;
|
||||||
else if (v == "perl")
|
else if (v == "perl")
|
||||||
|
|||||||
@@ -86,13 +86,20 @@ struct Configuration
|
|||||||
size_t visualizer_fps;
|
size_t visualizer_fps;
|
||||||
bool visualizer_autoscale;
|
bool visualizer_autoscale;
|
||||||
bool visualizer_spectrum_smooth_look;
|
bool visualizer_spectrum_smooth_look;
|
||||||
|
bool visualizer_spectrum_smooth_look_legacy_chars;
|
||||||
uint32_t visualizer_spectrum_dft_size;
|
uint32_t visualizer_spectrum_dft_size;
|
||||||
double visualizer_spectrum_gain;
|
double visualizer_spectrum_gain;
|
||||||
double visualizer_spectrum_hz_min;
|
double visualizer_spectrum_hz_min;
|
||||||
double visualizer_spectrum_hz_max;
|
double visualizer_spectrum_hz_max;
|
||||||
|
bool visualizer_spectrum_log_scale_x;
|
||||||
|
bool visualizer_spectrum_log_scale_y;
|
||||||
|
|
||||||
std::string pattern;
|
std::string pattern;
|
||||||
|
|
||||||
|
std::vector<size_t> playlist_editor_column_width_ratio;
|
||||||
|
std::vector<size_t> media_library_column_width_ratio_two;
|
||||||
|
std::vector<size_t> media_library_column_width_ratio_three;
|
||||||
|
|
||||||
std::vector<Column> columns;
|
std::vector<Column> columns;
|
||||||
|
|
||||||
DisplayMode playlist_display_mode;
|
DisplayMode playlist_display_mode;
|
||||||
|
|||||||
@@ -293,7 +293,9 @@ bool Song::isFromDatabase() const
|
|||||||
bool Song::isStream() const
|
bool Song::isStream() const
|
||||||
{
|
{
|
||||||
assert(m_song);
|
assert(m_song);
|
||||||
return !strncmp(mpd_song_get_uri(m_song.get()), "http://", 7);
|
const char *song_uri = mpd_song_get_uri(m_song.get());
|
||||||
|
// Stream schemas: http, https
|
||||||
|
return !strncmp(song_uri, "http://", 7) || !strncmp(song_uri, "https://", 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Song::empty() const
|
bool Song::empty() const
|
||||||
@@ -308,7 +310,7 @@ std::string Song::ShowTime(unsigned length)
|
|||||||
int minutes = length/60;
|
int minutes = length/60;
|
||||||
length -= minutes*60;
|
length -= minutes*60;
|
||||||
int seconds = length;
|
int seconds = length;
|
||||||
|
|
||||||
std::string result;
|
std::string result;
|
||||||
if (hours > 0)
|
if (hours > 0)
|
||||||
result = (boost::format("%d:%02d:%02d") % hours % minutes % seconds).str();
|
result = (boost::format("%d:%02d:%02d") % hours % minutes % seconds).str();
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
#include "curses/window.h"
|
#include "curses/window.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "gcc.h"
|
|
||||||
#include "interfaces.h"
|
#include "interfaces.h"
|
||||||
|
|
||||||
namespace Progressbar {
|
namespace Progressbar {
|
||||||
|
|||||||
19
src/tags.cpp
19
src/tags.cpp
@@ -92,7 +92,7 @@ void readID3v2Tags(mpd_song *s, TagLib::ID3v2::Tag *tag)
|
|||||||
readFrame(frames["TRCK"], "Track");
|
readFrame(frames["TRCK"], "Track");
|
||||||
readFrame(frames["TCON"], "Genre");
|
readFrame(frames["TCON"], "Genre");
|
||||||
readFrame(frames["TCOM"], "Composer");
|
readFrame(frames["TCOM"], "Composer");
|
||||||
readFrame(frames["TPE3"], "Performer");
|
readFrame(frames["TPE4"], "Performer");
|
||||||
readFrame(frames["TPOS"], "Disc");
|
readFrame(frames["TPOS"], "Disc");
|
||||||
readFrame(frames["COMM"], "Comment");
|
readFrame(frames["COMM"], "Comment");
|
||||||
}
|
}
|
||||||
@@ -123,12 +123,12 @@ void writeCommonTags(const MPD::MutableSong &s, TagLib::Tag *tag)
|
|||||||
tag->setArtist(ToWString(s.getArtist()));
|
tag->setArtist(ToWString(s.getArtist()));
|
||||||
tag->setAlbum(ToWString(s.getAlbum()));
|
tag->setAlbum(ToWString(s.getAlbum()));
|
||||||
try {
|
try {
|
||||||
tag->setYear(boost::lexical_cast<TagLib::uint>(s.getDate()));
|
tag->setYear(boost::lexical_cast<unsigned>(s.getDate()));
|
||||||
} catch (boost::bad_lexical_cast &) {
|
} catch (boost::bad_lexical_cast &) {
|
||||||
std::cerr << "writeCommonTags: couldn't write 'year' tag to '" << s.getURI() << "' as it's not a positive integer\n";
|
std::cerr << "writeCommonTags: couldn't write 'year' tag to '" << s.getURI() << "' as it's not a positive integer\n";
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
tag->setTrack(boost::lexical_cast<TagLib::uint>(s.getTrack()));
|
tag->setTrack(boost::lexical_cast<unsigned>(s.getTrack()));
|
||||||
} catch (boost::bad_lexical_cast &) {
|
} catch (boost::bad_lexical_cast &) {
|
||||||
std::cerr << "writeCommonTags: couldn't write 'track' tag to '" << s.getURI() << "' as it's not a positive integer\n";
|
std::cerr << "writeCommonTags: couldn't write 'track' tag to '" << s.getURI() << "' as it's not a positive integer\n";
|
||||||
}
|
}
|
||||||
@@ -166,7 +166,7 @@ void writeID3v2Tags(const MPD::MutableSong &s, TagLib::ID3v2::Tag *tag)
|
|||||||
writeID3v2("TRCK", tagList(s, &MPD::Song::getTrack));
|
writeID3v2("TRCK", tagList(s, &MPD::Song::getTrack));
|
||||||
writeID3v2("TCON", tagList(s, &MPD::Song::getGenre));
|
writeID3v2("TCON", tagList(s, &MPD::Song::getGenre));
|
||||||
writeID3v2("TCOM", tagList(s, &MPD::Song::getComposer));
|
writeID3v2("TCOM", tagList(s, &MPD::Song::getComposer));
|
||||||
writeID3v2("TPE3", tagList(s, &MPD::Song::getPerformer));
|
writeID3v2("TPE4", tagList(s, &MPD::Song::getPerformer));
|
||||||
writeID3v2("TPOS", tagList(s, &MPD::Song::getDisc));
|
writeID3v2("TPOS", tagList(s, &MPD::Song::getDisc));
|
||||||
writeID3v2("COMM", tagList(s, &MPD::Song::getComment));
|
writeID3v2("COMM", tagList(s, &MPD::Song::getComment));
|
||||||
}
|
}
|
||||||
@@ -174,6 +174,7 @@ void writeID3v2Tags(const MPD::MutableSong &s, TagLib::ID3v2::Tag *tag)
|
|||||||
void writeXiphComments(const MPD::MutableSong &s, TagLib::Ogg::XiphComment *tag)
|
void writeXiphComments(const MPD::MutableSong &s, TagLib::Ogg::XiphComment *tag)
|
||||||
{
|
{
|
||||||
auto writeXiph = [&](const TagLib::String &type, const TagLib::StringList &list) {
|
auto writeXiph = [&](const TagLib::String &type, const TagLib::StringList &list) {
|
||||||
|
tag->removeFields(type);
|
||||||
for (auto it = list.begin(); it != list.end(); ++it)
|
for (auto it = list.begin(); it != list.end(); ++it)
|
||||||
tag->addField(type, *it, it == list.begin());
|
tag->addField(type, *it, it == list.begin());
|
||||||
};
|
};
|
||||||
@@ -261,7 +262,7 @@ void read(mpd_song *s)
|
|||||||
if (f.isNull())
|
if (f.isNull())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
setAttribute(s, "Time", boost::lexical_cast<std::string>(f.audioProperties()->length()));
|
setAttribute(s, "Time", boost::lexical_cast<std::string>(f.audioProperties()->lengthInSeconds()));
|
||||||
|
|
||||||
if (auto mpeg_file = dynamic_cast<TagLib::MPEG::File *>(f.file()))
|
if (auto mpeg_file = dynamic_cast<TagLib::MPEG::File *>(f.file()))
|
||||||
{
|
{
|
||||||
@@ -301,15 +302,9 @@ bool write(MPD::MutableSong &s)
|
|||||||
if (f.isNull())
|
if (f.isNull())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool saved = false;
|
|
||||||
if (auto mpeg_file = dynamic_cast<TagLib::MPEG::File *>(f.file()))
|
if (auto mpeg_file = dynamic_cast<TagLib::MPEG::File *>(f.file()))
|
||||||
{
|
{
|
||||||
writeID3v2Tags(s, mpeg_file->ID3v2Tag(true));
|
writeID3v2Tags(s, mpeg_file->ID3v2Tag(true));
|
||||||
// write id3v2.4 tags only
|
|
||||||
if (!mpeg_file->save(TagLib::MPEG::File::ID3v2, true, 4, false))
|
|
||||||
return false;
|
|
||||||
// do not call generic save() as it will duplicate tags
|
|
||||||
saved = true;
|
|
||||||
}
|
}
|
||||||
else if (auto vorbis_file = dynamic_cast<TagLib::Ogg::Vorbis::File *>(f.file()))
|
else if (auto vorbis_file = dynamic_cast<TagLib::Ogg::Vorbis::File *>(f.file()))
|
||||||
{
|
{
|
||||||
@@ -326,7 +321,7 @@ bool write(MPD::MutableSong &s)
|
|||||||
else
|
else
|
||||||
writeCommonTags(s, f.tag());
|
writeCommonTags(s, f.tag());
|
||||||
|
|
||||||
if (!saved && !f.save())
|
if (!f.save())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// TODO: move this somewhere else
|
// TODO: move this somewhere else
|
||||||
|
|||||||
@@ -34,10 +34,23 @@ bool hasTheWord(const std::string &s)
|
|||||||
&& (s[3] == ' ');
|
&& (s[3] == ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long long strToLL(const char *s, size_t len)
|
||||||
|
{
|
||||||
|
long long n = 0;
|
||||||
|
while (len--)
|
||||||
|
n = 10*n + *s++ - '0';
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int LocaleStringComparison::compare(const char *a, size_t a_len, const char *b, size_t b_len) const
|
int LocaleStringComparison::compare(const char *a, size_t a_len, const char *b, size_t b_len) const
|
||||||
{
|
{
|
||||||
|
// If both strings are numbers, compare them as such.
|
||||||
|
if ( a_len > 0 && std::all_of(a, a + a_len, isdigit)
|
||||||
|
&& b_len > 0 && std::all_of(b, b + b_len, isdigit))
|
||||||
|
return strToLL(a, a_len) - strToLL(b, b_len);
|
||||||
|
|
||||||
size_t ac_off = 0, bc_off = 0;
|
size_t ac_off = 0, bc_off = 0;
|
||||||
if (m_ignore_the)
|
if (m_ignore_the)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
#include <boost/type_traits/is_unsigned.hpp>
|
#include <boost/type_traits/is_unsigned.hpp>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "gcc.h"
|
|
||||||
|
|
||||||
struct ConversionError
|
struct ConversionError
|
||||||
{
|
{
|
||||||
@@ -44,21 +43,21 @@ struct OutOfBounds : std::exception
|
|||||||
const std::string &errorMessage() { return m_error_message; }
|
const std::string &errorMessage() { return m_error_message; }
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
GNUC_NORETURN static void raise(const Type &value, const Type &lbound, const Type &ubound)
|
[[noreturn]] static void raise(const Type &value, const Type &lbound, const Type &ubound)
|
||||||
{
|
{
|
||||||
throw OutOfBounds((boost::format(
|
throw OutOfBounds((boost::format(
|
||||||
"value is out of bounds ([%1%, %2%] expected, %3% given)") % lbound % ubound % value).str());
|
"value is out of bounds ([%1%, %2%] expected, %3% given)") % lbound % ubound % value).str());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
GNUC_NORETURN static void raiseLower(const Type &value, const Type &lbound)
|
[[noreturn]] static void raiseLower(const Type &value, const Type &lbound)
|
||||||
{
|
{
|
||||||
throw OutOfBounds((boost::format(
|
throw OutOfBounds((boost::format(
|
||||||
"value is out of bounds ([%1%, ->) expected, %2% given)") % lbound % value).str());
|
"value is out of bounds ([%1%, ->) expected, %2% given)") % lbound % value).str());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
GNUC_NORETURN static void raiseUpper(const Type &value, const Type &ubound)
|
[[noreturn]] static void raiseUpper(const Type &value, const Type &ubound)
|
||||||
{
|
{
|
||||||
throw OutOfBounds((boost::format(
|
throw OutOfBounds((boost::format(
|
||||||
"value is out of bounds ((<-, %1%] expected, %2% given)") % ubound % value).str());
|
"value is out of bounds ((<-, %1%] expected, %2% given)") % ubound % value).str());
|
||||||
|
|||||||
@@ -20,16 +20,29 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
#include <cstdlib>
|
||||||
#include "utility/html.h"
|
#include "utility/html.h"
|
||||||
|
|
||||||
std::string unescapeHtmlUtf8(const std::string &data)
|
std::string unescapeHtmlUtf8(const std::string &data)
|
||||||
{
|
{
|
||||||
|
int base;
|
||||||
|
size_t offset;
|
||||||
std::string result;
|
std::string result;
|
||||||
for (size_t i = 0, j; i < data.length(); ++i)
|
for (size_t i = 0, j; i < data.length(); ++i)
|
||||||
{
|
{
|
||||||
if (data[i] == '&' && data[i+1] == '#' && (j = data.find(';', i)) != std::string::npos)
|
if (data[i] == '&' && data[i+1] == '#' && (j = data.find(';', i)) != std::string::npos)
|
||||||
{
|
{
|
||||||
int n = atoi(&data.c_str()[i+2]);
|
if (data[i+2] == 'x')
|
||||||
|
{
|
||||||
|
offset = 3;
|
||||||
|
base = 16;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offset = 2;
|
||||||
|
base = 10;
|
||||||
|
}
|
||||||
|
int n = strtol(&data.c_str()[i+offset], nullptr, base);
|
||||||
if (n >= 0x800)
|
if (n >= 0x800)
|
||||||
{
|
{
|
||||||
result += (0xe0 | ((n >> 12) & 0x0f));
|
result += (0xe0 | ((n >> 12) & 0x0f));
|
||||||
|
|||||||
@@ -45,6 +45,20 @@ bool yes_no(const std::string &v)
|
|||||||
invalid_value(v);
|
invalid_value(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<size_t> parse_ratio(const std::string &v, const std::vector<size_t>::size_type length)
|
||||||
|
{
|
||||||
|
std::vector<size_t> ret = list_of<size_t>(v, verbose_lexical_cast<size_t>, length, "", ":", "");
|
||||||
|
|
||||||
|
size_t total = 0;
|
||||||
|
for (auto i : ret)
|
||||||
|
total += i;
|
||||||
|
if (total == 0)
|
||||||
|
invalid_value(v);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool option_parser::run(std::istream &is, bool ignore_errors)
|
bool option_parser::run(std::istream &is, bool ignore_errors)
|
||||||
|
|||||||
@@ -56,17 +56,26 @@ DestT verbose_lexical_cast(const std::string &v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename ValueT, typename ConvertT>
|
template <typename ValueT, typename ConvertT>
|
||||||
std::vector<ValueT> list_of(const std::string &v, ConvertT convert)
|
std::vector<ValueT> list_of(const std::string &v, ConvertT convert, const typename std::vector<ValueT>::size_type length, const std::string &escape, const std::string &sep, const std::string "e)
|
||||||
{
|
{
|
||||||
std::vector<ValueT> result;
|
std::vector<ValueT> result;
|
||||||
boost::tokenizer<boost::escaped_list_separator<char>> elems(v);
|
boost::escaped_list_separator<char> esq(escape, sep, quote);
|
||||||
|
boost::tokenizer<boost::escaped_list_separator<char>> elems(v, esq);
|
||||||
for (auto &value : elems)
|
for (auto &value : elems)
|
||||||
result.push_back(convert(boost::trim_copy(value)));
|
result.push_back(convert(boost::trim_copy(value)));
|
||||||
if (result.empty())
|
if (result.empty())
|
||||||
throw std::runtime_error("empty list");
|
throw std::runtime_error("empty list");
|
||||||
|
if (length > 0 && result.size() != length)
|
||||||
|
throw std::runtime_error("invalid list length");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename ValueT, typename ConvertT>
|
||||||
|
std::vector<ValueT> list_of(const std::string &v, ConvertT convert)
|
||||||
|
{
|
||||||
|
return list_of<ValueT>(v, convert, 0, "\\", ",", "\"");
|
||||||
|
}
|
||||||
|
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
std::vector<ValueT> list_of(const std::string &v)
|
std::vector<ValueT> list_of(const std::string &v)
|
||||||
{
|
{
|
||||||
@@ -75,6 +84,8 @@ std::vector<ValueT> list_of(const std::string &v)
|
|||||||
|
|
||||||
bool yes_no(const std::string &v);
|
bool yes_no(const std::string &v);
|
||||||
|
|
||||||
|
std::vector<size_t> parse_ratio(const std::string &v, const std::vector<size_t>::size_type length);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class option_parser
|
class option_parser
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include <locale>
|
#include <locale>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "gcc.h"
|
|
||||||
|
|
||||||
template <size_t N> size_t const_strlen(const char (&)[N]) {
|
template <size_t N> size_t const_strlen(const char (&)[N]) {
|
||||||
return N-1;
|
return N-1;
|
||||||
|
|||||||
@@ -168,6 +168,8 @@ MPD::Song::GetFunction charToGetFunction(char c)
|
|||||||
return &MPD::Song::getDirectory;
|
return &MPD::Song::getDirectory;
|
||||||
case 'f':
|
case 'f':
|
||||||
return &MPD::Song::getName;
|
return &MPD::Song::getName;
|
||||||
|
case 'F':
|
||||||
|
return &MPD::Song::getURI;
|
||||||
case 'a':
|
case 'a':
|
||||||
return &MPD::Song::getArtist;
|
return &MPD::Song::getArtist;
|
||||||
case 'A':
|
case 'A':
|
||||||
|
|||||||
Reference in New Issue
Block a user