Projects
Multimedia
ncmpc
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 13
View file
ncmpc.changes
Changed
@@ -1,7 +1,7 @@ ------------------------------------------------------------------- -Mon Jan 13 20:20:20 UTC 2020 - olaf@aepfle.de +Fri Jan 13 20:20:20 UTC 2023 - olaf@aepfle.de -- Update to version 0.36 +- Update to version 0.47 ------------------------------------------------------------------- Thu Oct 11 07:38:47 UTC 2018 - aloisio@gmx.com
View file
ncmpc.spec
Changed
@@ -17,20 +17,23 @@ Name: ncmpc -Version: 0.36 +Version: 0.47 Release: 0 Summary: Curses Client for the Music Player Daemon License: GPL-2.0-or-later Group: Productivity/Multimedia/Sound/Players -URL: http://mpd.wikia.com/wiki/Client:Ncmpc +URL: https://www.musicpd.org/clients/ncmpc/ Source: https://www.musicpd.org/download/ncmpc/0/ncmpc-%{version}.tar.xz Patch3: ncmpc-fix_meson_docdir.patch +%if %suse_version == 1500 +BuildRequires: gcc12-c++ +%else BuildRequires: gcc-c++ -BuildRequires: libboost_iostreams-devel >= 1.62 +%endif BuildRequires: ncurses-devel BuildRequires: pkgconfig -BuildRequires: pkgconfig(glib-2.0) >= 2.30 BuildRequires: pkgconfig(libmpdclient) >= 2.9 +BuildRequires: pkgconfig(libpcre2-8) BuildRequires: python3-Sphinx BuildRequires: meson >= 0.47 BuildRequires: ninja @@ -45,9 +48,16 @@ %autosetup -p1 %build +test -x "$(type -p gcc)" && CC="$_" +test -x "$(type -p g++)" && CXX="$_" +test -x "$(type -p gcc-12)" && CC="$_" +test -x "$(type -p g++-12)" && CXX="$_" +export CC="$(readlink -f ${CC})" +export CXX="$(readlink -f ${CXX})" %meson \ -Dlirc=disabled \ - -Dhtml_manual=false + -Dhtml_manual=false \ + %nil %meson_build %install @@ -59,7 +69,7 @@ %files %license COPYING -%doc AUTHORS NEWS README.rst +%doc AUTHORS NEWS %doc doc/*.sample %{_bindir}/ncmpc %{_mandir}/man*/*
View file
ncmpc-fix_meson_docdir.patch
Changed
@@ -1,16 +1,16 @@ --- a/meson.build +++ b/meson.build -@@ -376,11 +376,10 @@ ncmpc = executable('ncmpc', +@@ -450,11 +450,10 @@ ncmpc = executable('ncmpc', configure_file(output: 'config.h', configuration: conf) -docdir = join_paths(get_option('datadir'), 'doc', meson.project_name()) -install_data('AUTHORS', 'COPYING', 'NEWS', 'README.rst', +docdir = join_paths(get_option('datadir'), 'doc', 'packages', meson.project_name()) -+install_data('AUTHORS', 'NEWS', 'README.rst', ++install_data('AUTHORS', 'NEWS', 'doc/config.sample', 'doc/keys.sample', - 'doc/ncmpc.lirc', install_dir: docdir) - if not mini + if get_option('test')
View file
ncmpc-0.36.tar.xz/.travis.yml
Deleted
@@ -1,18 +0,0 @@ -language: cpp - -matrix: - include: - - os: osx - osx_image: xcode9.3beta - -before_install: - - test "$TRAVIS_OS_NAME" != "osx" || brew update - -install: - - test "$TRAVIS_OS_NAME" != "osx" || brew install meson ninja glib ncurses libmpdclient - -script: - - OPTIONS="-Dtest=true -Dlyrics_screen=true -Dchat_screen=true" - - test "$TRAVIS_OS_NAME" != "osx" || export PKG_CONFIG_PATH=/usr/local/opt/ncurses/lib/pkgconfig - - meson . output $OPTIONS - - ninja -v -C output
View file
ncmpc-0.36.tar.xz/lyrics/10-hd.sh
Deleted
@@ -1,30 +0,0 @@ -#!/bin/sh -e -# -# (c) 2004-2019 The Music Player Daemon Project -# http://www.musicpd.org/ -# -# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -# -# Load lyrics from the user's home directory -# - -FILENAME=~/.lyrics/"$1 - $2".txt - -if -e "$FILENAME" ; then - exec cat "$FILENAME" -else - exit 69 -fi
View file
ncmpc-0.36.tar.xz/lyrics/20-lyricwiki.rb
Deleted
@@ -1,59 +0,0 @@ -#!/usr/bin/env ruby -# -# (c) 2004-2019 The Music Player Daemon Project -# http://www.musicpd.org/ -# -# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -# -# Load lyrics from lyrics.wikia.com, formerly lyricwiki.org -# - -require 'uri' -require 'open-uri' -require 'cgi' - -# We need this because URI.escape doesn't escape ampersands. -def escape(string) - new = URI.escape(string) - new.gsub(/&/, "%26") -end - -url = "http://lyrics.wikia.com/api.php?action=lyrics&fmt=xml&func=getSong" + \ - "&artist=#{escape(ARGV0)}&song=#{escape(ARGV1)}" -response = open(URI.parse(url)).read - -if not response =~ /<url>\s*(.*?)\s*<\/url>/im - $stderr.puts "No URL in response!" - exit(1) -end - -url = $1 -exit(69) if url =~ /action=edit$/ - -response = open(URI.parse(url)).read -if not response =~ /<div class='lyricbox'>\s*(.*?)\s*<div class='lyricsbreak'>/im - $stderr.puts "No <div class='lyricbox'> in lyrics page!\n" - exit(1) -end - -lyrics = $1.gsub(/<br \/>/, "\n") - -if lyrics.respond_to?(:force_encoding) - puts CGI::unescapeHTML(lyrics.force_encoding(Encoding::UTF_8)) -else - $KCODE = 'U' - puts CGI::unescapeHTML(lyrics) -end
View file
ncmpc-0.36.tar.xz/src/AsioGetIoService.hxx
Deleted
@@ -1,54 +0,0 @@ -/* - * Copyright 2019 Max Kellermann <max.kellermann@gmail.com> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ASIO_GET_IO_SERVICE_HXX -#define ASIO_GET_IO_SERVICE_HXX - -#if BOOST_VERSION >= 106600 -#include <boost/asio/io_service.hpp> -#endif - -/** - * Returns the #io_service/#io_context reference from a boost::asio - * object. This is a compatibility function which works with Boost - * 1.68+ where #io_service was renamed to #io_context and - * get_io_service() was replaced with get_executor(). - */ -template<typename T> -inline auto & -get_io_service(T &t) noexcept -{ -#if BOOST_VERSION >= 106600 - return (boost::asio::io_context &)t.get_executor().context(); -#else - return t.get_io_service(); -#endif -} - -#endif
View file
ncmpc-0.36.tar.xz/src/AsioServiceFwd.hxx
Deleted
@@ -1,42 +0,0 @@ -/* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org - * - * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef NCMPC_ASIO_SERVICE_FWD_HXX -#define NCMPC_ASIO_SERVICE_FWD_HXX - -/* This header provides a forward declaration for - boost::asio::io_service */ - -#include <boost/version.hpp> - -#if BOOST_VERSION >= 106600 - -/* in Boost 1.66, the API has changed for "Networking TS - compatibility"; the forward declaration above doesn't work because - boost::asio::io_service is a deprecated typedef to - boost::asio::io_context; eventually, we'll switch to the new API, - but this would require dropping support for older Boost versions */ - -#include <boost/asio/io_service.hpp> // IWYU pragma: export - -#else -namespace boost { namespace asio { class io_service; }} -#endif - -#endif
View file
ncmpc-0.36.tar.xz/src/UserInput.cxx
Deleted
@@ -1,28 +0,0 @@ -/* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org - * - * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "UserInput.hxx" - -#include <unistd.h> - -UserInput::UserInput(boost::asio::io_service &io_service) - :d(io_service) -{ - d.assign(STDIN_FILENO); -}
View file
ncmpc-0.36.tar.xz/src/UserInput.hxx
Deleted
@@ -1,45 +0,0 @@ -/* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org - * - * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef USER_INPUT_HXX -#define USER_INPUT_HXX - -#include "AsioServiceFwd.hxx" -#include "AsioGetIoService.hxx" - -#include <boost/asio/posix/stream_descriptor.hpp> - -class UserInput { - boost::asio::posix::stream_descriptor d; - -public: - explicit UserInput(boost::asio::io_service &io_service); - - auto &get_io_context() noexcept { - return ::get_io_service(d); - } - - template<typename F> - void AsyncWait(F &&f) noexcept { - d.async_read_some(boost::asio::null_buffers(), - std::forward<F>(f)); - } -}; - -#endif
View file
ncmpc-0.36.tar.xz/src/lyrics.cxx
Deleted
@@ -1,42 +0,0 @@ -/* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org - * - * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "lyrics.hxx" -#include "plugin.hxx" -#include "config.h" - -static PluginList plugins; - -void lyrics_init() -{ - plugins = plugin_list_load_directory(LYRICS_PLUGIN_DIR); -} - -PluginCycle * -lyrics_load(boost::asio::io_service &io_service, - const char *artist, const char *title, - PluginResponseHandler &handler) -{ - assert(artist != nullptr); - assert(title != nullptr); - - const char *args3 = { artist, title, nullptr }; - - return plugin_run(io_service, &plugins, args, handler); -}
View file
ncmpc-0.36.tar.xz/src/lyrics.hxx
Deleted
@@ -1,35 +0,0 @@ -/* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org - * - * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef LYRICS_H -#define LYRICS_H - -#include "AsioServiceFwd.hxx" - -struct PluginCycle; -class PluginResponseHandler; - -void lyrics_init(); - -PluginCycle * -lyrics_load(boost::asio::io_service &io_service, - const char *artist, const char *title, - PluginResponseHandler &handler); - -#endif
View file
ncmpc-0.36.tar.xz/src/net/AsyncConnect.cxx
Deleted
@@ -1,55 +0,0 @@ -/* ncmpc (Ncurses MPD Client) - (c) 2004-2019 The Music Player Daemon Project - Project homepage: http://musicpd.org - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "AsyncConnect.hxx" -#include "AsyncHandler.hxx" - -void -AsyncConnect::OnConnected(const boost::system::error_code &error) noexcept -{ - if (error) { - if (error == boost::asio::error::operation_aborted) - /* this object has already been deleted; bail out - quickly without touching anything */ - return; - - socket.close(); - handler.OnConnectError(error.message().c_str()); - return; - } - - handler.OnConnect(std::move(socket)); -} - -void -AsyncConnect::Start(const boost::asio::ip::tcp::endpoint &endpoint) noexcept -{ - socket.async_connect(endpoint, - std::bind(&AsyncConnect::OnConnected, this, - std::placeholders::_1)); -}
View file
ncmpc-0.36.tar.xz/src/net/AsyncConnect.hxx
Deleted
@@ -1,58 +0,0 @@ -/* ncmpc (Ncurses MPD Client) - (c) 2004-2019 The Music Player Daemon Project - Project homepage: http://musicpd.org - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef NET_ASYNC_CONNECT_HXX -#define NET_ASYNC_CONNECT_HXX - -#include "AsioServiceFwd.hxx" - -#include <boost/asio/ip/tcp.hpp> - -class AsyncConnectHandler; - -class AsyncConnect { - AsyncConnectHandler &handler; - - boost::asio::ip::tcp::socket socket; - -public: - AsyncConnect(boost::asio::io_service &io_service, - AsyncConnectHandler &_handler) noexcept - :handler(_handler), - socket(io_service) {} - - /** - * Create a socket and connect it to the given address. - */ - void Start(const boost::asio::ip::tcp::endpoint &endpoint) noexcept; - -private: - void OnConnected(const boost::system::error_code &error) noexcept; -}; - -#endif
View file
ncmpc-0.36.tar.xz/src/net/AsyncHandler.hxx
Deleted
@@ -1,40 +0,0 @@ -/* ncmpc (Ncurses MPD Client) - (c) 2004-2019 The Music Player Daemon Project - Project homepage: http://musicpd.org - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef NET_ASYNC_HANDLER_HXX -#define NET_ASYNC_HANDLER_HXX - -#include <boost/asio/generic/stream_protocol.hpp> - -class AsyncConnectHandler { -public: - virtual void OnConnect(boost::asio::generic::stream_protocol::socket socket) = 0; - virtual void OnConnectError(const char *message) = 0; -}; - -#endif
View file
ncmpc-0.36.tar.xz/src/util/ConstBuffer.hxx
Deleted
@@ -1,307 +0,0 @@ -/* - * Copyright (C) 2013-2017 Max Kellermann <max.kellermann@gmail.com> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CONST_BUFFER_HXX -#define CONST_BUFFER_HXX - -#include "Compiler.h" - -#include <cstddef> - -#ifndef NDEBUG -#include <assert.h> -#endif - -template<typename T> -struct ConstBuffer; - -template<> -struct ConstBuffer<void> { - typedef size_t size_type; - typedef void value_type; - typedef const void *pointer_type; - typedef pointer_type const_pointer_type; - typedef pointer_type iterator; - typedef pointer_type const_iterator; - - pointer_type data; - size_type size; - - ConstBuffer() = default; - - constexpr ConstBuffer(std::nullptr_t):data(nullptr), size(0) {} - - constexpr ConstBuffer(pointer_type _data, size_type _size) - :data(_data), size(_size) {} - - constexpr static ConstBuffer<void> FromVoid(ConstBuffer<void> other) { - return other; - } - - constexpr ConstBuffer<void> ToVoid() const { - return *this; - } - - constexpr bool IsNull() const { - return data == nullptr; - } - - constexpr bool operator==(std::nullptr_t) const { - return data == nullptr; - } - - constexpr bool operator!=(std::nullptr_t) const { - return data != nullptr; - } - - constexpr bool empty() const { - return size == 0; - } -}; - -/** - * A reference to a memory area that is read-only. - */ -template<typename T> -struct ConstBuffer { - typedef size_t size_type; - typedef T value_type; - typedef const T &reference_type; - typedef reference_type const_reference_type; - typedef const T *pointer_type; - typedef pointer_type const_pointer_type; - typedef pointer_type iterator; - typedef pointer_type const_iterator; - - pointer_type data; - size_type size; - - ConstBuffer() = default; - - constexpr ConstBuffer(std::nullptr_t):data(nullptr), size(0) {} - - constexpr ConstBuffer(pointer_type _data, size_type _size) - :data(_data), size(_size) {} - - constexpr ConstBuffer(pointer_type _data, pointer_type _end) - :data(_data), size(_end - _data) {} - - /** - * Convert array to ConstBuffer instance. - */ - template<size_type _size> - constexpr ConstBuffer(const T (&_data)_size) - :data(_data), size(_size) {} - - /** - * Cast a ConstBuffer<void> to a ConstBuffer<T>, rounding down - * to the next multiple of T's size. - */ - static constexpr ConstBuffer<T> FromVoidFloor(ConstBuffer<void> other) { - static_assert(sizeof(T) > 0, "Empty base type"); - return ConstBuffer<T>(pointer_type(other.data), - other.size / sizeof(T)); - } - - /** - * Cast a ConstBuffer<void> to a ConstBuffer<T>. A "void" - * buffer records its size in bytes, and when casting to "T", - * the assertion below ensures that the size is a multiple of - * sizeof(T). - */ -#ifdef NDEBUG - constexpr -#endif - static ConstBuffer<T> FromVoid(ConstBuffer<void> other) { - static_assert(sizeof(T) > 0, "Empty base type"); -#ifndef NDEBUG - assert(other.size % sizeof(T) == 0); -#endif - return FromVoidFloor(other); - } - - constexpr ConstBuffer<void> ToVoid() const { - static_assert(sizeof(T) > 0, "Empty base type"); - return ConstBuffer<void>(data, size * sizeof(T)); - } - - constexpr bool IsNull() const { - return data == nullptr; - } - - constexpr bool operator==(std::nullptr_t) const { - return data == nullptr; - } - - constexpr bool operator!=(std::nullptr_t) const { - return data != nullptr; - } - - constexpr bool empty() const { - return size == 0; - } - - template<typename U> - gcc_pure - bool Contains(U &&u) const noexcept { - for (const auto &i : *this) - if (u == i) - return true; - - return false; - } - - constexpr iterator begin() const { - return data; - } - - constexpr iterator end() const { - return data + size; - } - - constexpr const_iterator cbegin() const { - return data; - } - - constexpr const_iterator cend() const { - return data + size; - } - -#ifdef NDEBUG - constexpr -#endif - reference_type operator(size_type i) const { -#ifndef NDEBUG - assert(i < size); -#endif - - return datai; - } - - /** - * Returns a reference to the first element. Buffer must not - * be empty. - */ -#ifdef NDEBUG - constexpr -#endif - reference_type front() const { -#ifndef NDEBUG - assert(!empty()); -#endif - return data0; - } - - /** - * Returns a reference to the last element. Buffer must not - * be empty. - */ -#ifdef NDEBUG - constexpr -#endif - reference_type back() const { -#ifndef NDEBUG - assert(!empty()); -#endif - return datasize - 1; - } - - /** - * Remove the first element (by moving the head pointer, does - * not actually modify the buffer). Buffer must not be empty. - */ - void pop_front() { -#ifndef NDEBUG - assert(!empty()); -#endif - - ++data; - --size; - } - - /** - * Remove the last element (by moving the tail pointer, does - * not actually modify the buffer). Buffer must not be empty. - */ - void pop_back() { -#ifndef NDEBUG - assert(!empty()); -#endif - - --size; - } - - /** - * Remove the first element and return a reference to it. - * Buffer must not be empty. - */ - reference_type shift() { - reference_type result = front(); - pop_front(); - return result; - } - - void skip_front(size_type n) { -#ifndef NDEBUG - assert(size >= n); -#endif - - data += n; - size -= n; - } - - /** - * Move the front pointer to the given address, and adjust the - * size attribute to retain the old end address. - */ - void MoveFront(pointer_type new_data) { -#ifndef NDEBUG - assert(IsNull() == (new_data == nullptr)); - assert(new_data <= end()); -#endif - - size = end() - new_data; - data = new_data; - } - - /** - * Move the end pointer to the given address (by adjusting the - * size). - */ - void SetEnd(pointer_type new_end) { -#ifndef NDEBUG - assert(IsNull() == (new_end == nullptr)); - assert(new_end >= begin()); -#endif - - size = new_end - data; - } -}; - -#endif
View file
ncmpc-0.36.tar.xz/src/util/Macros.hxx
Deleted
@@ -1,35 +0,0 @@ -/* - * Copyright (C) 2010-2013 Max Kellermann <max.kellermann@gmail.com> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef MACROS_HPP -#define MACROS_HPP - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x0)) - -#endif
View file
ncmpc-0.36.tar.xz/src/util/StringView.cxx
Deleted
@@ -1,53 +0,0 @@ -/* - * Copyright (C) 2013-2015 Max Kellermann <max.kellermann@gmail.com> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "StringView.hxx" -#include "CharUtil.hxx" - -template<typename T> -void -BasicStringView<T>::StripLeft() noexcept -{ - while (!empty() && IsWhitespaceOrNull(front())) - pop_front(); -} - -template<typename T> -void -BasicStringView<T>::StripRight() noexcept -{ - while (!empty() && IsWhitespaceOrNull(back())) - pop_back(); -} - -template struct BasicStringView<char>; - -#ifdef _UNICODE -template struct BasicStringView<wchar_t>; -#endif
View file
ncmpc-0.36.tar.xz/src/util/StringView.hxx
Deleted
@@ -1,209 +0,0 @@ -/* - * Copyright 2013-2019 Max Kellermann <max.kellermann@gmail.com> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef STRING_VIEW_HXX -#define STRING_VIEW_HXX - -#include "ConstBuffer.hxx" -#include "StringAPI.hxx" -#include "Compiler.h" - -#include <utility> - -#if __cplusplus >= 201703L && !GCC_OLDER_THAN(7,0) -#include <string_view> -#endif - -template<typename T> -struct BasicStringView : ConstBuffer<T> { - typedef typename ConstBuffer<T>::size_type size_type; - typedef typename ConstBuffer<T>::value_type value_type; - typedef typename ConstBuffer<T>::pointer_type pointer_type; - - using ConstBuffer<T>::data; - using ConstBuffer<T>::size; - - BasicStringView() = default; - - explicit constexpr BasicStringView(ConstBuffer<T> src) - :ConstBuffer<T>(src) {} - - explicit constexpr BasicStringView(ConstBuffer<void> src) - :ConstBuffer<T>(ConstBuffer<T>::FromVoid(src)) {} - - constexpr BasicStringView(pointer_type _data, size_type _size) noexcept - :ConstBuffer<T>(_data, _size) {} - - constexpr BasicStringView(pointer_type _begin, - pointer_type _end) noexcept - :ConstBuffer<T>(_begin, _end - _begin) {} - - BasicStringView(pointer_type _data) noexcept - :ConstBuffer<T>(_data, - _data != nullptr ? StringLength(_data) : 0) {} - - constexpr BasicStringView(std::nullptr_t n) noexcept - :ConstBuffer<T>(n) {} - -#if __cplusplus >= 201703L && !GCC_OLDER_THAN(7,0) - constexpr BasicStringView(std::basic_string_view<T> src) noexcept - :ConstBuffer<T>(src.data(), src.size()) {} - - constexpr operator std::basic_string_view<T>() const noexcept { - return {data, size}; - } -#endif - - using ConstBuffer<T>::empty; - using ConstBuffer<T>::begin; - using ConstBuffer<T>::end; - using ConstBuffer<T>::front; - using ConstBuffer<T>::back; - using ConstBuffer<T>::pop_front; - using ConstBuffer<T>::pop_back; - using ConstBuffer<T>::skip_front; - - gcc_pure - pointer_type Find(value_type ch) const noexcept { - return StringFind(data, ch, this->size); - } - - gcc_pure - pointer_type FindLast(value_type ch) const noexcept { - return StringFindLast(data, ch, size); - } - - /** - * Split the string at the first occurrence of the given - * character. If the character is not found, then the first - * value is the whole string and the second value is nullptr. - */ - gcc_pure - std::pair<BasicStringView<T>, BasicStringView<T>> Split(value_type ch) const noexcept { - const auto separator = Find(ch); - if (separator == nullptr) - return {*this, nullptr}; - - return {{begin(), separator}, {separator + 1, end()}}; - } - - gcc_pure - bool StartsWith(BasicStringView<T> needle) const noexcept { - return this->size >= needle.size && - StringIsEqual(data, needle.data, needle.size); - } - - gcc_pure - bool EndsWith(BasicStringView<T> needle) const noexcept { - return this->size >= needle.size && - StringIsEqual(data + this->size - needle.size, - needle.data, needle.size); - } - - gcc_pure - int Compare(BasicStringView<T> other) const noexcept { - if (size < other.size) { - int result = StringCompare(data, other.data, size); - if (result == 0) - result = -1; - return result; - } else if (size > other.size) { - int result = StringCompare(data, other.data, - other.size); - if (result == 0) - result = 1; - return result; - } else - return StringCompare(data, other.data, size); - } - - gcc_pure - bool Equals(BasicStringView<T> other) const noexcept { - return this->size == other.size && - StringIsEqual(data, other.data, this->size); - } - - gcc_pure - bool StartsWithIgnoreCase(BasicStringView<T> needle) const noexcept { - return this->size >= needle.size && - StringIsEqualIgnoreCase(data, needle.data, needle.size); - } - - gcc_pure - bool EndsWithIgnoreCase(BasicStringView<T> needle) const noexcept { - return this->size >= needle.size && - StringIsEqualIgnoreCase(data + this->size - needle.size, - needle.data, needle.size); - } - - gcc_pure - bool EqualsIgnoreCase(BasicStringView<T> other) const noexcept { - return this->size == other.size && - StringIsEqualIgnoreCase(data, other.data, this->size); - } - - /** - * Skip all whitespace at the beginning. - */ - void StripLeft() noexcept; - - /** - * Skip all whitespace at the end. - */ - void StripRight() noexcept; - - void Strip() noexcept { - StripLeft(); - StripRight(); - } - - bool SkipPrefix(BasicStringView<T> needle) noexcept { - bool match = StartsWith(needle); - if (match) - skip_front(needle.size); - return match; - } - - bool RemoveSuffix(BasicStringView<T> needle) noexcept { - bool match = EndsWith(needle); - if (match) - size -= needle.size; - return match; - } -}; - -struct StringView : BasicStringView<char> { - using BasicStringView::BasicStringView; - - StringView() = default; - constexpr StringView(BasicStringView<value_type> src) noexcept - :BasicStringView(src) {} -}; - -#endif
View file
ncmpc-0.47.tar.xz/.github
Added
+(directory)
View file
ncmpc-0.47.tar.xz/.github/dependabot.yml
Added
@@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly"
View file
ncmpc-0.47.tar.xz/.github/workflows
Added
+(directory)
View file
ncmpc-0.47.tar.xz/.github/workflows/build.yml
Added
@@ -0,0 +1,82 @@ +--- +on: + workflow_dispatch: + push: + paths-ignore: + - 'doc/**' + - 'lyrics/**' + - 'po/**' + branches: + - master + pull_request: + paths-ignore: + - 'doc/**' + - 'lyrics/**' + - 'po/**' + branches: + - master + +jobs: + build-linux: + runs-on: ubuntu-latest + steps: + - id: checkout + uses: actions/checkout@v3 + + - id: cache-ccache + uses: hendrikmuhs/ccache-action@v1 + with: + key: linux + + - name: Install dependencies + run: | + sudo apt-get install -y --no-install-recommends \ + meson \ + libncursesw5-dev \ + libncurses5-dev \ + libpcre2-dev \ + libmpdclient-dev + + - name: Full Build + uses: BSFishy/meson-build@v1.0.3 + with: + action: build + directory: output/full + setup-options: -Ddocumentation=disabled -Dlyrics_screen=true -Dchat_screen=true + + - name: Mini Build + uses: BSFishy/meson-build@v1.0.3 + with: + action: build + directory: output/mini + setup-options: -Ddocumentation=disabled -Dbuildtype=minsize -Db_ndebug=true -Db_lto=true -Dauto_features=disabled -Dcurses=ncurses -Dcolors=false -Dmultibyte=false -Dtcp=false -Dasync_connect=false -Dmini=true + + build-macos: + runs-on: macos-latest + steps: + - id: checkout + uses: actions/checkout@v3 + + - id: cache-ccache + uses: hendrikmuhs/ccache-action@v1 + with: + key: macos + + - uses: actions/setup-python@v4 + with: + python-version: 3.x + + - name: Install dependencies + run: | + brew install \ + meson ninja \ + ncurses \ + pcre2 \ + libmpdclient + + - name: Meson Build + uses: BSFishy/meson-build@v1.0.3 + with: + action: build + directory: output + setup-options: -Ddocumentation=disabled -Dlyrics_screen=true -Dchat_screen=true
View file
ncmpc-0.36.tar.xz/.gitignore -> ncmpc-0.47.tar.xz/.gitignore
Changed
@@ -2,3 +2,6 @@ *~ /output/ + +/.clangd/ +/compile_commands.json
View file
ncmpc-0.36.tar.xz/NEWS -> ncmpc-0.47.tar.xz/NEWS
Changed
@@ -1,3 +1,76 @@ +ncmpc 0.47 - (2022-06-30) +* handle Ctrl-C in search prompt +* link with libintl and libiconv if necessary +* require libmpdclient 2.16 or newer +* require MPD 0.21 or newer +* switch to C++20 + +ncmpc 0.46 - (2021-11-26) +* eliminate Boost dependency +* install Lithuanian translation +* migrate to PCRE2 + +ncmpc 0.45 - (2021-02-12) +* make "tagtypes" errors non-fatal +* check which tag types are supported by MPD (fixes MPD 0.21 support) +* lyrics: update page title after loading has finished +* lyrics: fix path injection bug +* lyrics: load cached lyrics without plugin +* lyrics: use $XDG_CACHE_HOME/ncmpc/lyrics instead of ~/.lyrics +* lyrics/azlyrics: normalize accented letters (using the "unidecode" library) +* lyrics/azlyrics: unescape HTML entities + +ncmpc 0.44 - (2021-02-01) +* fix scrolling problems on help page +* highlight find results on help page +* don't attempt IPv6 connection if IPv6 routing is disabled + +ncmpc 0.43 - (2021-01-27) +* support MPD 0.22 tags "conductor", "work", "grouping" (requires + libmpdclient 2.17) +* show "conductor" and "work" on song page +* playlist editor (work in progress) +* file page: handle mouse double clicks +* fix crash bug +* fix build failure on macOS +* add azlyrics plugin + +ncmpc 0.42 - (2020-10-28) +* file page: repaint after moving cursor with mouse +* file page: handle mouse click on directory +* library page: mouse support +* support the mouse wheel +* fix assertion failure on exit + +ncmpc 0.41 - (2020-10-16) +* new main loop (copying code from MPD, replacing boost::asio) +* library page: fix crash bug +* lyrics: remove the "lyricwiki" plugin because the site is gone + +ncmpc 0.40 - (2020-10-07) +* fix crash when range selection includes ".." +* fix another crash with a very narrow terminal window +* another jumping cursor fix for large scroll-offset values +* show elapsed time of streams + +ncmpc 0.39 - (2020-08-21) +* library page: skip tags when there is only one value +* fix jumping cursor with large scroll-offset values +* key bindigs page: fix crash bug +* key bindigs page: eliminate bogus message "Did you forget to Apply your changes?" + +ncmpc 0.38 - (2020-04-30) +* add option "timedisplay-type=none" to hide current song time +* fix use-after-free bug +* fix crash after entering empty password + +ncmpc 0.37 - (2020-01-24) +* show performer on song page +* show partitions on outputs page (requires libmpdclient 2.18) +* search: add search tag "modified" (requires libmpdclient 2.10) +* fix compatibility with MPD versions older than 0.21 +* switch to C++17 + ncmpc 0.36 - (2019-11-05) * screen_keydef: show "Add new key" only if there is room for more keys * support the Alt modifier in hotkeys
View file
ncmpc-0.36.tar.xz/README.rst -> ncmpc-0.47.tar.xz/README.rst
Changed
@@ -13,9 +13,8 @@ You need: -- a C++14 compliant compiler (e.g. gcc or clang) -- `libmpdclient <https://www.musicpd.org/libs/libmpdclient/>`__ 2.9 -- `Boost 1.62 <https://www.boost.org/>`__ +- a C++17 compliant compiler (e.g. gcc or clang) +- `libmpdclient <https://www.musicpd.org/libs/libmpdclient/>`__ 2.16 - `ncurses <https://www.gnu.org/software/ncurses/>`__ - `Meson 0.47 <http://mesonbuild.com/>`__ and `Ninja <https://ninja-build.org/>`__ @@ -30,7 +29,7 @@ Run ``meson``:: - meson . output + meson . output --buildtype=debugoptimized -Db_ndebug=true Compile and install::
View file
ncmpc-0.36.tar.xz/doc/conf.py -> ncmpc-0.47.tar.xz/doc/conf.py
Changed
@@ -30,7 +30,7 @@ # General information about the project. project = 'ncmpc' -copyright = 'Copyright (C) 2004-2019 The Music Player Daemon Project' +copyright = 'Copyright 2004-2021 The Music Player Daemon Project' author = 'Max Kellermann' # The version info for the project you're documenting, acts as replacement for @@ -38,7 +38,7 @@ # built documents. # # The short X.Y version. -version = '0.36' +version = '0.47' # The full version, including alpha/beta/rc tags. release = version
View file
ncmpc-0.36.tar.xz/doc/config.sample -> ncmpc-0.47.tar.xz/doc/config.sample
Changed
@@ -35,6 +35,9 @@ ## Auto center (center the playing track in the playlist) #auto-center = no +## Keep at least NUM lines above and below the cursor on list windows, if possible. +#scroll-offset = 0 + ## Show the most recent query when using find. #find-show-last = no @@ -59,6 +62,9 @@ ## Seek forward/backward by NUM seconds. #seek-time = 1 +## Quits downloading lyrics of a song after the timeout of NUM seconds is reached, if NUM is greater than zero. +#lyrics-timeout = 60 + ############## Display ###################### ## Show a list of the screens in the top line. #welcome-screen-list = yes @@ -107,6 +113,9 @@ ## Automatically save the lyrics after receiving them. #lyrics-autosave = no +## Show the name of the plugin used to receive lyrics on the lyrics screen. +#lyrics-show-plugin = no + ## The text editor used for editing lyrics. #text-editor = emacs
View file
ncmpc-0.36.tar.xz/doc/index.rst -> ncmpc-0.47.tar.xz/doc/index.rst
Changed
@@ -110,9 +110,15 @@ :command:`enable-mouse = yes|no` - Enable mouse support (if enabled at compile time). :command:`screen-list = SCREEN1 SCREEN2...` - A list of screens to -cycle through when using the previous/next screen commands. Valid -choices, if enabled at compile time, are playlist, browse, library, -help, search, song, keydef, lyrics, outputs, and chat. +cycle through when using the commands :command:`screen-next` (bound to +"Tab" by default) and :command:`screen-prev` ("Shift+Tab"). Valid +choices, if enabled at compile time, are: + + ``help``, ``playlist``, ``browse``, ``library``, ``search``, + ``lyrics``, ``outputs``, ``chat``, ``song``, ``keydef`` + +The default is ``playlist browser``, i.e. the "Tab" key cycles only +between those two pages. :command:`library-page-tags = TAG1 TAG2 ...` - A list of tags to group the library page. The default is ``artist album``. @@ -166,7 +172,7 @@ :command:`chat-prefix = PREFIX` - Prefix messages send with the chat screen with PREFIX. By default they are prefixed with the current -user name enclosed by "<" and ">" and a space (i.e. "<name> "). +user name enclosed by ``<`` and ``>`` and a space (i.e. "<name> "). :command:`second-column = yes|no` - Display song length in a second column. @@ -208,9 +214,9 @@ :command:`display-time = yes|no` - Display the time in the status bar when idle. -:command:`timedisplay-type = elapsed/remaining` - Sets whether to +:command:`timedisplay-type = elapsed|remaining|none` - Sets whether to display remaining or elapsed time in the status window. Default is -elapsed. +elapsed. ``none`` doesn't show the time at all. :command:`visible-bitrate = yes|no` - Show the bitrate in the status bar when playing a stream. @@ -339,15 +345,16 @@ ----------- Format of song display for status and the list window. The metadata -delimiters are: %artist%, %albumartist%, %composer%, %performer%, -%title%, %album%, %shortalbum%, %track%, %disc, %genre%, %name%, -%time%, %date%, %file%, %shortfile%. - -The operators are used to group output such that if none of the -metadata delimiters between '' and '' are matched, then none of the -characters between '' and '' are output; literal text is always -output. '&' and '|' are logical operators for AND and OR. '#' is used -to escape characters. +delimiters are: ``%artist%``, ``%albumartist%``, ``%composer%``, +``%performer%``, ``%title%``, ``%album%``, ``%shortalbum%``, +``%track%``, ``%disc``, ``%genre%``, ``%name%``, ``%time%``, +``%date%``, ``%file%``, ``%shortfile%``. + +The ```` operators are used to group output such that if none of the +metadata delimiters between ```` and ```` are matched, then none of +the characters between ```` and ```` are output; literal text is +always output. ``&`` and ``|`` are logical operators for *and* and +*or*. ``#`` is used to escape characters. Some useful examples for format are::
View file
ncmpc-0.36.tar.xz/doc/meson.build -> ncmpc-0.47.tar.xz/doc/meson.build
Changed
@@ -1,3 +1,7 @@ +if not get_option('html_manual') and not get_option('manual') + subdir_done() +endif + sphinx = find_program('sphinx-build', required: get_option('documentation')) if not sphinx.found() subdir_done() @@ -20,7 +24,8 @@ output: 'upload', build_always_stale: true, command: - 'rsync', '-vpruz', '--delete', '@INPUT@', + find_program('rsync', required: false, disabler: true) + , '-vpruz', '--delete', '@INPUT@', 'www.musicpd.org:/var/www/mpd/doc/ncmpc/', '--chmod=a+rX', ,
View file
ncmpc-0.47.tar.xz/lyrics/20-azlyrics.py
Added
@@ -0,0 +1,88 @@ +#!/usr/bin/python3 +# +# Copyright 2004-2021 The Music Player Daemon Project +# http://www.musicpd.org/ +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +# +# Load lyrics from azlyrics.com if lyrics weren't found in the lyrics directory +# +import re +import sys +import urllib.request + +import requests +import html + +try: + # using the "unidecode" library if installed + # (https://pypi.org/project/Unidecode/ or package + # "python3-unidecode" on Debian) + from unidecode import unidecode +except ImportError: + # Dummy fallback (don't crash if "unidecode" is not installed) + def unidecode(s): + return s + + +def normalize_parameter(s): + return unidecode(s).lower() + + +def html_elements_to_text(s): + return ( + s.replace("<br>", "") + .replace("<i>", "") + .replace("</i>", "") + .replace("<b>", "") + .replace("</b>", "") + .replace("<div>", "") + .replace("</div>", "") + ) + + +def html_to_text(s): + return html.unescape(html_elements_to_text(s)) + + +artists = normalize_parameter(sys.argv1) +title = normalize_parameter(sys.argv2) +artists = artist.removeprefix("the ") for artist in artists.split(",") +artists = re.sub("^A-Za-z0-9+", "", artist) for artist in artists +title = re.sub("\(.*\)", "", title) +title = re.sub("^A-Za-z0-9+", "", title) + +for artist in artists: + url = "http://azlyrics.com/lyrics/" + artist + "/" + title + ".html" + + try: + r = urllib.request.urlopen(url) + response = r.read().decode() + start = response.find("that. -->") + end = response.find("<!-- MxM") + lyrics = responsestart + 9 : end + lyrics = html_to_text(lyrics).strip() + print(lyrics) + exit(0) + except urllib.error.HTTPError: + if artist is artists-1: + print("Lyrics not found :(", file=sys.stderr) + exit(1) + except Exception as e: + if artist is artists-1: + print("Unknown error: ", e, file=sys.stderr) + exit(2)
View file
ncmpc-0.47.tar.xz/lyrics/30-karaoke_texty.py
Added
@@ -0,0 +1,83 @@ +#!/usr/bin/python3 +# +# Copyright 2004-2021 The Music Player Daemon Project +# http://www.musicpd.org/ +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +# +# Load lyrics from karaoketexty.sk if lyrics weren't found in the lyrics directory +# +import bs4 +import re +import requests +import sys + +try: + # using the "unidecode" library if installed + # (https://pypi.org/project/Unidecode/ or package + # "python3-unidecode" on Debian) + from unidecode import unidecode +except ImportError: + # Dummy fallback (don't crash if "unidecode" is not installed) + def unidecode(s): + return s + + +def normalize_parameter(s): + return unidecode(s).lower() + + +base_url = "https://www.karaoketexty.sk" +artists = normalize_parameter(sys.argv1) +title = normalize_parameter(sys.argv2) +artists = artist.removeprefix("the ") for artist in artists.split(",") + +title = re.sub("\(.*\)", "", title) + +for artist in artists: + r = requests.get(f"{base_url}/search?sid=outxq&q={title}") + r.raise_for_status() + soup = bs4.BeautifulSoup(r.text, "html5lib") + results = soup.findAll(attrs={"class": "h2_search"})1 + matches = + x.a for x in results.findAllNext("span", attrs={"class": "searchresrow_songs"}) + + matches = + x for x in matches if f"{artist} - {title}" == normalize_parameter(x.text) + + if not matches: + print("Lyrics not found :(", file=sys.stderr) + exit(1) + + # first match is a good match + song_url = f'{base_url}{matches0.get("href")}' + r = requests.get(song_url) + r.raise_for_status() + soup = bs4.BeautifulSoup(r.text, "html5lib") + lyrics_block = soup.find(attrs={"class": "lyrics_cont"}).findAll( + attrs={"class": "para_row"} + ) + lyrics_paragraphs = x.findAll("span") for x in lyrics_block + lyrics = "".join( + + x.text + for x in soup.find(attrs={"class": "lyrics_cont"}).findAll( + attrs={"class": "para_row"} + ) + + ) + print("\n".join("\n".join(x.text for x in x) for x in lyrics_paragraphs))
View file
ncmpc-0.47.tar.xz/lyrics/40-tekstowo.py
Added
@@ -0,0 +1,71 @@ +#!/usr/bin/python3 +# +# Copyright 2004-2021 The Music Player Daemon Project +# http://www.musicpd.org/ +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +# +# Load lyrics from tekstowo.pl if lyrics weren't found in the lyrics directory +# +import bs4 +import re +import requests +import sys + +try: + # using the "unidecode" library if installed + # (https://pypi.org/project/Unidecode/ or package + # "python3-unidecode" on Debian) + from unidecode import unidecode +except ImportError: + # Dummy fallback (don't crash if "unidecode" is not installed) + def unidecode(s): + return s + + +def normalize_parameter(s): + return unidecode(s).lower() + + +artists = normalize_parameter(sys.argv1) +title = normalize_parameter(sys.argv2) +artists = artist.removeprefix("the ") for artist in artists.split(",") + +title = re.sub("\(.*\)", "", title) + +for artist in artists: + r = requests.get( + f"https://www.tekstowo.pl/wyszukaj.html?search-artist={artist}&search-title={title}" + ) + r.raise_for_status() + soup = bs4.BeautifulSoup(r.text, "html5lib") + results = soup.find(attrs={"class": "card-body p-0"}).select("a") + matches = + x + for x in results + if re.search(title, normalize_parameter(x.text).split(" - ")1) + + if not matches: + print("Lyrics not found :(", file=sys.stderr) + exit(1) + + # first match is a good match + song_url = f'https://www.tekstowo.pl{matches0.get("href")}' + r = requests.get(song_url) + r.raise_for_status() + soup = bs4.BeautifulSoup(r.text, "lxml") + print(soup.select_one("#songText .inner-text").text)
View file
ncmpc-0.47.tar.xz/lyrics/50-genius.py
Added
@@ -0,0 +1,69 @@ +#!/usr/bin/python3 +# +# Copyright 2004-2021 The Music Player Daemon Project +# http://www.musicpd.org/ +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +# +# Load lyrics from genius.com if lyrics weren't found in the lyrics directory +# +import bs4 +import re +import requests +import sys + +try: + # using the "unidecode" library if installed + # (https://pypi.org/project/Unidecode/ or package + # "python3-unidecode" on Debian) + from unidecode import unidecode +except ImportError: + # Dummy fallback (don't crash if "unidecode" is not installed) + def unidecode(s): + return s + + +def normalize_parameter(s): + return unidecode(s).lower() + + +base_url = "https://genius.com/" +artists = normalize_parameter(sys.argv1) +title = normalize_parameter(sys.argv2) +artists = artist for artist in artists.split(",") + +title = re.sub("\(.*\)", "", title) + +for artist in artists: + title = title.replace(" ", "-").replace("'", "") + artist = artist.replace(" ", "-").replace("'", "") + r = requests.get(f"{base_url}{artist}-{title}-lyrics") + try: + r.raise_for_status() + except: + exit(1) + soup = bs4.BeautifulSoup(r.text, "html5lib") + lyrics = + x.getText("\n") for x in soup.find(attrs={"data-lyrics-container": "true"}) + + print( + re.sub( + r"\n\n+", + "\n", + "".join(x.replace("", "\n") if not x else x for x in lyrics), + ) + )
View file
ncmpc-0.47.tar.xz/lyrics/51-supermusic.py
Added
@@ -0,0 +1,90 @@ +#!/usr/bin/python3 +# +# Copyright 2004-2021 The Music Player Daemon Project +# http://www.musicpd.org/ +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +# +# Load lyrics from supermusic.cz if lyrics weren't found in the lyrics directory +# +import re +import sys +import urllib.request + +import requests +import html +import bs4 + +try: + # using the "unidecode" library if installed + # (https://pypi.org/project/Unidecode/ or package + # "python3-unidecode" on Debian) + from unidecode import unidecode +except ImportError: + # Dummy fallback (don't crash if "unidecode" is not installed) + def unidecode(s): + return s + + +def normalize_parameter(s): + return unidecode(s).lower() + + +artists = normalize_parameter(sys.argv1) +title = normalize_parameter(sys.argv2) +artists = artist.removeprefix("the ") for artist in artists.split(",") + +title = re.sub("\(.*\)", "", title) +base_url = "https://supermusic.cz/" + +for artist in artists: + r = requests.post( + f"{base_url}najdi.php", + data={"hladane": f'"{title}"', "typhladania": "piesen", "fraza": "off"}, + ) + r.raise_for_status() + soup = bs4.BeautifulSoup(r.text, "html5lib") + results = soup.select(".clanok atarget") + # drop melody, notes and guitar tabs from results + results = + x + for x in results + if "- taby" not in x.nextSibling + and "- melodia" not in x.nextSibling + and "- akordy" not in x.nextSibling + and "- preklad" not in x.nextSibling + and "- noty" not in x.nextSibling + + # filter on artist name + results = x for x in results if normalize_parameter(x.text) == artist + if not results: + print("Lyrics not found :(", file=sys.stderr) + exit(1) + song_url = f'{base_url}{results0"href"}' + song_id = re.search(r"idpiesne=(.*)", song_url).group(1) + r = requests.get(f"{base_url}export.php?idpiesne={song_id}&typ=TXT") + r.raise_for_status() + soup = bs4.BeautifulSoup(r.text, "html5lib") + print( + "".join( + + x.text + for x in soup.select_one('tdvalign="top"') + if x.text != "SŤAHUJ" and x.text + 2: + ) + )
View file
ncmpc-0.47.tar.xz/lyrics/52-zeneszoveg.py
Added
@@ -0,0 +1,108 @@ +#!/usr/bin/python3 +# +# Copyright 2004-2021 The Music Player Daemon Project +# http://www.musicpd.org/ +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +# +# Load lyrics from zeneszoveg.hu if lyrics weren't found in the lyrics directory +# +import re +import sys +import urllib.request + +import requests +import html +import bs4 + +try: + # using the "unidecode" library if installed + # (https://pypi.org/project/Unidecode/ or package + # "python3-unidecode" on Debian) + from unidecode import unidecode +except ImportError: + # Dummy fallback (don't crash if "unidecode" is not installed) + def unidecode(s): + return s + + +def normalize_parameter(s): + return unidecode(s).lower() + + +def get_artist_url(artist): + r = requests.get(f"{base_url}eloadok/{artist0}") + r.raise_for_status() + soup = bs4.BeautifulSoup(r.text, "html5lib") + pages = + x"href" for x in soup.select("div.paginator > a") if len(x.text.strip()) < 3 + + for page in pages: + r = requests.get(f"{base_url}{page}") + soup = bs4.BeautifulSoup(r.text, "html5lib") + match = + x + for x in soup.select(".col2.olist a") + if normalize_parameter(x.text) == artist + + if match: + break + else: + print("Artist not found :(", file=sys.stderr) + exit(1) + return match0.get("href") + + +def get_title_url(artist_url, title): + r = requests.get(f"{base_url}{artist_url}") + r.raise_for_status() + soup = bs4.BeautifulSoup(r.text, "html5lib") + match = + x.select("a")-1"href" + for x in soup.select(".artistRelatedList .search-result h3") + if normalize_parameter(x.text.strip()) == title + + if not match: + print("Song not found :(", file=sys.stderr) + exit(1) + return match0 + + +def get_lyrics(title_url): + r = requests.get(f"{base_url}{title_url}") + r.raise_for_status() + soup = bs4.BeautifulSoup(r.text, "html5lib") + lyrics = soup.select_one("div.lyrics-plain-text") + if not lyrics: + print("Lyrics not found :(", file=sys.stderr) + exit(1) + lyrics = lyrics.text.lstrip() + return lyrics + + +artists = normalize_parameter(sys.argv1) +title = normalize_parameter(sys.argv2) +artists = artist.removeprefix("the ") for artist in artists.split(",") + +title = re.sub("\(.*\)", "", title) +base_url = "https://kulfoldi.zeneszoveg.hu/" + +for artist in artists: + artist_url = get_artist_url(artist) + title_url = get_title_url(artist_url, title) + lyrics = get_lyrics(title_url) + print(lyrics)
View file
ncmpc-0.47.tar.xz/lyrics/60-google.py
Added
@@ -0,0 +1,66 @@ +#!/usr/bin/python3 +# +# Copyright 2004-2021 The Music Player Daemon Project +# http://www.musicpd.org/ +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +# +# Load lyrics from google.com if lyrics weren't found in the lyrics directory +# +import bs4 +import re +import requests +import sys + +try: + # using the "unidecode" library if installed + # (https://pypi.org/project/Unidecode/ or package + # "python3-unidecode" on Debian) + from unidecode import unidecode +except ImportError: + # Dummy fallback (don't crash if "unidecode" is not installed) + def unidecode(s): + return s + + +def normalize_parameter(s): + return unidecode(s).lower() + + +base_url = "http://www.google.com/" +artists = normalize_parameter(sys.argv1) +title = normalize_parameter(sys.argv2) +artists = artist.removeprefix("the ") for artist in artists.split(",") + +title = re.sub("\(.*\)", "", title) + +for artist in artists: + artist = artist.replace(" ", "+") + title = title.replace(" ", "+") + r = requests.get( + f"{base_url}/search?q={artist}+{title}+lyrics", + headers={"client": "google-csbe"}, + ) + try: + r.raise_for_status() + except: + exit(1) + soup = bs4.BeautifulSoup(r.text, "html5lib") + results = x for x in soup.select("div") if len(x.select("div")) == 0 + # element with the longest text node is usually a match + results.sort(key=lambda n: len(n.text)) + print(results-1.text)
View file
ncmpc-0.36.tar.xz/meson.build -> ncmpc-0.47.tar.xz/meson.build
Changed
@@ -1,8 +1,9 @@ project('ncmpc', 'cpp', - version: '0.36', - meson_version: '>= 0.47', + version: '0.47', + meson_version: '>= 0.49', default_options: - 'cpp_std=c++14' + 'cpp_std=c++2a', + 'warning_level=3', , license: 'GPLv2+', ) @@ -31,11 +32,18 @@ conf.set('ENABLE_LOCALE', enable_locale) enable_nls = get_option('nls') -if enable_nls.disabled() or mini +if meson.version().version_compare('>= 0.59') and not mini + # Meson 0.59 has native libintl support + intl_dep = dependency('intl', required: enable_nls) + enable_nls = intl_dep.found() +elif enable_nls.disabled() or mini + intl_dep = dependency('', required: false) enable_nls = false elif cc.has_header('libintl.h') + intl_dep = dependency('', required: false) enable_nls = true elif enable_nls.auto() + intl_dep = dependency('', required: false) enable_nls = false else error('libintl.h not found') @@ -47,7 +55,24 @@ endif conf.set('HAVE_LOCALE_T', enable_locale and cc.has_header_symbol('locale.h', 'locale_t')) -conf.set('HAVE_ICONV', enable_locale and cc.has_function('iconv')) +iconv_dep = dependency('', required: false) +if enable_locale + iconv_open_snippet = '''#include <iconv.h> + int main() { + iconv_open("",""); + }''' + if meson.version().version_compare('>= 0.60') + iconv_dep = dependency('iconv', required: false) + iconv_found = iconv_dep.found() + else + iconv_found = cc.links(iconv_open_snippet, name: 'iconv_open') + if not iconv_found + iconv_dep = cc.find_library('iconv', required: false) + iconv_found = cc.links(iconv_open_snippet, dependencies: iconv_dep, name: 'iconv_open') + endif + endif +endif +conf.set('HAVE_ICONV', enable_locale and iconv_found) async_connect = get_option('async_connect') conf.set('ENABLE_ASYNC_CONNECT', async_connect) @@ -115,60 +140,87 @@ conf.set('ENABLE_COLORS', curses_color and get_option('colors')) -common_cflags = +common_cppflags = # for getaddrinfo() and sigaction() with glibc '-D_GNU_SOURCE', + - # no header bloat for the iostream library we don't use - '-DBOOST_NO_IOSTREAM', - - # avoid the runtime dependency on libboost_system - '-DBOOST_ERROR_CODE_HEADER_ONLY', - - # disable deprecated boost::system features - '-DBOOST_SYSTEM_NO_DEPRECATED', +test_global_common_flags = + '-fvisibility=hidden', -test_cflags = - '-Wall', - '-Wextra', - '-Wno-deprecated-declarations', - '-Wshadow', - '-Wpointer-arith', +test_common_flags = '-Wcast-qual', '-Wcast-align', + '-Wdouble-promotion', + '-Wmissing-declarations', + '-Wmissing-format-attribute', + '-Wmissing-noreturn', + '-Wredundant-decls', + '-Wshadow', + '-Wundef', + '-Wvla', '-Wwrite-strings', - '-Wmissing-declarations', '-Wmissing-noreturn', '-Wmissing-format-attribute', - '-Wredundant-decls', '-Wundef', + + # clang specific warning options: + '-Wunreachable-code-aggressive', + '-Wused-but-marked-unused', + + +test_global_cxxflags = test_global_common_flags + + + +test_cxxflags = test_common_flags + + '-fno-threadsafe-statics', + '-fmerge-all-constants', + + # a vtable without a dtor is just fine '-Wno-non-virtual-dtor', - '-fvisibility=hidden', # the only warnings we got from this are from formatted error # messages, and their truncation is harmless '-Wno-format-truncation', + + # clang specific warning options: + '-Wcomma', + '-Wheader-hygiene', + '-Winconsistent-missing-destructor-override', + + +test_ldflags = if get_option('buildtype') != 'debug' - test_cflags += + test_global_cxxflags += '-ffunction-sections', '-fdata-sections', + test_ldflags += + '-Wl,--gc-sections', + endif -foreach f: test_cflags - if cc.has_argument(f) - common_cflags += f - endif -endforeach +add_global_arguments(common_cppflags, language: 'cpp') +add_global_arguments(cc.get_supported_arguments(test_global_cxxflags), language: 'cpp') +add_project_arguments(cc.get_supported_arguments(test_cxxflags), language: 'cpp') +add_project_link_arguments(cc.get_supported_link_arguments(test_ldflags), language: 'cpp') -add_global_arguments(common_cflags, language: 'cpp') +is_linux = host_machine.system() == 'linux' +is_windows = host_machine.system() == 'windows' thread_dep = dependency('threads') -boost_dep = dependency('boost', version: '>= 1.62') -libmpdclient_dep = dependency('libmpdclient', version: '>= 2.9') +libmpdclient_dep = dependency('libmpdclient', version: '>= 2.16') if not mini - pcre_dep = dependency('libpcre', required: get_option('regex')) + pcre_dep = dependency('libpcre2-8', required: get_option('regex')) + + if pcre_dep.found() + pcre_dep = declare_dependency( + compile_args: '-DPCRE2_CODE_UNIT_WIDTH=0', + dependencies: pcre_dep, + ) + endif + conf.set('HAVE_PCRE', pcre_dep.found()) else pcre_dep = declare_dependency() @@ -211,8 +263,9 @@ if async_connect sources += - 'src/net/AsyncConnect.cxx', + 'src/net/SocketError.cxx', 'src/net/AsyncResolveConnect.cxx', + 'src/event/net/ConnectSocket.cxx', 'src/aconnect.cxx', endif @@ -245,6 +298,12 @@ sources += 'src/SearchPage.cxx' endif +enable_playlist_editor = get_option('playlist_editor') and not mini +conf.set('ENABLE_PLAYLIST_EDITOR', enable_playlist_editor) +if enable_playlist_editor + sources += 'src/EditPlaylistPage.cxx' +endif + enable_song_screen = get_option('song_screen') and not mini conf.set('ENABLE_SONG_SCREEN', enable_song_screen) if enable_song_screen @@ -260,7 +319,11 @@ enable_lyrics_screen = get_option('lyrics_screen') and not mini conf.set('ENABLE_LYRICS_SCREEN', enable_lyrics_screen) if enable_lyrics_screen - sources += 'src/LyricsPage.cxx', 'src/lyrics.cxx' + sources += + 'src/LyricsPage.cxx', + 'src/LyricsLoader.cxx', + 'src/LyricsCache.cxx', + lyrics_plugin_dir = get_option('lyrics_plugin_dir') if lyrics_plugin_dir == '' @@ -269,8 +332,13 @@ conf.set_quoted('LYRICS_PLUGIN_DIR', lyrics_plugin_dir) install_data( - 'lyrics/10-hd.sh', - 'lyrics/20-lyricwiki.rb', + 'lyrics/20-azlyrics.py', + 'lyrics/30-karaoke_texty.py', + 'lyrics/40-tekstowo.py', + 'lyrics/50-genius.py', + 'lyrics/51-supermusic.py', + 'lyrics/52-zeneszoveg.py', + 'lyrics/60-google.py', install_dir: lyrics_plugin_dir) need_screen_text = true @@ -306,6 +374,11 @@ subdir('src/win') endif +subdir('src/io') +subdir('src/system') +subdir('src/net') +subdir('src/event') + ncmpc = executable('ncmpc', 'src/Main.cxx', 'src/Instance.cxx', @@ -318,7 +391,6 @@ 'src/Command.cxx', 'src/Bindings.cxx', 'src/GlobalBindings.cxx', - 'src/UserInput.cxx', 'src/AsyncUserInput.cxx', 'src/KeyName.cxx', 'src/Match.cxx', @@ -355,18 +427,20 @@ 'src/strfsong.cxx', 'src/time_format.cxx', 'src/util/LocaleString.cxx', + 'src/util/Exception.cxx', 'src/util/PrintException.cxx', 'src/util/StringCompare.cxx', 'src/util/StringStrip.cxx', 'src/util/StringUTF8.cxx', - 'src/util/StringView.cxx', 'src/util/UriUtil.cxx', sources, include_directories: inc, dependencies: thread_dep, - boost_dep, + event_dep, pcre_dep, + intl_dep, + iconv_dep, curses_dep, lirc_dep, libmpdclient_dep, @@ -383,7 +457,7 @@ 'doc/ncmpc.lirc', install_dir: docdir) -if not mini +if get_option('test') subdir('test') endif
View file
ncmpc-0.36.tar.xz/meson_options.txt -> ncmpc-0.47.tar.xz/meson_options.txt
Changed
@@ -1,3 +1,7 @@ +option('epoll', type: 'boolean', value: true, description: 'Use epoll on Linux') +option('eventfd', type: 'boolean', value: true, description: 'Use eventfd() on Linux') +option('signalfd', type: 'boolean', value: true, description: 'Use signalfd() on Linux') + option('curses', type: 'combo', choices: 'ncursesw', 'ncurses', 'auto', value: 'auto', @@ -46,6 +50,11 @@ value: true, description: 'Enable the search screen') +# The playlist editor is work in progress, not usable yet. +option('playlist_editor', type: 'boolean', + value: false, + description: 'Enable the playlist editor') + option('song_screen', type: 'boolean', value: true, description: 'Enable the song viewer screen') @@ -80,3 +89,5 @@ option('html_manual', type: 'boolean', value: true, description: 'Build the HTML manual') + +option('test', type: 'boolean', value: false, description: 'Build the unit tests and debug programs')
View file
ncmpc-0.36.tar.xz/po/LINGUAS -> ncmpc-0.47.tar.xz/po/LINGUAS
Changed
@@ -4,18 +4,23 @@ en eo es +fa fi fr gl he hu +ie it +ja +lt ko nb nl ru pl pt_BR +pt sk sv uk
View file
ncmpc-0.36.tar.xz/po/cs.po -> ncmpc-0.47.tar.xz/po/cs.po
Changed
@@ -7,342 +7,346 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2011-03-02 13:59+0000\n" -"Last-Translator: Zbyněk Schwarz <Unknown>\n" -"Language-Team: Czech <cs@li.org>\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2020-02-03 11:50+0000\n" +"Last-Translator: Miroslav Burdych <mirek.burdych@gmail.com>\n" +"Language-Team: Czech <https://hosted.weblate.org/projects/ncmpc/translations/" +"cs/>\n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"X-Generator: Weblate 3.11-dev\n" "X-Launchpad-Export-Date: 2011-06-23 08:56+0000\n" -"X-Generator: Launchpad (build 13265)\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "Klávesa %s je přiřazena k %s a %s" #: src/ChatPage.cxx:64 src/ChatPage.cxx:182 msgid "Chat" -msgstr "" +msgstr "Chat" #: src/ChatPage.cxx:163 msgid "Your message" -msgstr "" +msgstr "Vaše zpráva" #: src/ChatPage.cxx:172 msgid "Message could not be sent" -msgstr "" +msgstr "Zprávu nelze odeslat" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "Obrazovka klávesových zkratek" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Ukončit" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "Posunout kurzor nahoru" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "Posunout kurzoru dolů" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "Přesunout kurzor na horní okraj obrazovky" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "Přesunout kurzor doprostřed obrazovky" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "Přesunout kurzor na dolní okraj obrazovky" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" -msgstr "Přesunout kurzor na vrchol seznamu" +msgstr "Přesunout kurzor na začátek seznamu" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" -msgstr "Přesunout kurzor na dno seznamu" +msgstr "Přesunout kurzor na konec seznamu" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" -msgstr "Page up" +msgstr "O stánku nahoru" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" -msgstr "Page down" +msgstr "O stránku dolů" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "Výběr rozsahu" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "Posunout o jeden řádek dolů" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "Posunout o jeden řádek nahoru" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" -msgstr "Posunout o půlku obrazovky nahoru" +msgstr "Posunout o půl obrazovky nahoru" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" -msgstr "Posunout o půlku obrazovky dolů" +msgstr "Posunout o půl obrazovky dolů" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "Zvolit právě hrající skladbu" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "Obrazovka nápovědy" -#: src/Command.cxx:71 src/HelpPage.cxx:140 -#, fuzzy +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" -msgstr "Obrazovka keydef" +msgstr "Obrazovka prohlížení fronty" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "Obrazovka prohlížení" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "Přehrát/Vstoupit do adresáře" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Pozastavit" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "Stop" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "Oříznout" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" -msgstr "Následující stopa" +msgstr "Další stopa" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Předchozí stopa" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "Přetočit vpřed" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "Přetočit zpět" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "Zvýšit hlasitost" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "Snížit hlasitost" -#: src/Command.cxx:98 +#: src/Command.cxx:99 #, fuzzy msgid "Select/deselect song in queue" msgstr "Vybrat/Zrušit výběr skladby v seznamu skladeb" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Vybrat všechny vypsané položky" -#: src/Command.cxx:102 +#: src/Command.cxx:103 #, fuzzy msgid "Delete song from queue" msgstr "Smazat skladbu ze seznamu skladeb" -#: src/Command.cxx:104 +#: src/Command.cxx:105 +#, fuzzy msgid "Shuffle queue" -msgstr "" +msgstr "Zamíchat frontu" -#: src/Command.cxx:106 +#: src/Command.cxx:107 +#, fuzzy msgid "Clear queue" -msgstr "" +msgstr "Vymazat frontu" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "Přepnout režim opakování" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "Přepnout náhodný režim" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "Přepnout jednoduchý mód" -#: src/Command.cxx:114 +#: src/Command.cxx:115 +#, fuzzy msgid "Toggle consume mode" -msgstr "Přepnout režim konzumace" +msgstr "Přepnout spotřební režim" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" -msgstr "Zapnout režim přerušení" +msgstr "Zapnout režim prolínání skladeb" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "Spustit aktualizaci databáze skladeb" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" msgstr "" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 #, fuzzy msgid "Append song to queue" msgstr "Přidat skladbu do seznamu skladeb" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "Přejít do kořenového adresáře" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "Přejít do nadřazeného adresáře" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "Najít skladbu v prohlížeči" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "Přesunout položku výše" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "Přesunout položku níže" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "Aktualizovat obrazovku" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "Přepnout na režim vyhledávání" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "Zapnout režim automatické centrování" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "Další obrazovka" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "Předchozí obrazovka" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "Přepnout na nedávnou obrazovku" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "Najít vpřed" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "Najít další vpřed" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "Najít zpět" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "Najít předchozí" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "Skočit na" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" msgstr "" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Obrazovka vyhledávání" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "Změnit režim hledání" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "Zobrazit vybranou a v současnosti přehrávanou píseň" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "Obrazovka textu písně" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "Přerušit akci" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "Aktualizovat text písně" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "Obrazovka výstupů" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 #, fuzzy msgid "Chat screen" msgstr "Další obrazovka" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "Neplatná definice klávesové zkratky" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "Neúplné nastavení klávesových zkratek" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "Neznámý příkaz" @@ -354,29 +358,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "Chybný typ zobrazení času" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "Chybí '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "Chybné jméno barvy" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "Neúplná definice barvy" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "Neplatné číslo" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "Neplatná definice barvy" @@ -385,24 +389,24 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "Neznámé jméno obrazovky" -#: src/ConfigParser.cxx:403 +#: src/ConfigParser.cxx:388 #, fuzzy msgid "Unknown MPD tag" msgstr "Neznámý příkaz" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "Chybný vyhledávací mód" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "Neznámý vyhledávací mód" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "Neznámý parametr nastavení" @@ -413,141 +417,141 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "Smazání této položky není možné" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, fuzzy, c-format msgid "Delete playlist %s?" msgstr "Smazat seznam skladeb" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Přerušeno" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "Seznam skladeb smazán" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Procházet" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, fuzzy, c-format msgid "Loading playlist '%s'" msgstr "Načítám seznam skladeb: %s..." -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 #, fuzzy, c-format msgid "Adding '%s' to queue" msgstr "Přidávám '%s' do seznamu skladeb" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Pohyb" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Globální" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Přehrát" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "Střed" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Vytoupit do adresáře/Vybrat a přehrát skladbu" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Smazat seznam skladeb" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 #, fuzzy msgid "New search" msgstr "Vyhledávání" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Vybrat a přehrát" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "Zobrazit text písně" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "Znovu načíst text písně" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Přerušit načítání" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "Stáhnout text pro aktuálně přehrávanou skladbu" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 #, fuzzy msgid "Add or edit lyrics" msgstr "Žádný uložený text písně" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "Uložit text písně" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" msgstr "Smazat uložený text písně" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Povolit/zakázat výstup" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" msgstr "" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Obrazovka keydef" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Upravit keydefs pro vybraný příkaz" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "Odstranit vybraný keydef" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 #, fuzzy msgid "Add a keydef" msgstr "Přidat novou klávesovou zkratku" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Jít o úroveň výš" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Aplikovat a uložit změny" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Nápověda" @@ -559,154 +563,156 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Odstraněno" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "Vložte novou klávesu pro %s: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" msgstr "" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Chyba: klávesa %s je již použita pro %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "%s přiřazeno k %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Přidat novou klávesovou zkratku" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "Upravit klávesové zkratky pro %s" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "Nové klávesové zkratky" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "Klávesové zkratky nezměněny" -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 #, fuzzy msgid "Unable to write configuration" msgstr "Neúplné nastavení klávesových zkratek" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "Chyba" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "Zapsat %s" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "===> Použít klávesové zkratky " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "===> Použít & Uložit klávesové zkratky " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "Upravit klávesové zkratky" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "Poznámka: Zapomněl jste 'Uplatnit' změny?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "Nedefinováno" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Mezera" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Vstup" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "Zpět" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Odstranit" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Nahoru" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Dolů" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "Doleva" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "Doprava" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Domů" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "Konec" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "PageDown" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "PageUp" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Shift+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Insert" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "" @@ -716,7 +722,7 @@ msgid "Artists" msgstr "Interpret" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 #, fuzzy msgid "Albums" msgstr "Album" @@ -725,11 +731,11 @@ msgid "All" msgstr "" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" msgstr "" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" msgstr "" @@ -791,12 +797,12 @@ msgid "No saved lyrics" msgstr "Žádný uložený text písně" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, fuzzy, c-format msgid "Connecting to %s" msgstr "Připojeno k %s" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, fuzzy, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "Chyba: MPD verze %d.%d.%d je příliš stará (potřebuji %s)" @@ -811,20 +817,38 @@ " Vojtěch Trefný https://launchpad.net/~vojtech.trefny\n" " Zbyněk Schwarz https://launchpad.net/~tsbook" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Název" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "Výstup '%s' povolen" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "Výstup '%s' zakázán" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Výstupy" +#: src/OutputsPage.cxx:383 +#, fuzzy +msgid "Partition" +msgstr "interpret" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" msgstr "" @@ -964,86 +988,90 @@ msgid "Password" msgstr "Heslo" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "interpret" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "album" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "titulek" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "stopa" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "název" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "žánr" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "datum" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "skladatel" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "umělec" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "poznámka" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "soubor" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Název" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Interpret" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Album" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Název souboru" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Interpret + Název" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Chybný tag vyhledávání %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "Žádný argument vyhledávání %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Vyhledávání" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Režim vyhledávání: %s" @@ -1061,99 +1089,100 @@ msgstr "Skladatel" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Název" +#, fuzzy +msgid "Performer" +msgstr "umělec" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Disk" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Skladba" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Datum" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Žánr" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Poznámka" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Cesta" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Bitrate" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" msgstr "" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Počet interpretů" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Počet alb" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Počet skladeb" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "Doba běhu" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "Poslední aktualizace db" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "Čas přehrávání" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "Čas hraní DB" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "Prohlížeč skladeb" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "MPD statistiky" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "Vybraná skladba" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "Právě přehrávaná skladba" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d kbps" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" msgstr "" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Přehrávání:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "Pozastaveno"
View file
ncmpc-0.36.tar.xz/po/da.po -> ncmpc-0.47.tar.xz/po/da.po
Changed
@@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: ncmpc 0.11.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" "PO-Revision-Date: 2009-09-24 10:26+0200\n" "Last-Translator: Niels Anker <nanker@webspeed.dk>\n" "Language-Team: da <da@li.org>\n" @@ -18,7 +18,7 @@ "X-Launchpad-Export-Date: 2009-09-24 08:24+0000\n" "X-Generator: Launchpad (build Unknown)\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "Tast %s tildelt %s og %s" @@ -35,314 +35,314 @@ msgid "Message could not be sent" msgstr "" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "Taste konfigurations skærm" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Afslut" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "Flyt markør op" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "Flyt markør ned" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "Flyt cursor til toppen af skærmen" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "Flyt cursor til midten af skærmen" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "Flyt cursor til bunden af skærmen" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "Flyt cursor til toppen af listen" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "Flyt cursor til bunden af listen" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "Side op" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "Side ned" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "Valg af interval" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "Scroll en linie ned" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "Scroll en linie op" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "Scroll en halv skærm op" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "Scroll en halv skærm ned" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "Vælg den sang der spilles nu" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "Hjælp" -#: src/Command.cxx:71 src/HelpPage.cxx:140 +#: src/Command.cxx:72 src/HelpPage.cxx:141 #, fuzzy msgid "Queue screen" msgstr "Tastdefinitions skærm" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "Gennemse" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "Afspil/Gå til mappe" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Pause" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "Stop" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "Beskær" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "Næste" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Forrige" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "Søg fremad" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "Søg tilbage" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "Hæv volumen" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "Sænk volumen" -#: src/Command.cxx:98 +#: src/Command.cxx:99 #, fuzzy msgid "Select/deselect song in queue" msgstr "Marker/afmarker sang i afspilningsliste" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Vælg alle emner på listen" -#: src/Command.cxx:102 +#: src/Command.cxx:103 #, fuzzy msgid "Delete song from queue" msgstr "Slet sang fra afspilningsliste" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" msgstr "" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" msgstr "" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "Aktiver/deaktiver gentag" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "Aktiver/deaktiver tilfældigt valg" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "Aktiver/deaktiver enkelt valg" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "Aktiver/deaktiver consume valg" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "Aktiver/deaktiver crossfade mellem sange" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "Opdater databasen" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" msgstr "" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 #, fuzzy msgid "Append song to queue" msgstr "Tilføj spor til afspilningsliste" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "Gå til rod mappen" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "Gå til forældre mappe" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "Lokaliser sang i browseren" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "Flyt op" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "Flyt ned" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "Genopfrisk skærm" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "Ændre søge tilstand" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "Aktiver/deaktiver automatisk centrering" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "Næste skærm" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "Forrige skærm" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "Skift til seneste skærm" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "Søg" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "Gentag søg" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "Søg baglæns" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "Gentag søg baglæns" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "Spring til" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" msgstr "" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Database søgning" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "Ændre søge tilstand" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "Vis valgte numre og det der afspilles" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "Sangtekst skærm" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "Afbryd action" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "Opdater sangtekster" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "Output skærm" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 #, fuzzy msgid "Chat screen" msgstr "Næste skærm" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "Forkert hotkey definition" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "Ufuldstændig hotkey konfiguration" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "Ukendt kommando" @@ -354,29 +354,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "Ringe tidsvisningstype" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "Mangler '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "Dårligt farvenavn" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "Ufuldstændig farve definition" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "Ugyldigt tal." -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "Forkert farve definition" @@ -385,24 +385,24 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "Ukendt skærm navn" -#: src/ConfigParser.cxx:403 +#: src/ConfigParser.cxx:388 #, fuzzy msgid "Unknown MPD tag" msgstr "Ukendt kommando" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "Ugyldig søgetilstand" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "Ukendt søgetilstand" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "Ukendt konfigurations parameter" @@ -413,142 +413,142 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "Sletning af dette emne ikke muligt" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, fuzzy, c-format msgid "Delete playlist %s?" msgstr "Slet afspilningsliste" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Afbrudt" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "Afspilningslisten slettet" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Gennemse" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, fuzzy, c-format msgid "Loading playlist '%s'" msgstr "Henter %s..." -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 #, fuzzy, c-format msgid "Adding '%s' to queue" msgstr "Tilføjer '%s' til listen" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Navigation" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Globale" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Afspil" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "Centrer" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Skift til bibliotek/Tilføj til afspilningslisten og afspil" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Slet afspilningsliste" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 #, fuzzy msgid "New search" msgstr "Søg" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Vælg og afspil" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "Gennemse sangtekster" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "(Gen)indlæs santekster" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Abryd hentning" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "Download tekst for det nummer der afspilles" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 #, fuzzy msgid "Add or edit lyrics" msgstr "Gem sagtekster" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "Gem sagtekster" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 #, fuzzy msgid "Delete saved lyrics" msgstr "Gem sagtekster" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Slå output til/fra" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" msgstr "" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Tastdefinitions skærm" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Redigér tastdefinitioner for udvalgte kommandoer" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "Fjern valgte tastdefinitioner" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 #, fuzzy msgid "Add a keydef" msgstr "Definér ny tast" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Gå et niveau op" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Anvend og gem ændringer" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Hjælp" @@ -560,154 +560,156 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Slettet" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "Ny tast for %s: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" msgstr "" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Tasten %s anvendes allerede til %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "Tildelt %s til %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Definér ny tast" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "Modificer tast for '%s'" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "Taste bindinger opdaterede" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "Taste bindinger uændrede!" -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 #, fuzzy msgid "Unable to write configuration" msgstr "Ufuldstændig hotkey konfiguration" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "Fejl" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "Skrev %s" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "==> Anvend taste bindinger " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "==> Anvend og gem taste bindinger " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "Modificer taste bindinger" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "OBS! Du glemte vel ikke at 'anvende' dine ændringer?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "Udefineret" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Mellemrum" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Retur" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "Tilbagetast" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Slet" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Op" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Ned" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "Venstre" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "Højre" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Hjem" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "Slut" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "PageDown" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "PageUp" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Skift+Tabulator" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Indsæt" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "" @@ -717,7 +719,7 @@ msgid "Artists" msgstr "Kunstner" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 #, fuzzy msgid "Albums" msgstr "Album" @@ -726,11 +728,11 @@ msgid "All" msgstr "" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" msgstr "" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" msgstr "" @@ -794,12 +796,12 @@ msgid "No saved lyrics" msgstr "Gem sagtekster" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, fuzzy, c-format msgid "Connecting to %s" msgstr "Forbundet til %s" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, fuzzy, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "Fejl: MPD version %d.%d.%d er for gammel (mindst %s er nødvendig)" @@ -813,20 +815,38 @@ " Mikkel Kirkgaard Nielsen https://launchpad.net/~ncmpc\n" " Niels Anker https://launchpad.net/~nanker" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Navn" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "Output '%s' slået til" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "Output '%s' slået fra" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Output" +#: src/OutputsPage.cxx:383 +#, fuzzy +msgid "Partition" +msgstr "kunstner" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" msgstr "" @@ -966,86 +986,90 @@ msgid "Password" msgstr "Adgangskode" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "kunstner" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "album" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "titel" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "spor" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "navn" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "genre" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "dato" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "komponist" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "udførende" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "kommentar" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "fil" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Titel" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Kunstner" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Album" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Filnavn" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Kunstner + Titel" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Ugyldigt søge tag %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "Inter argument for søge tag %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Søg" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Søg efter: %s" @@ -1063,99 +1087,100 @@ msgstr "Komponist" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Navn" +#, fuzzy +msgid "Performer" +msgstr "udførende" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Disk" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Spor" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Dato" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Genre" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Kommentar" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Sti" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Bithastighed" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" msgstr "" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Antal kunstnere" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Antal albums" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Antal sange" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "Oppetid" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "Seneste db opdatering" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "Spilletid" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "DB spilletid" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "Sang viser" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "MPD statistik" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "Valgt nummer" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "Nummer der afspilles" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d kb/sek" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" msgstr "" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Afspiller:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "Pause"
View file
ncmpc-0.36.tar.xz/po/de.po -> ncmpc-0.47.tar.xz/po/de.po
Changed
@@ -8,9 +8,9 @@ msgstr "" "Project-Id-Version: ncmpc 0.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2019-09-08 13:57+0200\n" -"Last-Translator: ssantos <ssantos@web.de>\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2020-11-06 20:26+0000\n" +"Last-Translator: mv87 <mv87@dismail.de>\n" "Language-Team: German <https://hosted.weblate.org/projects/ncmpc/" "translations/de/>\n" "Language: de\n" @@ -18,10 +18,10 @@ "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 3.7-dev\n" +"X-Generator: Weblate 4.3.2\n" "X-Launchpad-Export-Date: 2011-06-23 08:56+0000\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "Taste %s ist %s und %s zugeordnet" @@ -38,309 +38,309 @@ msgid "Message could not be sent" msgstr "Nachricht konnte nicht gesendet werden" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "Tastenkonfigurationsanzeige" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Beenden" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "Cursor nach oben bewegen" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "Cursor nach unten bewegen" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "Markierung an den Anfang der Anzeige setzen" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "Markierung in die Mitte der Anzeige setzen" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "Markierung ans Ende der Anzeige setzen" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "Markierung an den Anfang der Liste setzen" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "Markierung ans Ende der Liste setzen" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "Bild auf" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "Bild ab" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "Mehrfachauswahl" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "Eine Zeile nach unten scrollen" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "Eine Zeile nach oben scrollen" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "Die halbe Anzeige nach oben scrollen" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "Die halbe Anzeige nach unten scrollen" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" -msgstr "Derzeit spielenden Song auswählen" +msgstr "Derzeit spielendes Lied auswählen" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "Hilfeanzeige" -#: src/Command.cxx:71 src/HelpPage.cxx:140 +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" msgstr "Warteschlangenanzeige" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "Anzeige durchstöbern" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "Abspielen/Verzeichnis öffnen" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Pause" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" -msgstr "Stop" +msgstr "Stopp" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "Playlist auf das markierte Lied reduzieren" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "Nächstes Stück" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Vorheriges Stück" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "Vorspulen" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "Zurückspulen" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "Lautstärke erhöhen" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "Lautstärke verringern" -#: src/Command.cxx:98 +#: src/Command.cxx:99 msgid "Select/deselect song in queue" msgstr "Stück in der Warteschlange auswählen/abwählen" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Alle angezeigten Lieder zur Playlist hinzufügen" -#: src/Command.cxx:102 +#: src/Command.cxx:103 msgid "Delete song from queue" msgstr "Lösche Song aus der Warteschlange" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" msgstr "Warteschlange mischen" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" msgstr "Warteschlange leeren" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "Schalte Wiederholungswiedergabe ein/aus" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "Schalte Zufallswiedergabe ein/aus" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "Einzelabspiel-Modus umschalten" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "Verbrauchs-Modus Umschalten" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "Schalte Crossfade-Wiedergabe ein/aus" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "Starte eine Aktualisierung der Musikdatenbank" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" msgstr "Warteschlange speichern" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" msgstr "Song zur Warteschlange hinzufügen" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "Basis-Verzeichnis öffnen" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "Übergeordnetes Verzeichnis öffnen" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "Lied in Datenbank orten" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "Bewege es nach oben" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "Bewege es nach unten" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "Aktualisiere Anzeige" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "Wechsle den Suchmodus" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "Schalte den Autozentrier-Modus ein/aus" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "Nächste Anzeige" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "Vorherige Anzeige" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "Wechsle zur zuletzt benutzten Anzeige" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "Vorwärtssuche" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "Vorwärtssuche fortsetzen" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "Rückwärtssuche" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "Rückwärtssuche fortsetzen" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "Springe zu" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" -msgstr "" +msgstr "Bibliotheksseite" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Suchanzeige" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "Suchmodus wechseln" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "Zeige das ausgewählte und das gerade laufende Lied an" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "Liedtextanzeige" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "Kommando Unterbrechen" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "Liedtext aktualisieren" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "Aktuelles Element bearbeiten" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "Anzeige der Ausgabegeräte" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" msgstr "Chat-Bildschirm" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "Wort erwartet" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "Fehlerhafte Definition der Tastenbelegung" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "Unvollständige Konfiguration für Tastenbelegung" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "Unbekannter Befehl" @@ -352,29 +352,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "Ungültige Anzeigeart" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "Es fehlt ein '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "Ungültiger Farbname" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "Unvollständige Farbkonfiguration" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "Ungültige Zahl" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "Fehlerhafte Farbdefinition" @@ -383,24 +383,23 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "Unbekannter Anzeigenname" -#: src/ConfigParser.cxx:403 -#, fuzzy +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" -msgstr "Unbekannter Befehl" +msgstr "Unbekannter MPD Tag" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "Ungültiger Suchmodus" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "Unbekannter Suchmodus" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "Unbekannter Konfigurationsparameter" @@ -411,138 +410,138 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "Dieses Objekt kann nicht gelöscht werden" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, c-format msgid "Delete playlist %s?" msgstr "Wiedergabeliste %s löschen?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Abbruch" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "Playlist gelöscht" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Stöbern" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, c-format msgid "Loading playlist '%s'" -msgstr "Lade Wiedergabeliste '%s'" +msgstr "Lade Wiedergabeliste „%s“" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 #, c-format msgid "Adding '%s' to queue" -msgstr "Füge '%s' der Wiedergabeliste hinzu" +msgstr "Füge „%s“ der Wiedergabeliste hinzu" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Bewegung" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Global" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Abspielen" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "Zentrieren" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Verzeichnis öffnen/Stück auswählen und abspielen" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" -msgstr "Lösche Playlist" +msgstr "Wiedergabeliste löschen" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 msgid "New search" msgstr "Neue Suche" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Auswählen und abspielen" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "Liedtext lesen" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "Text (neu) laden" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Laden unterbrechen" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "Liedtexte für aktuell laufendes Stück herunterladen" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" msgstr "Texte hinzufügen oder bearbeiten" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "Liedtext speichern" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" -msgstr "Lösche gespeicherte Texte" +msgstr "Gespeicherte Texte löschen" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Ausgabegerät aktivieren/deaktivieren" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" msgstr "Nachricht schreiben" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Tastenbelegungsanzeige" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Tastenbelegung für ausgewählten Befehl bearbeiten" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "Ausgewählte Tastenbelegung entfernen" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 msgid "Add a keydef" msgstr "Füge neue Taste hinzu" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Eine Ebene nach oben" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Änderungen bestätigen und speichern" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Hilfe" @@ -554,153 +553,155 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Gelöscht" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "Gib neue Taste für %s ein: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" msgstr "Strg-Leerzeichen kann nicht verwendet werden" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Fehler: Taste %s wird bereits benutzt für %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "%s wurde %s zugeordnet" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" -msgstr "Füge neue Taste hinzu" +msgstr "Neue Taste hinzufügen" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" -msgstr "Editiere Tasten für %s" +msgstr "Tasten für %s ändern" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "Du hast eine neue Tastenbelegung" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "Tastenbelegung unverändert." -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" msgstr "Konfiguration kann nicht geschrieben werden" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "Fehler" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "%s geschrieben" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "===> Tastenbelegung anwenden " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "===> Tastenbelegung speichern und anwenden " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" -msgstr "Editiere Tastenbelegungen" +msgstr "Tastenbelegungen ändern" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" -msgstr "Tipp: Hast du vergessen, deine Änderungen 'Anzuwenden'?" +msgstr "Tipp: Hast du vergessen, deine Änderungen „Anzuwenden“?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "Tasten" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "Undefiniert" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Leertaste" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Enter" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" -msgstr "Backspace" +msgstr "Rücktaste" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Entf" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Oben" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Unten" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "Links" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "Rechts" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Pos1" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "Ende" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "Bild ab" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "Bild auf" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Shift+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Einfg" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "Strg-%c" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "Alt-%c" @@ -709,22 +710,21 @@ msgid "Artists" msgstr "Künstler" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 msgid "Albums" msgstr "Alben" #: src/LibraryPage.cxx:123 msgid "All" -msgstr "" +msgstr "Alle" -#: src/LibraryPage.cxx:199 -#, fuzzy +#: src/LibraryPage.cxx:197 msgid "Songs" -msgstr "Lied" +msgstr "Lieder" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" -msgstr "" +msgstr "Bibliothek" #: src/ListWindow.cxx:213 msgid "Range selection disabled" @@ -753,7 +753,7 @@ #. while data is retrieved #: src/LyricsPage.cxx:356 msgid "loading..." -msgstr "lade…" +msgstr "lade …" #: src/LyricsPage.cxx:378 msgid "Editor not configured" @@ -784,12 +784,12 @@ msgid "No saved lyrics" msgstr "Keine gespeicherten Texte" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, c-format msgid "Connecting to %s" msgstr "Verbinden mit %s" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "Fehler: MPD-Version %d.%d.%d ist zu alt (%s wird benötigt)" @@ -809,20 +809,38 @@ " Samuel Creshal https://launchpad.net/~samuel-creshal\n" " cmdrhenner https://launchpad.net/~cmdrhenner" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Name" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" -msgstr "Ausgabegerät '%s' aktiviert" +msgstr "Ausgabegerät „%s“ aktiviert" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" -msgstr "Ausgabegerät '%s' deaktiviert" +msgstr "Ausgabegerät „%s“ deaktiviert" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Ausgabegeräte" +#: src/OutputsPage.cxx:383 +#, fuzzy +msgid "Partition" +msgstr "Position" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" msgstr "durchmischte Warteschlange" @@ -955,92 +973,96 @@ #: src/screen_find.cxx:81 #, c-format msgid "Unable to find '%s'" -msgstr "Kann '%s' nicht finden" +msgstr "Kann „%s“ nicht finden" #: src/screen_utils.cxx:150 msgid "Password" msgstr "Passwort" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "Künstler" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "Album" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "Titel" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "Stück" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "Name" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "Genre" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "Datum" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "Komponist" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "Aufführung" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "Anmerkung" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "Datei" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Titel" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Künstler" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Album" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Dateiname" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Künstler + Titel" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "Unbekanntes Suffix" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Tag nicht erkannt: %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "Kein Argument für Tag %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Suche" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Suchmodus: %s" @@ -1058,99 +1080,99 @@ msgstr "Komponist" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Name" +msgid "Performer" +msgstr "Interpret" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "CD" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Stück" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Datum" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Genre" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Anmerkung" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Pfad" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Bitrate" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" msgstr "Format" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Anzahl der Künstler" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Anzahl der Alben" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Anzahl der Lieder" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "Laufzeit" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "Letzte db-Aktualisierung" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "Spielzeit" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "DB Spielzeit" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "Liedbetrachter" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "MPD Statistik" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "Lied anzeigen" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "Gerade laufendes Lied" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" -msgstr "%d kbps" +msgstr "%d kB/s" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" msgstr "Lied" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Spiele:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "Pause"
View file
ncmpc-0.36.tar.xz/po/en.po -> ncmpc-0.47.tar.xz/po/en.po
Changed
@@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" "PO-Revision-Date: 2019-09-08 13:58+0200\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" @@ -17,7 +17,7 @@ "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "Key %s assigned to %s and %s" @@ -34,309 +34,309 @@ msgid "Message could not be sent" msgstr "Message could not be sent" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "Key configuration screen" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Quit" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "Move cursor up" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "Move cursor down" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "Move cursor to the top of screen" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "Move cursor to the middle of screen" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "Move cursor to the bottom of screen" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "Move cursor to the top of the list" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "Move cursor to the bottom of the list" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "Page up" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "Page down" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "Range selection" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "Scroll down one line" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "Scroll up one line" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "Scroll up half a screen" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "Scroll down half a screen" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "Select currently playing song" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "Help screen" -#: src/Command.cxx:71 src/HelpPage.cxx:140 +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" msgstr "Queue screen" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "Browse screen" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "Play/Enter directory" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Pause" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "Stop" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "Crop" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "Next track" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Previous track" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "Seek forward" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "Seek backward" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "Increase volume" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "Decrease volume" -#: src/Command.cxx:98 +#: src/Command.cxx:99 msgid "Select/deselect song in queue" msgstr "Select/deselect song in queue" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Select all listed items" -#: src/Command.cxx:102 +#: src/Command.cxx:103 msgid "Delete song from queue" msgstr "Delete song from queue" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" msgstr "Shuffle queue" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" msgstr "Clear queue" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "Toggle repeat mode" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "Toggle random mode" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "Toggle single mode" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "Toggle consume mode" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "Toggle crossfade mode" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "Start a music database update" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" msgstr "Save queue" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" msgstr "Append song to queue" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "Go to root directory" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "Go to parent directory" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "Locate song in browser" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "Move item up" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "Move item down" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "Refresh screen" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "Toggle find mode" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "Toggle auto center mode" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "Next screen" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "Previous screen" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "Swap to most recent screen" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "Forward find" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "Forward find next" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "Backward find" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "Backward find previous" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "Jump to" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" msgstr "Library page" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Search screen" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "Change search mode" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "View the selected and the currently playing song" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "Lyrics screen" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "Interrupt action" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "Update Lyrics" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "Edit the current item" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "Outputs screen" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" msgstr "Chat screen" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "Word expected" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "Malformed hotkey definition" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "Incomplete hotkey configuration" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "Unknown command" @@ -348,29 +348,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "Bad time display type" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "Missing '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "Bad color name" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "Incomplete color definition" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "Invalid number" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "Malformed color definition" @@ -379,23 +379,23 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "Unknown screen name" -#: src/ConfigParser.cxx:403 +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" msgstr "Unknown MPD tag" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "Invalid search mode" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "Unknown search mode" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "Unknown configuration parameter" @@ -406,138 +406,138 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "Deleting this item is not possible" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, c-format msgid "Delete playlist %s?" msgstr "Delete playlist %s?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Aborted" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "Playlist deleted" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Browse" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, c-format msgid "Loading playlist '%s'" msgstr "Loading playlist '%s'" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 #, c-format msgid "Adding '%s' to queue" msgstr "Adding '%s' to queue" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Movement" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Global" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Play" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "Center" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Enter directory/Select and play song" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Delete playlist" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 msgid "New search" msgstr "New search" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Select and play" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "View Lyrics" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "(Re)load lyrics" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Interrupt retrieval" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "Download lyrics for currently playing song" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" msgstr "Add or edit lyrics" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "Save lyrics" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" msgstr "Delete saved lyrics" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Enable/disable output" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" msgstr "Write a message" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Keydef screen" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Edit keydefs for selected command" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "Remove selected keydef" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 msgid "Add a keydef" msgstr "Add a keydef" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Go up a level" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Apply and save changes" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Help" @@ -549,153 +549,155 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Deleted" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "Enter new key for %s: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" msgstr "Ctrl-Space can't be used" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Error: key %s is already used for %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "Assigned %s to %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Add new key" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "Edit keys for %s" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "You have new key bindings" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "Keybindings unchanged." -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" msgstr "Unable to write configuration" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "Error" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "Wrote %s" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "===> Apply key bindings " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "===> Apply & Save key bindings " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "Edit key bindings" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "Note: Did you forget to 'Apply' your changes?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "Keys" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "Undefined" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Space" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Enter" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "Backspace" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Delete" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Up" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Down" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "Left" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "Right" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Home" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "End" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "PageDown" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "PageUp" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Shift+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Insert" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "Ctrl-%c" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "Alt-%c" @@ -704,7 +706,7 @@ msgid "Artists" msgstr "Artists" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 msgid "Albums" msgstr "Albums" @@ -712,11 +714,11 @@ msgid "All" msgstr "All" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" msgstr "Songs" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" msgstr "Library" @@ -778,12 +780,12 @@ msgid "No saved lyrics" msgstr "No saved lyrics" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, c-format msgid "Connecting to %s" msgstr "Connecting to %s" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "Error: MPD version %d.%d.%d is too old (%s needed)" @@ -794,20 +796,38 @@ msgid "translator-credits" msgstr "translator-credits" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Name" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "Output '%s' enabled" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "Output '%s' disabled" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Outputs" +#: src/OutputsPage.cxx:383 +#, fuzzy +msgid "Partition" +msgstr "Position" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" msgstr "Shuffled queue" @@ -946,86 +966,90 @@ msgid "Password" msgstr "Password" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "artist" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "album" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "title" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "track" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "name" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "genre" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "date" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "composer" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "performer" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "comment" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "file" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Title" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Artist" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Album" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Filename" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Artist + Title" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Bad search tag %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "No argument for search tag %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Search" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Search mode: %s" @@ -1043,99 +1067,100 @@ msgstr "Composer" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Name" +#, fuzzy +msgid "Performer" +msgstr "performer" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Disc" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Track" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Date" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Genre" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Comment" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Path" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Bitrate" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" msgstr "Format" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Number of artists" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Number of albums" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Number of songs" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "Uptime" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "Most recent db update" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "Playtime" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "DB playtime" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "Song viewer" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "MPD statistics" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "Selected song" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "Currently playing song" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d kbps" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" msgstr "Song" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Playing:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "Paused"
View file
ncmpc-0.36.tar.xz/po/eo.po -> ncmpc-0.47.tar.xz/po/eo.po
Changed
@@ -7,339 +7,341 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2011-05-16 15:13+0000\n" -"Last-Translator: Aleksej <Unknown>\n" -"Language-Team: Esperanto <eo@li.org>\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2021-03-29 23:26+0000\n" +"Last-Translator: phlostically <phlostically@mailinator.com>\n" +"Language-Team: Esperanto <https://hosted.weblate.org/projects/ncmpc/" +"translations/eo/>\n" "Language: eo\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.6-dev\n" "X-Launchpad-Export-Date: 2011-06-23 08:56+0000\n" -"X-Generator: Launchpad (build 13265)\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" -msgstr "" +msgstr "Klavo %s estas asignita al %s kaj %s" #: src/ChatPage.cxx:64 src/ChatPage.cxx:182 msgid "Chat" -msgstr "" +msgstr "Babili" #: src/ChatPage.cxx:163 msgid "Your message" -msgstr "" +msgstr "Via mesaĝo" #: src/ChatPage.cxx:172 msgid "Message could not be sent" -msgstr "" +msgstr "Malsukcesis sendi mesaĝon" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" -msgstr "" +msgstr "Klavo-agorda ekrano" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" -msgstr "" +msgstr "Forlasi" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" -msgstr "" +msgstr "Movi kursoron supren" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" -msgstr "" +msgstr "Movi kursoron suben" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" -msgstr "" +msgstr "Movi kursoron al la supro de la ekrano" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" -msgstr "" +msgstr "Movi kursoron al la mezo de la ekrano" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" -msgstr "" +msgstr "Movi kursoron al la malsupro de la ekrano" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" -msgstr "" +msgstr "Movi kursoron al la supro de la listo" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" -msgstr "" +msgstr "Movi kursoron al la malsupro de la listo" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" -msgstr "" +msgstr "Supreniri unu paĝon" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" -msgstr "" +msgstr "Malsupreniri unu paĝon" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" -msgstr "" +msgstr "Intervala elektado" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" -msgstr "" +msgstr "Rulumi malsupren unu linion" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" -msgstr "" +msgstr "Rulumi supren unu linion" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" -msgstr "" +msgstr "Rulumi supren ekranduonon" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" -msgstr "" +msgstr "Rulumi malsupren ekranduonon" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" -msgstr "" +msgstr "Elekti nuntempe ludatan kanton" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" -msgstr "" +msgstr "Helpa ekrano" -#: src/Command.cxx:71 src/HelpPage.cxx:140 +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" -msgstr "" +msgstr "Vica ekrano" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" -msgstr "" +msgstr "Foliuma ekrano" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" -msgstr "" +msgstr "Ludi/Eniri dosierujon" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" -msgstr "" +msgstr "Paŭzi" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" -msgstr "" +msgstr "Ĉesigi" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" -msgstr "" +msgstr "Stuci" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" -msgstr "" +msgstr "Sekva trako" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" -msgstr "" +msgstr "Antaŭa trako" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" -msgstr "" +msgstr "Salti antaŭen" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" -msgstr "" +msgstr "Salti malantaŭen" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" -msgstr "" +msgstr "Plilaŭtigi" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" -msgstr "" +msgstr "Malplilaŭtigi" -#: src/Command.cxx:98 +#: src/Command.cxx:99 msgid "Select/deselect song in queue" -msgstr "" +msgstr "Elekti/malelekti kanton en vico" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" -msgstr "" +msgstr "Elekti ĉiujn erojn en listo" -#: src/Command.cxx:102 +#: src/Command.cxx:103 msgid "Delete song from queue" -msgstr "" +msgstr "Forigi kanton for de vico" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" -msgstr "" +msgstr "Miksi vicon" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" -msgstr "" +msgstr "Malplenigi vicon" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" -msgstr "" +msgstr "Baskuligi ripetan reĝimon" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" -msgstr "" +msgstr "Baskuligi hazardan reĝimon" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" -msgstr "" +msgstr "Baskuligi unuopan reĝimon" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" -msgstr "" +msgstr "Baskuligi konsuman reĝimon" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" -msgstr "" +msgstr "Baskuligi interfadan reĝimon" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" -msgstr "" +msgstr "Ekĝisdatigi muzikan datenbankon" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" -msgstr "" +msgstr "Konservi vicon" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" -msgstr "" +msgstr "Postmeti kanton en vicon" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" -msgstr "" +msgstr "Iri al radika dosierujo" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" -msgstr "" +msgstr "Iri al patra dosierujo" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" -msgstr "" +msgstr "Trovi kanton en foliumilo" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" -msgstr "" +msgstr "Movi eron supren" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" -msgstr "" +msgstr "Movi eron malsupren" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" -msgstr "" +msgstr "Reŝargi ekranon" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" -msgstr "" +msgstr "Baskuligi serĉan reĝimon" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" -msgstr "" +msgstr "Baskuligi aŭtomate centrigan reĝimon" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" -msgstr "" +msgstr "Sekva ekrano" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" -msgstr "" +msgstr "Antaŭa ekrano" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" -msgstr "" +msgstr "Iri al lasta ekrano" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" -msgstr "" +msgstr "Serĉi finen" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" -msgstr "" +msgstr "Serĉi la sekvan" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" -msgstr "" +msgstr "Serĉi komencen" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" -msgstr "" +msgstr "Serĉi la antaŭan" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" -msgstr "" +msgstr "Salti al" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" -msgstr "" +msgstr "Biblioteka paĝo" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" -msgstr "" +msgstr "Serĉa ekrano" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" -msgstr "" +msgstr "Ŝanĝi serĉan reĝimon" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" -msgstr "" +msgstr "Vidi la elektitan ludatan kanton" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" -msgstr "" +msgstr "Kantoteksta ekrano" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" -msgstr "" +msgstr "Interrompi agon" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" -msgstr "" +msgstr "Ĝisdatigi Kantotekstojn" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" -msgstr "" +msgstr "Redakti la aktualan eron" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" -msgstr "" +msgstr "Eliga ekrano" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" -msgstr "" +msgstr "Babila ekrano" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" -msgstr "" +msgstr "Vorto estas atendata" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" -msgstr "" +msgstr "Misformita klavasigno" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" -msgstr "" +msgstr "Nekompleta klavasigno" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" -msgstr "" +msgstr "Nekonata komando" #. translators: ncmpc #. supports displaying the @@ -349,196 +351,196 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" -msgstr "" +msgstr "Nekonata tempo-montra tipo" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" -msgstr "" +msgstr "Mankas '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" -msgstr "" +msgstr "Nevalida kolornomo" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" -msgstr "" +msgstr "Nekompleta kolordifino" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" -msgstr "" +msgstr "Nevalida nombro" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" -msgstr "" +msgstr "Misformita kolordifino" #. an unknown screen #. name was specified #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" -msgstr "" +msgstr "Nekonata nomo de ekrano" -#: src/ConfigParser.cxx:403 +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" -msgstr "" +msgstr "Nekonata MPD-etikedo" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" -msgstr "" +msgstr "Nevalida serĉa reĝimo" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" -msgstr "" +msgstr "Nekonata serĉa reĝimo" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" -msgstr "" +msgstr "Nekonata agorda parametro" #: src/CustomColors.cxx:57 msgid "Terminal lacks support for changing colors" -msgstr "" +msgstr "Al la terminalo mankas kapablo ŝanĝi kolorojn" #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" -msgstr "" +msgstr "Ne eblas forviŝi ĉi tiun eron" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, c-format msgid "Delete playlist %s?" -msgstr "" +msgstr "Ĉu forviŝi ludliston %s?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" -msgstr "" +msgstr "Nuligita" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" -msgstr "" +msgstr "Forviŝiĝis ludlisto" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" -msgstr "" +msgstr "Foliumi" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, c-format msgid "Loading playlist '%s'" -msgstr "" +msgstr "Ŝargante ludliston '%s'" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 -#, fuzzy, c-format +#, c-format msgid "Adding '%s' to queue" -msgstr "Aldonas \"%s\" al la ludlisto" +msgstr "Aldonante \"%s\" en vicon" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" -msgstr "" +msgstr "Movado" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" -msgstr "" +msgstr "Malloka" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" -msgstr "" +msgstr "Ludi" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" -msgstr "" +msgstr "Centrigi" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" -msgstr "" +msgstr "Eniri en dosierujon/Elekti kaj ludi kanton" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" -msgstr "" +msgstr "Forviŝi ludliston" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 msgid "New search" -msgstr "" +msgstr "Nova serĉo" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" -msgstr "" +msgstr "Elekti kaj ludi" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" -msgstr "" +msgstr "Vidi Kantotekstojn" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" -msgstr "" +msgstr "(Re)ŝargi kantotekstojn" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" -msgstr "" +msgstr "Haltigi elŝutadon" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" -msgstr "" +msgstr "Elŝuti kantotekstojn de ludata kanto" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" -msgstr "" +msgstr "Aldoni aŭ redakti kantotekstojn" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" -msgstr "" +msgstr "Konservi kantotekstojn" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" -msgstr "" +msgstr "Forviŝi konservitajn kantotekstojn" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" -msgstr "" +msgstr "Ŝalti/malŝalti eligon" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" -msgstr "" +msgstr "Skribi mesaĝon" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" -msgstr "" +msgstr "Klavdifina ekrano" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" -msgstr "" +msgstr "Redakti klavdifinojn por la elektita komando" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" -msgstr "" +msgstr "Forigi elektitan klavdifinon" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 msgid "Add a keydef" -msgstr "" +msgstr "Aldoni klavdifinon" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" -msgstr "" +msgstr "Supreniri unu nivelon" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" -msgstr "" +msgstr "Efektivigi kaj konservi ŝanĝojn" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Helpo" @@ -550,244 +552,246 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" -msgstr "" +msgstr "Forviŝiĝis" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " -msgstr "" +msgstr "Premu novan klavon por %s: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" -msgstr "" +msgstr "Stir-Spaceto ne uzeblas" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" -msgstr "" +msgstr "Eraro: klavo %s jam estas asignita por %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" -msgstr "" +msgstr "Asignis la klavon %s al %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" -msgstr "" +msgstr "Aldoni novan klavon" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" -msgstr "" +msgstr "Redakti klavojn por %s" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" -msgstr "" +msgstr "Efektiviĝis novaj klavasignoj" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." -msgstr "" +msgstr "Ne ŝanĝiĝis klavasignoj." -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" -msgstr "" +msgstr "Malsukcesis skribi agordojn" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" -msgstr "" +msgstr "Eraro" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" -msgstr "" +msgstr "Skribis sur %s" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " -msgstr "" +msgstr "===> Efektivigi klavasignojn " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " -msgstr "" +msgstr "===> Efektivigi kaj Konservi klavasignojn " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" -msgstr "" +msgstr "Redakti klavasignojn" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" -msgstr "" +msgstr "Noto: Ĉu vi forgesis 'Efektivigi' viajn ŝanĝojn?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" -msgstr "" +msgstr "Klavoj" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" -msgstr "" +msgstr "Nedifinita" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" -msgstr "" +msgstr "Spaceto" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" -msgstr "" +msgstr "Enigo" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" -msgstr "" +msgstr "Retropaŝo" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" -msgstr "" +msgstr "Forigo" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" -msgstr "" +msgstr "Supren" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" -msgstr "" +msgstr "Malsupren" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" -msgstr "" +msgstr "Maldekstren" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" -msgstr "" +msgstr "Dekstren" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" -msgstr "" +msgstr "Hejmen" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" -msgstr "" +msgstr "Finen" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" -msgstr "" +msgstr "Paĝosuben" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" -msgstr "" +msgstr "Paĝosupren" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" -msgstr "" +msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" -msgstr "" +msgstr "Maj+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" -msgstr "" +msgstr "Esk" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" -msgstr "" +msgstr "Enmeto" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" -msgstr "" +msgstr "Stir-%c" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" -msgstr "" +msgstr "Alt-%c" #: src/LibraryPage.cxx:45 msgid "Artists" -msgstr "" +msgstr "Muzikistoj" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 msgid "Albums" -msgstr "" +msgstr "Albumoj" #: src/LibraryPage.cxx:123 msgid "All" -msgstr "" +msgstr "Ĉiuj" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" -msgstr "" +msgstr "Kantoj" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" -msgstr "" +msgstr "Biblioteko" #: src/ListWindow.cxx:213 msgid "Range selection disabled" -msgstr "" +msgstr "Intervala elektado estas neaktiva" #: src/ListWindow.cxx:216 msgid "Range selection enabled" -msgstr "" +msgstr "Intervala elektado estas aktiva" #. translators: no lyrics were found for the song #: src/LyricsPage.cxx:253 msgid "No lyrics" -msgstr "" +msgstr "Neniuj kantotekstoj" #: src/LyricsPage.cxx:270 #, c-format msgid "Lyrics timeout occurred after %d seconds" -msgstr "" +msgstr "Elĉerpiĝis templimo por elŝuti kantotektojn post %d sekundoj" #: src/LyricsPage.cxx:353 src/LyricsPage.cxx:361 src/LyricsPage.cxx:371 #: src/LyricsPage.cxx:507 msgid "Lyrics" -msgstr "" +msgstr "Kantotekstoj" #. translators: this message is displayed #. while data is retrieved #: src/LyricsPage.cxx:356 msgid "loading..." -msgstr "" +msgstr "ŝargante..." #: src/LyricsPage.cxx:378 msgid "Editor not configured" -msgstr "" +msgstr "Redaktilo ne estas agordita" #: src/LyricsPage.cxx:385 msgid "Do you really want to start an editor and edit these lyrics?" -msgstr "" +msgstr "Ĉu lanĉi redaktilon kaj redakti tiujn kantotekstojn?" #: src/LyricsPage.cxx:403 src/LyricsPage.cxx:427 msgid "Can't start editor" -msgstr "" +msgstr "Malsukcesis lanĉi redaktilon" #: src/LyricsPage.cxx:430 src/LyricsPage.cxx:434 msgid "Editor exited unexpectedly" -msgstr "" +msgstr "Redaktilo neatendite kolapsis" #. lyrics for the song were saved on hard disk #: src/LyricsPage.cxx:456 msgid "Lyrics saved" -msgstr "" +msgstr "Konserviĝis kantotekstoj" #: src/LyricsPage.cxx:462 msgid "Lyrics deleted" -msgstr "" +msgstr "Forviŝiĝis kantotekstoj" #: src/LyricsPage.cxx:463 msgid "No saved lyrics" -msgstr "" +msgstr "Neniuj konservitaj kantotekstoj" -#: src/Main.cxx:132 -#, fuzzy, c-format +#: src/Main.cxx:133 +#, c-format msgid "Connecting to %s" -msgstr "Konektite al %s" +msgstr "Konektante al %s" -#: src/Main.cxx:148 -#, fuzzy, c-format +#: src/Main.cxx:149 +#, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" -msgstr "Problemo: la versio %d.%d.%d de MPD estas tro malnova (necesas %s)" +msgstr "Eraro: la versio %d.%d.%d de MPD estas tro malnova (necesas %s)" #. To translators: these credits are shown #. when ncmpc is started with "--version" @@ -799,27 +803,44 @@ " Kristjan SCHMIDT https://launchpad.net/~kristjan-eo\n" " Max Kellermann https://launchpad.net/~max-duempel" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "Iris al dividaĵo '%s'" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Nomo" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" -msgstr "" +msgstr "Eligo '%s' estas aktiva" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" -msgstr "" +msgstr "Eligo '%s' estas neaktiva" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" -msgstr "" +msgstr "Eligoj" + +#: src/OutputsPage.cxx:383 +msgid "Partition" +msgstr "Dividaĵo" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "Krei novan dividaĵon" #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" -msgstr "" +msgstr "Miksiĝis vico" #: src/player_command.cxx:100 msgid "Cleared queue" -msgstr "" +msgstr "Malpleniĝis vico" #. get path #: src/QueuePage.cxx:314 @@ -828,58 +849,57 @@ #: src/QueuePage.cxx:379 src/QueuePage.cxx:697 msgid "Queue" -msgstr "" +msgstr "Vico" #: src/QueuePage.cxx:381 #, c-format msgid "Queue on %s" -msgstr "" +msgstr "Vico ĉe %s" #. query the user for a filename #: src/save_playlist.cxx:86 msgid "Save queue as" -msgstr "" +msgstr "Konservi vicon kiel" #: src/save_playlist.cxx:108 #, c-format msgid "Replace %s?" -msgstr "" +msgstr "Ĉu anstataŭigi %s?" #. success #: src/save_playlist.cxx:129 #, c-format msgid "Saved %s" -msgstr "" +msgstr "Konserviĝis %s" #: src/screen_client.cxx:41 -#, fuzzy msgid "Database update running" -msgstr "Ĝisdatigis datumbazon" +msgstr "Ĝisdatigante datenbankon" #: src/screen_client.cxx:48 #, c-format msgid "Database update of %s started" -msgstr "" +msgstr "Ekĝisdatiĝis datenbanko %s" #: src/screen_client.cxx:51 msgid "Database update started" -msgstr "" +msgstr "Ekĝisdatiĝis la datenbanko" #: src/screen.cxx:158 msgid "Repeat mode is on" -msgstr "" +msgstr "Ripeta reĝimo estas aktiva" #: src/screen.cxx:159 msgid "Repeat mode is off" -msgstr "" +msgstr "Ripeta reĝimo estas neaktiva" #: src/screen.cxx:163 msgid "Random mode is on" -msgstr "" +msgstr "Hazarda reĝimo estas aktiva" #: src/screen.cxx:164 msgid "Random mode is off" -msgstr "" +msgstr "Hazarda reĝimo estas neaktiva" #. "single" mode means #. that MPD will @@ -888,11 +908,11 @@ #. single song #: src/screen.cxx:173 msgid "Single mode is on" -msgstr "" +msgstr "Unuopa reĝimo estas aktiva" #: src/screen.cxx:174 msgid "Single mode is off" -msgstr "" +msgstr "Unuopa reĝimo estas neaktiva" #. "consume" mode means #. that MPD removes each @@ -900,16 +920,16 @@ #. finished playing #: src/screen.cxx:182 msgid "Consume mode is on" -msgstr "" +msgstr "Konsuma reĝimo estas aktiva" #: src/screen.cxx:183 msgid "Consume mode is off" -msgstr "" +msgstr "Konsuma reĝimo estas neaktiva" #: src/screen.cxx:186 #, c-format msgid "Crossfade %d seconds" -msgstr "" +msgstr "%d sekundoj da interfado" #: src/screen.cxx:198 msgid "Database updated" @@ -917,31 +937,31 @@ #: src/screen.cxx:248 msgid "Find mode: Wrapped" -msgstr "" +msgstr "Serĉa reĝimo: Linifalda" #: src/screen.cxx:249 msgid "Find mode: Normal" -msgstr "" +msgstr "Serĉa reĝimo: Normala" #: src/screen.cxx:254 msgid "Auto center mode: On" -msgstr "" +msgstr "Aŭtomate centriga reĝimo: Aktiva" #: src/screen.cxx:255 msgid "Auto center mode: Off" -msgstr "" +msgstr "Aŭtomate centriga reĝimo: Neaktiva" #: src/screen_find.cxx:33 msgid "Find" -msgstr "" +msgstr "Serĉi" #: src/screen_find.cxx:34 msgid "Find backward" -msgstr "" +msgstr "Serĉi komencen" #: src/screen_find.cxx:35 msgid "Jump" -msgstr "" +msgstr "Salti" #: src/screen_find.cxx:81 #, c-format @@ -950,249 +970,253 @@ #: src/screen_utils.cxx:150 msgid "Password" -msgstr "" +msgstr "Pasvorto" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" -msgstr "" +msgstr "muzikisto" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" -msgstr "" +msgstr "albumo" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" -msgstr "" +msgstr "titolo" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" -msgstr "" +msgstr "trako" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" -msgstr "" +msgstr "nomo" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" -msgstr "" +msgstr "ĝenro" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "dato" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" -msgstr "" +msgstr "komponisto" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" -msgstr "" +msgstr "interpretisto" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" -msgstr "" +msgstr "komento" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "dosiero" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Titolo" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" -msgstr "" +msgstr "Muzikisto" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" -msgstr "" +msgstr "Albumo" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Dosiernomo" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" -msgstr "" +msgstr "Muzikisto + Titolo" + +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "Nekonata sufikso" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" -msgstr "" +msgstr "Nekonata serĉa etikedo %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" -msgstr "" +msgstr "Mankas argumento de serĉa etikedo %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" -msgstr "" +msgstr "Serĉi" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" -msgstr "" +msgstr "Serĉa reĝimo: %s" #: src/SongPage.cxx:65 msgid "Length" -msgstr "" +msgstr "Longo" #: src/SongPage.cxx:66 msgid "Position" -msgstr "" +msgstr "Pozicio" #: src/SongPage.cxx:67 msgid "Composer" -msgstr "" +msgstr "Komponisto" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "" +msgid "Performer" +msgstr "Interpretisto" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" -msgstr "" +msgstr "Disko" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" -msgstr "" +msgstr "Trako" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" -msgstr "" +msgstr "Dato" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" -msgstr "" +msgstr "Ĝenro" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" -msgstr "" +msgstr "Komento" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" -msgstr "" +msgstr "Loko" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" -msgstr "" +msgstr "Bitrapido" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" -msgstr "" +msgstr "Formo" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" -msgstr "" +msgstr "Nombro de muzikistoj" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" -msgstr "" +msgstr "Nombro de albumoj" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" -msgstr "" +msgstr "Nombro de kantoj" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" -msgstr "" +msgstr "Daŭro de funkciado" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" -msgstr "" +msgstr "Lasta ĝisdatigo de datenbanko" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" -msgstr "" +msgstr "Daŭro de ludado" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" -msgstr "" +msgstr "Daŭro de datenbanka ludado" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" -msgstr "" +msgstr "Kantovidigilo" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" -msgstr "" +msgstr "Statistikoj pri MPD" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" -msgstr "" +msgstr "Elektita kanto" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" -msgstr "" +msgstr "Nuntempe ludata kanto" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" -msgstr "" +msgstr "%d kilobitoj/sek" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" -msgstr "" +msgstr "Kanto" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" -msgstr "" +msgstr "Ludanta:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" -msgstr "" +msgstr "Paŭzita" #: src/Styles.cxx:252 src/Styles.cxx:313 msgid "Unknown color" -msgstr "" +msgstr "Nekonata koloro" #: src/Styles.cxx:323 msgid "Unknown color field" -msgstr "" +msgstr "Nekonata kolorkampo" #: src/Styles.cxx:356 msgid "Terminal lacks color capabilities" -msgstr "" +msgstr "Al la terminalo mankas koloraj kapabloj" #: src/TagListPage.cxx:71 msgid "All tracks" -msgstr "" +msgstr "Ĉiuj trakoj" #: src/time_format.cxx:44 msgid "year" -msgstr "" +msgstr "jaro" #: src/time_format.cxx:46 msgid "years" -msgstr "" +msgstr "jaroj" #: src/time_format.cxx:54 msgid "week" -msgstr "" +msgstr "semajno" #: src/time_format.cxx:57 msgid "weeks" -msgstr "" +msgstr "semajnoj" #: src/time_format.cxx:65 msgid "day" -msgstr "" +msgstr "tago" #: src/time_format.cxx:68 msgid "days" -msgstr "" +msgstr "tagoj" #: src/TitleBar.cxx:101 msgid "Volume n/a" -msgstr "" +msgstr "Laŭto n/a" #: src/TitleBar.cxx:103 #, c-format msgid "Volume %d%%" -msgstr "" +msgstr "Laŭto %d%%" #~ msgid "Connecting to %s... Press %s to abort" #~ msgstr "Konektiĝado al %s... Premu %s por ĉesigi"
View file
ncmpc-0.36.tar.xz/po/es.po -> ncmpc-0.47.tar.xz/po/es.po
Changed
@@ -12,342 +12,339 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2012-01-30 07:08+0000\n" -"Last-Translator: Adolfo Jayme Barrientos <fitoschido@gmail.com>\n" -"Language-Team: es\n" -"Language: \n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2021-12-29 10:52+0000\n" +"Last-Translator: badlop <badlop@process-one.net>\n" +"Language-Team: Spanish <https://hosted.weblate.org/projects/ncmpc/" +"translations/es/>\n" +"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.10.1\n" "X-Launchpad-Export-Date: 2013-04-11 07:56+0000\n" -"X-Generator: Launchpad (build 16550)\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "Tecla %s asignada a %s y %s" #: src/ChatPage.cxx:64 src/ChatPage.cxx:182 msgid "Chat" -msgstr "" +msgstr "Chat" #: src/ChatPage.cxx:163 msgid "Your message" -msgstr "" +msgstr "Su mensaje" #: src/ChatPage.cxx:172 msgid "Message could not be sent" -msgstr "" +msgstr "El mensaje no pudo ser enviado" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "Configuración de teclas" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Salir" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "Mover el cursor hacia arriba" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "Mover el cursor hacia abajo" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "Mover el cursor hasta el principio de la pantalla" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "Mover el cursor hasta la mitad de la pantalla" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "Mover el cursor hasta el final de la pantalla" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "Mover el cursor hasta el principio de la lista" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "Mover el cursor hasta el final de la lista" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "Página arriba" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "Página abajo" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "Selección del rango" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "Bajar una linea" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "Subir una linea" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "Subir media pantalla" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "Bajar media pantalla" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "Seleccionar la actual canción en reproducción" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "Ayuda" -#: src/Command.cxx:71 src/HelpPage.cxx:140 -#, fuzzy +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" -msgstr "Pantalla de teclas de acceso" +msgstr "Pantalla de espera" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "Navegador" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "Reproducir/Entrar en el directorio" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Pausa" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "Parar" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "Reducir lista de canciónes a canción marcado" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "Siguiente" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Anterior" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "Avanzar" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "Retroceder" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "Subir el volumen" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "Bajar el volumen" -#: src/Command.cxx:98 -#, fuzzy +#: src/Command.cxx:99 msgid "Select/deselect song in queue" msgstr "Seleccionar/Deseleccionar la canción en la lista" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Seleccionar todos" -#: src/Command.cxx:102 -#, fuzzy +#: src/Command.cxx:103 msgid "Delete song from queue" msgstr "Borrar la canción de la lista" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" -msgstr "" +msgstr "Aleatorizar la lista" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" -msgstr "" +msgstr "Vaciar la lista" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "Alternar modo repetición" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "Alternar modo aleatorio" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "Alternar modo compacto" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "Alternar modo completo" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "Alternar modo crossfade" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "Iniciar la actualización de la BD musical" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" -msgstr "" +msgstr "Guardar lista" -#: src/Command.cxx:122 src/HelpPage.cxx:174 -#, fuzzy +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" -msgstr "Añadir la canción de la lista" +msgstr "Añadir la canción a la lista" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "Entrar al directorio fundamental" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "Entrar al directorio superior" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "Encontrar la canción en el navegador" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "Moverlo arriba" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "Moverlo abajo" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "Actualizar la ventana" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "Alternar modo de búsqueda" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "Alternar centrado automático de la ventana" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "Pantalla siguiente" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "Pantalla anterior" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "Volver a la anterior pantalla" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "Buscar hacia adelante" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "Buscar siguiente" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "Buscar hacia atrás" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "Buscar anterior" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "Saltar a" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" -msgstr "" +msgstr "Página de la librería" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Búsqueda" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "Cambiar el modo de búsqueda" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "Ver la canción seleccionada y reproducida" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "Letras" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "Interrumpir la acción" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "Actualizar las letras" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" -msgstr "" +msgstr "Editar el elemento actual" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "Pantalla de salidas" -#: src/Command.cxx:214 src/HelpPage.cxx:203 -#, fuzzy +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" -msgstr "Pantalla siguiente" +msgstr "Pantalla del chat" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" -msgstr "" +msgstr "Se esperaba una palabra" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "Definición incorrecta de la tecla de acceso" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "Configuración incompleta de la tecla de acceso" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "Comando desconocido" @@ -359,29 +356,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "Configuración incorrecta del tipo de duración mostrada" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "Falta un '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "Nombre de color incorrecto" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "Definición de color incompleta" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "Número inválido" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "Definición de color erronea" @@ -390,24 +387,23 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "Nombre de pantalla desconocido" -#: src/ConfigParser.cxx:403 -#, fuzzy +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" -msgstr "Comando desconocido" +msgstr "Etiqueta MPD desconocida" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "Modo de búsqueda inválido" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "No se reconoce el modo de búsqueda" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "Parámetro de configuración desconocido" @@ -418,141 +414,138 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "No se puede borrar el elemento" -#: src/FileBrowserPage.cxx:256 -#, fuzzy, c-format +#: src/FileBrowserPage.cxx:254 +#, c-format msgid "Delete playlist %s?" -msgstr "Borrar la lista de canciones" +msgstr "Eliminar la playlist %s?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Ejecución interrumpida" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "Lista de reproducción borrada" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Navegar" -#: src/FileListPage.cxx:119 -#, fuzzy, c-format +#: src/FileListPage.cxx:125 +#, c-format msgid "Loading playlist '%s'" -msgstr "Cargando la lista %s..." +msgstr "Cargando playlist \"%s\"" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 -#, fuzzy, c-format +#, c-format msgid "Adding '%s' to queue" -msgstr "Añadiendo '%s' a la lista de canciones" +msgstr "Añadiendo \"%s\" a la lista" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Navegar" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Global" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Reproducir" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "Centro" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Acceder al directorio/Seleccionar y reproducir canción" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Borrar la lista de canciones" -#: src/HelpPage.cxx:171 -#, fuzzy +#: src/HelpPage.cxx:172 msgid "New search" -msgstr "Búsqueda" +msgstr "Nueva búsqueda" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Seleccionar y reproducir" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "Ver letras" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "(Re)cargar letras" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Interrumpir la descarga" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "Obtener las letras de la canción reproducida" -#: src/HelpPage.cxx:189 -#, fuzzy +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" -msgstr "No hay letras guardadas" +msgstr "Añadir o editar la letra de la canción" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "Guardar las letras" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" msgstr "Borrar letras guardadas" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Activar/desactivar la salida" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" -msgstr "" +msgstr "Escribir un mensaje" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Pantalla de teclas de acceso" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Cambia las teclas de acceso rápido para el comando seleccionado" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "ELiminar la tecla de acceso rápido seleccionada" -#: src/HelpPage.cxx:214 -#, fuzzy +#: src/HelpPage.cxx:215 msgid "Add a keydef" -msgstr "Introduce una nueva tecla" +msgstr "Añadir un nuevo atajo" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Subir un nivel" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Aplicar y guardar los cambios" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Ayuda" @@ -564,179 +557,178 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Borrado" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "Introduce tecla de acceso rápido para %s: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" -msgstr "" +msgstr "Ctrl-Space no se puede utilizar" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Error: la tecla %s ya está asignada a %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "%s asignada a %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Introduce una nueva tecla" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "Cambia las teclas para %s" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "Has definido nuevas teclas de acceso rápido" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "Las teclas de acceso rápido no han sido modificadas." -#: src/KeyDefPage.cxx:406 -#, fuzzy +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" -msgstr "Configuración incompleta de la tecla de acceso" +msgstr "No se puede escribir la configuración" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "Error" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "%s creado" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "===> Aplicar las teclas de acceso rápido " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "===> Aplicar y guardar las teclas de acceso rápido " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "Cambia las teclas de acceso rápido" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "Nota: Has olvidado 'Aplicar' tus cambios?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" -msgstr "" +msgstr "Teclas" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "Indefinido" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Espacio" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Enter" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "Backspace" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Borrar" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Arriba" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Abajo" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "Izquierda" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "Derecha" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Inicio" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "Fin" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "Pagina siguiente" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "Pagina anterior" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tabulador" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Shift+Tabulador" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Insertar" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" -msgstr "" +msgstr "Ctrl-%c" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" -msgstr "" +msgstr "Alt-%c" #: src/LibraryPage.cxx:45 -#, fuzzy msgid "Artists" -msgstr "Artista" +msgstr "Artistas" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 -#, fuzzy +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 msgid "Albums" -msgstr "Álbum" +msgstr "Álbums" #: src/LibraryPage.cxx:123 msgid "All" -msgstr "" +msgstr "Todo" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" -msgstr "" +msgstr "Canciones" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" -msgstr "" +msgstr "Librería" #: src/ListWindow.cxx:213 msgid "Range selection disabled" @@ -754,7 +746,7 @@ #: src/LyricsPage.cxx:270 #, c-format msgid "Lyrics timeout occurred after %d seconds" -msgstr "" +msgstr "El tiempo de espera de la letra ocurrió después de %d segundos" #: src/LyricsPage.cxx:353 src/LyricsPage.cxx:361 src/LyricsPage.cxx:371 #: src/LyricsPage.cxx:507 @@ -769,19 +761,19 @@ #: src/LyricsPage.cxx:378 msgid "Editor not configured" -msgstr "" +msgstr "El editor no está configurado" #: src/LyricsPage.cxx:385 msgid "Do you really want to start an editor and edit these lyrics?" -msgstr "" +msgstr "Estás seguro de que quieres empezar un editor y editar estas letras?" #: src/LyricsPage.cxx:403 src/LyricsPage.cxx:427 msgid "Can't start editor" -msgstr "" +msgstr "No se puede iniciar el editor" #: src/LyricsPage.cxx:430 src/LyricsPage.cxx:434 msgid "Editor exited unexpectedly" -msgstr "" +msgstr "El editor salió inesperadamente" #. lyrics for the song were saved on hard disk #: src/LyricsPage.cxx:456 @@ -796,17 +788,17 @@ msgid "No saved lyrics" msgstr "No hay letras guardadas" -#: src/Main.cxx:132 -#, fuzzy, c-format +#: src/Main.cxx:133 +#, c-format msgid "Connecting to %s" -msgstr "Conectado a %s" +msgstr "Conectando a %s" -#: src/Main.cxx:148 -#, fuzzy, c-format +#: src/Main.cxx:149 +#, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "" -"Error: La versión %d.%d.%d del MPD es demasiado antigua (se necesita al " -"menos la %s)" +"Error: La versión %d.%d.%d del MPD es demasiado vieja (se necesita al menos " +"%s)" #. To translators: these credits are shown #. when ncmpc is started with "--version" @@ -823,27 +815,44 @@ " Monkey https://launchpad.net/~monkey-libre\n" " Paco Molinero https://launchpad.net/~franciscomol" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "Cambiado a la partición '%s'" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Nombre" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "Se activó la salida '%s'" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "Se desactivó la salida '%s'" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Salidas" +#: src/OutputsPage.cxx:383 +msgid "Partition" +msgstr "División" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "Crear una nueva división" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" -msgstr "" +msgstr "Lista aleatoria" #: src/player_command.cxx:100 msgid "Cleared queue" -msgstr "" +msgstr "Lista vaciada" #. get path #: src/QueuePage.cxx:314 @@ -852,22 +861,22 @@ #: src/QueuePage.cxx:379 src/QueuePage.cxx:697 msgid "Queue" -msgstr "" +msgstr "Lista" #: src/QueuePage.cxx:381 #, c-format msgid "Queue on %s" -msgstr "" +msgstr "Lista en %s" #. query the user for a filename #: src/save_playlist.cxx:86 msgid "Save queue as" -msgstr "" +msgstr "Guardar lista como" #: src/save_playlist.cxx:108 -#, fuzzy, c-format +#, c-format msgid "Replace %s?" -msgstr "Sustituir %s %s%s ? " +msgstr "Reemplazar %s?" #. success #: src/save_playlist.cxx:129 @@ -876,9 +885,8 @@ msgstr "%s Guardada" #: src/screen_client.cxx:41 -#, fuzzy msgid "Database update running" -msgstr "Actualizando la base de datos..." +msgstr "Actualización de la base de datos en marcha" #: src/screen_client.cxx:48 #, c-format @@ -976,86 +984,90 @@ msgid "Password" msgstr "Contraseña" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "artista" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "álbum" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "título" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "canción" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "nombre" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "estilo" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "fecha" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "compositor" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "intérprete" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "comentario" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "fichero" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Título" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Artista" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Álbum" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Nombre de archivo" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Artista + Título" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "Sufijo no reconocible" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Etiqueta de búsqueda inválida: %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "Sin argumentos para la etiqueta de búsqueda %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Búsqueda" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Modo de búsqueda: %s" @@ -1066,118 +1078,116 @@ #: src/SongPage.cxx:66 msgid "Position" -msgstr "" +msgstr "Posición" #: src/SongPage.cxx:67 msgid "Composer" msgstr "Compositor" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Nombre" +msgid "Performer" +msgstr "Intérprete" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Disco" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Pista" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Fecha" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Estilo" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Comentario" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Ruta" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Bitrate" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" -msgstr "" +msgstr "Formato" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Número de artistas" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Número de álbumes" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Número de canciones" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "Tiempo de ejecución" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "Actualización más reciente de la BD" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "Tiempo de reproducción" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "Duración de la BD" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "Visor de la canción" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "Estadísticas del MPD" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "Canción seleccionada" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "Canción reproducida" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d kbps" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" -msgstr "" +msgstr "Canción" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Escuchando:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "Parado" #: src/Styles.cxx:252 src/Styles.cxx:313 -#, fuzzy msgid "Unknown color" -msgstr "Comando desconocido" +msgstr "Color desconocido" #: src/Styles.cxx:323 -#, fuzzy msgid "Unknown color field" -msgstr "Advertencia: Propiedad del color - %s no reconocida\n" +msgstr "Área de color desconocida" #: src/Styles.cxx:356 msgid "Terminal lacks color capabilities" @@ -1189,27 +1199,27 @@ #: src/time_format.cxx:44 msgid "year" -msgstr "" +msgstr "año" #: src/time_format.cxx:46 msgid "years" -msgstr "" +msgstr "años" #: src/time_format.cxx:54 msgid "week" -msgstr "" +msgstr "semana" #: src/time_format.cxx:57 msgid "weeks" -msgstr "" +msgstr "semanas" #: src/time_format.cxx:65 msgid "day" -msgstr "" +msgstr "día" #: src/time_format.cxx:68 msgid "days" -msgstr "" +msgstr "días" #: src/TitleBar.cxx:101 msgid "Volume n/a"
View file
ncmpc-0.47.tar.xz/po/fa.po
Added
@@ -0,0 +1,1211 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the ncmpc package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: ncmpc\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: fa\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/Bindings.cxx:80 src/Bindings.cxx:86 +#, c-format +msgid "Key %s assigned to %s and %s" +msgstr "" + +#: src/ChatPage.cxx:64 src/ChatPage.cxx:182 +msgid "Chat" +msgstr "" + +#: src/ChatPage.cxx:163 +msgid "Your message" +msgstr "" + +#: src/ChatPage.cxx:172 +msgid "Message could not be sent" +msgstr "" + +#: src/Command.cxx:30 +msgid "Key configuration screen" +msgstr "" + +#: src/Command.cxx:33 +msgid "Quit" +msgstr "" + +#: src/Command.cxx:37 +msgid "Move cursor up" +msgstr "" + +#: src/Command.cxx:39 +msgid "Move cursor down" +msgstr "" + +#: src/Command.cxx:41 +msgid "Move cursor to the top of screen" +msgstr "" + +#: src/Command.cxx:43 +msgid "Move cursor to the middle of screen" +msgstr "" + +#: src/Command.cxx:45 +msgid "Move cursor to the bottom of screen" +msgstr "" + +#: src/Command.cxx:47 +msgid "Move cursor to the top of the list" +msgstr "" + +#: src/Command.cxx:49 +msgid "Move cursor to the bottom of the list" +msgstr "" + +#: src/Command.cxx:51 +msgid "Page up" +msgstr "" + +#: src/Command.cxx:53 +msgid "Page down" +msgstr "" + +#: src/Command.cxx:55 +msgid "Range selection" +msgstr "" + +#: src/Command.cxx:57 +msgid "Scroll down one line" +msgstr "" + +#: src/Command.cxx:59 +msgid "Scroll up one line" +msgstr "" + +#: src/Command.cxx:61 +msgid "Scroll up half a screen" +msgstr "" + +#: src/Command.cxx:63 +msgid "Scroll down half a screen" +msgstr "" + +#: src/Command.cxx:65 +msgid "Select currently playing song" +msgstr "" + +#: src/Command.cxx:70 +msgid "Help screen" +msgstr "" + +#: src/Command.cxx:72 src/HelpPage.cxx:141 +msgid "Queue screen" +msgstr "" + +#: src/Command.cxx:74 src/HelpPage.cxx:156 +msgid "Browse screen" +msgstr "" + +#: src/Command.cxx:79 +msgid "Play/Enter directory" +msgstr "" + +#: src/Command.cxx:81 +msgid "Pause" +msgstr "" + +#: src/Command.cxx:83 +msgid "Stop" +msgstr "" + +#: src/Command.cxx:85 +msgid "Crop" +msgstr "" + +#: src/Command.cxx:87 +msgid "Next track" +msgstr "" + +#: src/Command.cxx:89 +msgid "Previous track" +msgstr "" + +#: src/Command.cxx:91 +msgid "Seek forward" +msgstr "" + +#: src/Command.cxx:93 +msgid "Seek backward" +msgstr "" + +#: src/Command.cxx:95 +msgid "Increase volume" +msgstr "" + +#: src/Command.cxx:97 +msgid "Decrease volume" +msgstr "" + +#: src/Command.cxx:99 +msgid "Select/deselect song in queue" +msgstr "" + +#: src/Command.cxx:101 +msgid "Select all listed items" +msgstr "" + +#: src/Command.cxx:103 +msgid "Delete song from queue" +msgstr "" + +#: src/Command.cxx:105 +msgid "Shuffle queue" +msgstr "" + +#: src/Command.cxx:107 +msgid "Clear queue" +msgstr "" + +#: src/Command.cxx:109 +msgid "Toggle repeat mode" +msgstr "" + +#: src/Command.cxx:111 +msgid "Toggle random mode" +msgstr "" + +#: src/Command.cxx:113 +msgid "Toggle single mode" +msgstr "" + +#: src/Command.cxx:115 +msgid "Toggle consume mode" +msgstr "" + +#: src/Command.cxx:117 +msgid "Toggle crossfade mode" +msgstr "" + +#: src/Command.cxx:119 +msgid "Start a music database update" +msgstr "" + +#: src/Command.cxx:121 +msgid "Save queue" +msgstr "" + +#: src/Command.cxx:123 src/HelpPage.cxx:175 +msgid "Append song to queue" +msgstr "" + +#: src/Command.cxx:126 +msgid "Go to root directory" +msgstr "" + +#: src/Command.cxx:128 +msgid "Go to parent directory" +msgstr "" + +#: src/Command.cxx:131 +msgid "Locate song in browser" +msgstr "" + +#: src/Command.cxx:135 +msgid "Move item up" +msgstr "" + +#: src/Command.cxx:137 +msgid "Move item down" +msgstr "" + +#: src/Command.cxx:139 +msgid "Refresh screen" +msgstr "" + +#. translators: toggle between wrapping and non-wrapping +#. search +#: src/Command.cxx:146 +msgid "Toggle find mode" +msgstr "" + +#. translators: the auto center mode always centers the song +#. currently being played +#: src/Command.cxx:150 +msgid "Toggle auto center mode" +msgstr "" + +#: src/Command.cxx:155 +msgid "Next screen" +msgstr "" + +#: src/Command.cxx:157 +msgid "Previous screen" +msgstr "" + +#: src/Command.cxx:159 +msgid "Swap to most recent screen" +msgstr "" + +#: src/Command.cxx:164 +msgid "Forward find" +msgstr "" + +#: src/Command.cxx:166 +msgid "Forward find next" +msgstr "" + +#: src/Command.cxx:168 +msgid "Backward find" +msgstr "" + +#: src/Command.cxx:170 +msgid "Backward find previous" +msgstr "" + +#. translators: this queries the user for a string +#. * and jumps directly (while the user is typing) +#. * to the entry which begins with this string +#: src/Command.cxx:175 +msgid "Jump to" +msgstr "" + +#: src/Command.cxx:181 +msgid "Library page" +msgstr "" + +#: src/Command.cxx:185 src/HelpPage.cxx:170 +msgid "Search screen" +msgstr "" + +#: src/Command.cxx:187 +msgid "Change search mode" +msgstr "" + +#: src/Command.cxx:191 +msgid "View the selected and the currently playing song" +msgstr "" + +#: src/Command.cxx:195 src/HelpPage.cxx:182 +msgid "Lyrics screen" +msgstr "" + +#. translators: interrupt the current background action, +#. e.g. stop loading lyrics from the internet +#: src/Command.cxx:199 +msgid "Interrupt action" +msgstr "" + +#: src/Command.cxx:201 +msgid "Update Lyrics" +msgstr "" + +#: src/Command.cxx:205 +msgid "Edit the current item" +msgstr "" + +#: src/Command.cxx:210 src/HelpPage.cxx:197 +msgid "Outputs screen" +msgstr "" + +#: src/Command.cxx:215 src/HelpPage.cxx:204 +msgid "Chat screen" +msgstr "" + +#: src/ConfigParser.cxx:120 +msgid "Word expected" +msgstr "" + +#: src/ConfigParser.cxx:139 +msgid "Malformed hotkey definition" +msgstr "" + +#. the hotkey configuration +#. line is incomplete +#: src/ConfigParser.cxx:158 +msgid "Incomplete hotkey configuration" +msgstr "" + +#. the hotkey configuration +#. contains an unknown +#. command +#: src/ConfigParser.cxx:172 +msgid "Unknown command" +msgstr "" + +#. translators: ncmpc +#. supports displaying the +#. "elapsed" or "remaining" +#. time of a song being +#. played; in this case, the +#. configuration file +#. contained an invalid +#. setting +#: src/ConfigParser.cxx:210 +msgid "Bad time display type" +msgstr "" + +#. an equals sign '=' was expected while parsing a +#. configuration file line +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 +msgid "Missing '='" +msgstr "" + +#: src/ConfigParser.cxx:273 +msgid "Bad color name" +msgstr "" + +#: src/ConfigParser.cxx:282 +msgid "Incomplete color definition" +msgstr "" + +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 +msgid "Invalid number" +msgstr "" + +#: src/ConfigParser.cxx:295 +msgid "Malformed color definition" +msgstr "" + +#. an unknown screen +#. name was specified +#. in the +#. configuration +#. file +#: src/ConfigParser.cxx:359 +msgid "Unknown screen name" +msgstr "" + +#: src/ConfigParser.cxx:388 +msgid "Unknown MPD tag" +msgstr "" + +#: src/ConfigParser.cxx:415 +msgid "Invalid search mode" +msgstr "" + +#: src/ConfigParser.cxx:433 +msgid "Unknown search mode" +msgstr "" + +#: src/ConfigParser.cxx:621 +msgid "Unknown configuration parameter" +msgstr "" + +#: src/CustomColors.cxx:57 +msgid "Terminal lacks support for changing colors" +msgstr "" + +#. translators: the "delete" command is only possible +#. for playlists; the user attempted to delete a song +#. or a directory or something else +#: src/FileBrowserPage.cxx:246 +msgid "Deleting this item is not possible" +msgstr "" + +#: src/FileBrowserPage.cxx:254 +#, c-format +msgid "Delete playlist %s?" +msgstr "" + +#. translators: a dialog was aborted by the user +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 +#: src/save_playlist.cxx:111 +msgid "Aborted" +msgstr "" + +#. translators: MPD deleted the playlist, as requested by the +#. user +#: src/FileBrowserPage.cxx:272 +msgid "Playlist deleted" +msgstr "" + +#. translators: caption of the browser screen +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 +msgid "Browse" +msgstr "" + +#: src/FileListPage.cxx:125 +#, c-format +msgid "Loading playlist '%s'" +msgstr "" + +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 +#: src/TagListPage.cxx:184 +#, c-format +msgid "Adding '%s' to queue" +msgstr "" + +#: src/HelpPage.cxx:61 +msgid "Movement" +msgstr "" + +#: src/HelpPage.cxx:106 +msgid "Global" +msgstr "" + +#: src/HelpPage.cxx:143 +msgid "Play" +msgstr "" + +#: src/HelpPage.cxx:150 +msgid "Center" +msgstr "" + +#: src/HelpPage.cxx:158 +msgid "Enter directory/Select and play song" +msgstr "" + +#: src/HelpPage.cxx:162 +msgid "Delete playlist" +msgstr "" + +#: src/HelpPage.cxx:172 +msgid "New search" +msgstr "" + +#: src/HelpPage.cxx:173 +msgid "Select and play" +msgstr "" + +#: src/HelpPage.cxx:184 +msgid "View Lyrics" +msgstr "" + +#: src/HelpPage.cxx:185 +msgid "(Re)load lyrics" +msgstr "" + +#. to translators: this hotkey aborts the retrieval of lyrics +#. from the server +#: src/HelpPage.cxx:188 +msgid "Interrupt retrieval" +msgstr "" + +#: src/HelpPage.cxx:189 +msgid "Download lyrics for currently playing song" +msgstr "" + +#: src/HelpPage.cxx:190 +msgid "Add or edit lyrics" +msgstr "" + +#: src/HelpPage.cxx:191 +msgid "Save lyrics" +msgstr "" + +#: src/HelpPage.cxx:192 +msgid "Delete saved lyrics" +msgstr "" + +#: src/HelpPage.cxx:199 +msgid "Enable/disable output" +msgstr "" + +#: src/HelpPage.cxx:206 +msgid "Write a message" +msgstr "" + +#: src/HelpPage.cxx:211 +msgid "Keydef screen" +msgstr "" + +#: src/HelpPage.cxx:213 +msgid "Edit keydefs for selected command" +msgstr "" + +#: src/HelpPage.cxx:214 +msgid "Remove selected keydef" +msgstr "" + +#: src/HelpPage.cxx:215 +msgid "Add a keydef" +msgstr "" + +#: src/HelpPage.cxx:216 +msgid "Go up a level" +msgstr "" + +#: src/HelpPage.cxx:217 +msgid "Apply and save changes" +msgstr "" + +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 +msgid "Help" +msgstr "" + +#: src/i18n.h:43 +msgid "y" +msgstr "" + +#: src/i18n.h:44 +msgid "n" +msgstr "" + +#: src/KeyDefPage.cxx:161 +msgid "Deleted" +msgstr "" + +#: src/KeyDefPage.cxx:177 +#, c-format +msgid "Enter new key for %s: " +msgstr "" + +#: src/KeyDefPage.cxx:187 +msgid "Ctrl-Space can't be used" +msgstr "" + +#: src/KeyDefPage.cxx:193 +#, c-format +msgid "Error: key %s is already used for %s" +msgstr "" + +#: src/KeyDefPage.cxx:203 +#, c-format +msgid "Assigned %s to %s" +msgstr "" + +#: src/KeyDefPage.cxx:230 +msgid "Add new key" +msgstr "" + +#: src/KeyDefPage.cxx:252 +#, c-format +msgid "Edit keys for %s" +msgstr "" + +#: src/KeyDefPage.cxx:395 +msgid "You have new key bindings" +msgstr "" + +#: src/KeyDefPage.cxx:397 +msgid "Keybindings unchanged." +msgstr "" + +#: src/KeyDefPage.cxx:407 +msgid "Unable to write configuration" +msgstr "" + +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 +msgid "Error" +msgstr "" + +#: src/KeyDefPage.cxx:423 +#, c-format +msgid "Wrote %s" +msgstr "" + +#: src/KeyDefPage.cxx:436 +msgid "===> Apply key bindings " +msgstr "" + +#: src/KeyDefPage.cxx:438 +msgid "===> Apply & Save key bindings " +msgstr "" + +#: src/KeyDefPage.cxx:475 +msgid "Edit key bindings" +msgstr "" + +#: src/KeyDefPage.cxx:557 +msgid "Note: Did you forget to 'Apply' your changes?" +msgstr "" + +#: src/KeyDefPage.cxx:607 +msgid "Keys" +msgstr "" + +#: src/KeyName.cxx:115 +msgid "Undefined" +msgstr "" + +#: src/KeyName.cxx:117 +msgid "Space" +msgstr "" + +#: src/KeyName.cxx:119 +msgid "Enter" +msgstr "" + +#: src/KeyName.cxx:121 +msgid "Backspace" +msgstr "" + +#: src/KeyName.cxx:123 +msgid "Delete" +msgstr "" + +#: src/KeyName.cxx:125 +msgid "Up" +msgstr "" + +#: src/KeyName.cxx:127 +msgid "Down" +msgstr "" + +#: src/KeyName.cxx:129 +msgid "Left" +msgstr "" + +#: src/KeyName.cxx:131 +msgid "Right" +msgstr "" + +#: src/KeyName.cxx:133 +msgid "Home" +msgstr "" + +#: src/KeyName.cxx:135 +msgid "End" +msgstr "" + +#: src/KeyName.cxx:137 +msgid "PageDown" +msgstr "" + +#: src/KeyName.cxx:139 +msgid "PageUp" +msgstr "" + +#: src/KeyName.cxx:141 +msgid "Tab" +msgstr "" + +#: src/KeyName.cxx:143 +msgid "Shift+Tab" +msgstr "" + +#: src/KeyName.cxx:145 +msgid "Esc" +msgstr "" + +#: src/KeyName.cxx:147 +msgid "Insert" +msgstr "" + +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 +#, c-format +msgid "Ctrl-%c" +msgstr "" + +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 +#, c-format +msgid "Alt-%c" +msgstr "" + +#: src/LibraryPage.cxx:45 +msgid "Artists" +msgstr "" + +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 +msgid "Albums" +msgstr "" + +#: src/LibraryPage.cxx:123 +msgid "All" +msgstr "" + +#: src/LibraryPage.cxx:197 +msgid "Songs" +msgstr "" + +#: src/LibraryPage.cxx:314 +msgid "Library" +msgstr "" + +#: src/ListWindow.cxx:213 +msgid "Range selection disabled" +msgstr "" + +#: src/ListWindow.cxx:216 +msgid "Range selection enabled" +msgstr "" + +#. translators: no lyrics were found for the song +#: src/LyricsPage.cxx:253 +msgid "No lyrics" +msgstr "" + +#: src/LyricsPage.cxx:270 +#, c-format +msgid "Lyrics timeout occurred after %d seconds" +msgstr "" + +#: src/LyricsPage.cxx:353 src/LyricsPage.cxx:361 src/LyricsPage.cxx:371 +#: src/LyricsPage.cxx:507 +msgid "Lyrics" +msgstr "" + +#. translators: this message is displayed +#. while data is retrieved +#: src/LyricsPage.cxx:356 +msgid "loading..." +msgstr "" + +#: src/LyricsPage.cxx:378 +msgid "Editor not configured" +msgstr "" + +#: src/LyricsPage.cxx:385 +msgid "Do you really want to start an editor and edit these lyrics?" +msgstr "" + +#: src/LyricsPage.cxx:403 src/LyricsPage.cxx:427 +msgid "Can't start editor" +msgstr "" + +#: src/LyricsPage.cxx:430 src/LyricsPage.cxx:434 +msgid "Editor exited unexpectedly" +msgstr "" + +#. lyrics for the song were saved on hard disk +#: src/LyricsPage.cxx:456 +msgid "Lyrics saved" +msgstr "" + +#: src/LyricsPage.cxx:462 +msgid "Lyrics deleted" +msgstr "" + +#: src/LyricsPage.cxx:463 +msgid "No saved lyrics" +msgstr "" + +#: src/Main.cxx:133 +#, c-format +msgid "Connecting to %s" +msgstr "" + +#: src/Main.cxx:149 +#, c-format +msgid "Error: MPD version %d.%d.%d is too old (%s needed)" +msgstr "" + +#. To translators: these credits are shown +#. when ncmpc is started with "--version" +#: src/Options.cxx:216 src/Options.cxx:219 +msgid "translator-credits" +msgstr "" + +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "" + +#: src/OutputsPage.cxx:230 +#, c-format +msgid "Output '%s' enabled" +msgstr "" + +#: src/OutputsPage.cxx:241 +#, c-format +msgid "Output '%s' disabled" +msgstr "" + +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 +msgid "Outputs" +msgstr "" + +#: src/OutputsPage.cxx:383 +msgid "Partition" +msgstr "" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "" + +#: src/player_command.cxx:94 src/QueuePage.cxx:651 +msgid "Shuffled queue" +msgstr "" + +#: src/player_command.cxx:100 +msgid "Cleared queue" +msgstr "" + +#. get path +#: src/QueuePage.cxx:314 +msgid "Add" +msgstr "" + +#: src/QueuePage.cxx:379 src/QueuePage.cxx:697 +msgid "Queue" +msgstr "" + +#: src/QueuePage.cxx:381 +#, c-format +msgid "Queue on %s" +msgstr "" + +#. query the user for a filename +#: src/save_playlist.cxx:86 +msgid "Save queue as" +msgstr "" + +#: src/save_playlist.cxx:108 +#, c-format +msgid "Replace %s?" +msgstr "" + +#. success +#: src/save_playlist.cxx:129 +#, c-format +msgid "Saved %s" +msgstr "" + +#: src/screen_client.cxx:41 +msgid "Database update running" +msgstr "" + +#: src/screen_client.cxx:48 +#, c-format +msgid "Database update of %s started" +msgstr "" + +#: src/screen_client.cxx:51 +msgid "Database update started" +msgstr "" + +#: src/screen.cxx:158 +msgid "Repeat mode is on" +msgstr "" + +#: src/screen.cxx:159 +msgid "Repeat mode is off" +msgstr "" + +#: src/screen.cxx:163 +msgid "Random mode is on" +msgstr "" + +#: src/screen.cxx:164 +msgid "Random mode is off" +msgstr "" + +#. "single" mode means +#. that MPD will +#. automatically stop +#. after playing one +#. single song +#: src/screen.cxx:173 +msgid "Single mode is on" +msgstr "" + +#: src/screen.cxx:174 +msgid "Single mode is off" +msgstr "" + +#. "consume" mode means +#. that MPD removes each +#. song which has +#. finished playing +#: src/screen.cxx:182 +msgid "Consume mode is on" +msgstr "" + +#: src/screen.cxx:183 +msgid "Consume mode is off" +msgstr "" + +#: src/screen.cxx:186 +#, c-format +msgid "Crossfade %d seconds" +msgstr "" + +#: src/screen.cxx:198 +msgid "Database updated" +msgstr "" + +#: src/screen.cxx:248 +msgid "Find mode: Wrapped" +msgstr "" + +#: src/screen.cxx:249 +msgid "Find mode: Normal" +msgstr "" + +#: src/screen.cxx:254 +msgid "Auto center mode: On" +msgstr "" + +#: src/screen.cxx:255 +msgid "Auto center mode: Off" +msgstr "" + +#: src/screen_find.cxx:33 +msgid "Find" +msgstr "" + +#: src/screen_find.cxx:34 +msgid "Find backward" +msgstr "" + +#: src/screen_find.cxx:35 +msgid "Jump" +msgstr "" + +#: src/screen_find.cxx:81 +#, c-format +msgid "Unable to find '%s'" +msgstr "" + +#: src/screen_utils.cxx:150 +msgid "Password" +msgstr "" + +#: src/SearchPage.cxx:51 +msgid "artist" +msgstr "" + +#: src/SearchPage.cxx:52 +msgid "album" +msgstr "" + +#: src/SearchPage.cxx:53 +msgid "title" +msgstr "" + +#: src/SearchPage.cxx:54 +msgid "track" +msgstr "" + +#: src/SearchPage.cxx:55 +msgid "name" +msgstr "" + +#: src/SearchPage.cxx:56 +msgid "genre" +msgstr "" + +#: src/SearchPage.cxx:57 +msgid "date" +msgstr "" + +#: src/SearchPage.cxx:58 +msgid "composer" +msgstr "" + +#: src/SearchPage.cxx:59 +msgid "performer" +msgstr "" + +#: src/SearchPage.cxx:60 +msgid "comment" +msgstr "" + +#: src/SearchPage.cxx:68 +msgid "file" +msgstr "" + +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 +msgid "Title" +msgstr "" + +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 +msgid "Artist" +msgstr "" + +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 +msgid "Album" +msgstr "" + +#: src/SearchPage.cxx:93 +msgid "Filename" +msgstr "" + +#: src/SearchPage.cxx:94 +msgid "Artist + Title" +msgstr "" + +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "" + +#: src/SearchPage.cxx:337 +#, c-format +msgid "Bad search tag %s" +msgstr "" + +#: src/SearchPage.cxx:351 +#, c-format +msgid "No argument for search tag %s" +msgstr "" + +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 +msgid "Search" +msgstr "" + +#: src/SearchPage.cxx:509 +#, c-format +msgid "Search mode: %s" +msgstr "" + +#: src/SongPage.cxx:65 +msgid "Length" +msgstr "" + +#: src/SongPage.cxx:66 +msgid "Position" +msgstr "" + +#: src/SongPage.cxx:67 +msgid "Composer" +msgstr "" + +#: src/SongPage.cxx:68 +msgid "Performer" +msgstr "" + +#: src/SongPage.cxx:70 +msgid "Disc" +msgstr "" + +#: src/SongPage.cxx:71 +msgid "Track" +msgstr "" + +#: src/SongPage.cxx:72 +msgid "Date" +msgstr "" + +#: src/SongPage.cxx:73 +msgid "Genre" +msgstr "" + +#: src/SongPage.cxx:74 +msgid "Comment" +msgstr "" + +#: src/SongPage.cxx:75 +msgid "Path" +msgstr "" + +#: src/SongPage.cxx:76 +msgid "Bitrate" +msgstr "" + +#: src/SongPage.cxx:77 +msgid "Format" +msgstr "" + +#: src/SongPage.cxx:94 +msgid "Number of artists" +msgstr "" + +#: src/SongPage.cxx:95 +msgid "Number of albums" +msgstr "" + +#: src/SongPage.cxx:96 +msgid "Number of songs" +msgstr "" + +#: src/SongPage.cxx:97 +msgid "Uptime" +msgstr "" + +#: src/SongPage.cxx:98 +msgid "Most recent db update" +msgstr "" + +#: src/SongPage.cxx:99 +msgid "Playtime" +msgstr "" + +#: src/SongPage.cxx:100 +msgid "DB playtime" +msgstr "" + +#: src/SongPage.cxx:205 +msgid "Song viewer" +msgstr "" + +#: src/SongPage.cxx:371 +msgid "MPD statistics" +msgstr "" + +#: src/SongPage.cxx:457 +msgid "Selected song" +msgstr "" + +#: src/SongPage.cxx:467 +msgid "Currently playing song" +msgstr "" + +#: src/SongPage.cxx:472 +#, c-format +msgid "%d kbps" +msgstr "" + +#: src/SongPage.cxx:556 +msgid "Song" +msgstr "" + +#: src/StatusBar.cxx:165 +msgid "Playing:" +msgstr "" + +#: src/StatusBar.cxx:169 +msgid "Paused" +msgstr "" + +#: src/Styles.cxx:252 src/Styles.cxx:313 +msgid "Unknown color" +msgstr "" + +#: src/Styles.cxx:323 +msgid "Unknown color field" +msgstr "" + +#: src/Styles.cxx:356 +msgid "Terminal lacks color capabilities" +msgstr "" + +#: src/TagListPage.cxx:71 +msgid "All tracks" +msgstr "" + +#: src/time_format.cxx:44 +msgid "year" +msgstr "" + +#: src/time_format.cxx:46 +msgid "years" +msgstr "" + +#: src/time_format.cxx:54 +msgid "week" +msgstr "" + +#: src/time_format.cxx:57 +msgid "weeks" +msgstr "" + +#: src/time_format.cxx:65 +msgid "day" +msgstr "" + +#: src/time_format.cxx:68 +msgid "days" +msgstr "" + +#: src/TitleBar.cxx:101 +msgid "Volume n/a" +msgstr "" + +#: src/TitleBar.cxx:103 +#, c-format +msgid "Volume %d%%" +msgstr ""
View file
ncmpc-0.36.tar.xz/po/fi.po -> ncmpc-0.47.tar.xz/po/fi.po
Changed
@@ -7,18 +7,20 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2011-03-06 16:02+0000\n" -"Last-Translator: Sami Sankala <Unknown>\n" -"Language-Team: Finnish <fi@li.org>\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2021-01-30 15:41+0000\n" +"Last-Translator: Riku Viitanen <riku.viitanen@protonmail.com>\n" +"Language-Team: Finnish <https://hosted.weblate.org/projects/ncmpc/" +"translations/fi/>\n" "Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.5-dev\n" "X-Launchpad-Export-Date: 2011-06-23 08:56+0000\n" -"X-Generator: Launchpad (build 13265)\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "" @@ -29,318 +31,316 @@ #: src/ChatPage.cxx:163 msgid "Your message" -msgstr "" +msgstr "Viestisi" #: src/ChatPage.cxx:172 msgid "Message could not be sent" -msgstr "" +msgstr "Viestiä ei voitu lähettää" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" -msgstr "" +msgstr "Näppäinten asetukset" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" -msgstr "" +msgstr "Lopeta" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" -msgstr "" +msgstr "Sivu ylöspäin" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" -msgstr "" +msgstr "Sivu alaspäin" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" -msgstr "" +msgstr "Siirry yksi rivi alaspäin" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" -msgstr "" +msgstr "Siirry yksi rivi ylöspäin" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" -msgstr "" +msgstr "Siirry puoli näyttöä ylöspäin" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" -msgstr "" +msgstr "Siirry puoli näyttöä alaspäin" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "" -#: src/Command.cxx:71 src/HelpPage.cxx:140 -#, fuzzy +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" -msgstr "Näppäinmäärittely ruutu" +msgstr "Jononäkymä" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "Selailunäkymä" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" -msgstr "" +msgstr "Pysäytä" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" -msgstr "" +msgstr "Rajaa" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" -msgstr "" +msgstr "Seuraava raita" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" -msgstr "" +msgstr "Edellinen raita" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" -msgstr "" +msgstr "Nosta äänenvoimakkuutta" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" -msgstr "" +msgstr "Laske äänenvoimakkuutta" -#: src/Command.cxx:98 +#: src/Command.cxx:99 msgid "Select/deselect song in queue" msgstr "" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "" -#: src/Command.cxx:102 +#: src/Command.cxx:103 msgid "Delete song from queue" -msgstr "" +msgstr "Poista kappale jonosta" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" -msgstr "" +msgstr "Sekoita jono" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" -msgstr "" +msgstr "Tyhjennä jono" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" -msgstr "" +msgstr "Tallenna jono" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 #, fuzzy msgid "Append song to queue" msgstr "Lisää kappale soittolistaan" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" -msgstr "" +msgstr "Mene juurihakemistoon" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" -msgstr "" +msgstr "Päivitä näkymä" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" -msgstr "" +msgstr "Seuraava näkymä" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" -msgstr "" +msgstr "Edellinen näkymä" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" -msgstr "" +msgstr "Vaihda viimeisimpään näkymään" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" -msgstr "" +msgstr "Kirjastosivu" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Hakunäkymä" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" -msgstr "" +msgstr "Vaihda hakutilaa" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "Sanoitusnäkymä" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "" -#: src/Command.cxx:214 src/HelpPage.cxx:203 -#, fuzzy +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" -msgstr "Soittolista näyttö" +msgstr "Keskustelunäkymä" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "" @@ -352,29 +352,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" -msgstr "" +msgstr "Puuttuva '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" -msgstr "" +msgstr "Epätäydellisesti määritelty väri" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" -msgstr "" +msgstr "Virheellinen luku" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "" @@ -383,168 +383,165 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "" -#: src/ConfigParser.cxx:403 +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" msgstr "" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "" #: src/CustomColors.cxx:57 msgid "Terminal lacks support for changing colors" -msgstr "" +msgstr "Pääte ei tue värien vaihtamista" #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "Tämän kohteen poistaminen ei ole mahdollista" -#: src/FileBrowserPage.cxx:256 -#, fuzzy, c-format +#: src/FileBrowserPage.cxx:254 +#, c-format msgid "Delete playlist %s?" -msgstr "Poista soittolista" +msgstr "Poistetaanko soittolista %s?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Keskeytetty" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "Soittolista poistettu" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Selaa" -#: src/FileListPage.cxx:119 -#, fuzzy, c-format +#: src/FileListPage.cxx:125 +#, c-format msgid "Loading playlist '%s'" -msgstr "Ladataan soittolistaa %s..." +msgstr "Ladataan soittolistaa '%s'" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 -#, fuzzy, c-format +#, c-format msgid "Adding '%s' to queue" -msgstr "Soittolistaan lisätään '%s'" +msgstr "Lisätään '%s' jonoon" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Toista" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Poista soittolista" -#: src/HelpPage.cxx:171 -#, fuzzy +#: src/HelpPage.cxx:172 msgid "New search" -msgstr "Haku" +msgstr "Uusi haku" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Valitse ja toista" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "Näytä sanoitukset" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "Lataa sanoitukset" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Keskeytä sanoitusten noutaminen" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "Lataa sanoitukset toistettavaan kappaleeseen" -#: src/HelpPage.cxx:189 -#, fuzzy +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" -msgstr "Ei talletettuja sanoituksia" +msgstr "Lisää tai muokkaa sanoituksia" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "Tallenna sanoitukset" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" msgstr "Poista tallennettut sanoitukset" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Ulostulo päälle/poissa" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" -msgstr "" +msgstr "Kirjoita viesti" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Näppäinmäärittely ruutu" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Muokkaa näppäinmäärittelyjä halutulle komennolle" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "Poista valittu näppäinmäärittely" -#: src/HelpPage.cxx:214 -#, fuzzy +#: src/HelpPage.cxx:215 msgid "Add a keydef" -msgstr "Lisää uusi näppäin" +msgstr "Lisää näppäinmäärittely" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Siirry taso ylöspäin" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Toteuta ja tallenna muutokset" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Ohje" @@ -556,153 +553,155 @@ msgid "n" msgstr "e" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Poistettu" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "" -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" msgstr "" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Virhe: näppäin %s on jo %s käytössä" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "Asetettu %s %s:ksi" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Lisää uusi näppäin" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "Muokkaa %s näppäimiä" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "Uusia näppäinmäärittelyjä" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "Näppäinmäärittelyjä ei muutettu" -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" msgstr "" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" -msgstr "" +msgstr "Virhe" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "Kirjoitettiin %s" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "" -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "" -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "Muuta näppäinasetteluja" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "Huomio: Unohditko 'Toteuttaa' muutokset?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" -msgstr "" +msgstr "Välilyönti" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" -msgstr "" +msgstr "Enter" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" -msgstr "" +msgstr "Delete" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" -msgstr "" +msgstr "Home" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" -msgstr "" +msgstr "End" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" -msgstr "" +msgstr "PageDown" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" -msgstr "" +msgstr "PageUp" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" -msgstr "" +msgstr "Sarkain" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" -msgstr "" +msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" -msgstr "" +msgstr "Insert" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "" @@ -712,22 +711,22 @@ msgid "Artists" msgstr "Esittäjä" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 #, fuzzy msgid "Albums" msgstr "Albumi" #: src/LibraryPage.cxx:123 msgid "All" -msgstr "" +msgstr "Kaikki" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" msgstr "" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" -msgstr "" +msgstr "Kirjasto" #: src/ListWindow.cxx:213 msgid "Range selection disabled" @@ -787,15 +786,15 @@ msgid "No saved lyrics" msgstr "Ei talletettuja sanoituksia" -#: src/Main.cxx:132 -#, fuzzy, c-format +#: src/Main.cxx:133 +#, c-format msgid "Connecting to %s" -msgstr "Yhdistetty kohteeseen %s" +msgstr "Yhdistetään kohteeseen %s" -#: src/Main.cxx:148 -#, fuzzy, c-format +#: src/Main.cxx:149 +#, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" -msgstr "Virhe: MPD versio %d.%d.%d on liian vanha (tarvitaan %s)" +msgstr "Virhe: MPD:n versio %d.%d.%d on liian vanha (%s vaaditaan)" #. To translators: these credits are shown #. when ncmpc is started with "--version" @@ -806,27 +805,45 @@ " Katja Viljakainen https://launchpad.net/~katja-viljakainen\n" " Sami Sankala https://launchpad.net/~valijumi" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "Vaihdettu osioon '%s'" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Nimi" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "Ulostulo '%s' päällä" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "Ulostulo '%s' poissa päältä" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Ulostulot" +#: src/OutputsPage.cxx:383 +#, fuzzy +msgid "Partition" +msgstr "esittäjä" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "Luo uusi osio" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" -msgstr "" +msgstr "Sekoitettu jono" #: src/player_command.cxx:100 msgid "Cleared queue" -msgstr "" +msgstr "Tyhjennetty jono" #. get path #: src/QueuePage.cxx:314 @@ -835,7 +852,7 @@ #: src/QueuePage.cxx:379 src/QueuePage.cxx:697 msgid "Queue" -msgstr "" +msgstr "Jono" #: src/QueuePage.cxx:381 #, c-format @@ -845,12 +862,12 @@ #. query the user for a filename #: src/save_playlist.cxx:86 msgid "Save queue as" -msgstr "" +msgstr "Tallenna jono nimellä" #: src/save_playlist.cxx:108 -#, fuzzy, c-format +#, c-format msgid "Replace %s?" -msgstr "Korvaa %s %s/%s ? " +msgstr "Korvaa %s?" #. success #: src/save_playlist.cxx:129 @@ -859,18 +876,17 @@ msgstr "Tallennettu %s" #: src/screen_client.cxx:41 -#, fuzzy msgid "Database update running" -msgstr "Tietokannan päivitys käynnissä..." +msgstr "Tietokannan päivitys käynnissä" #: src/screen_client.cxx:48 #, c-format msgid "Database update of %s started" -msgstr "Tietokannan %s päivitys käynnistyi" +msgstr "Tietokannan %s päivitys alkoi" #: src/screen_client.cxx:51 msgid "Database update started" -msgstr "Tietokannan päivitys käynnistyi" +msgstr "Tietokannan päivitys alkoi" #: src/screen.cxx:158 msgid "Repeat mode is on" @@ -959,86 +975,90 @@ msgid "Password" msgstr "Salasana" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "esittäjä" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "levy" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "nimi" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "kappale" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "nimi" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "tyylilaji" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "päiväys:" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "säveltäjä" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "esittäjä" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "kommentti" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "tiedosto" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Kappale" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Esittäjä" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Albumi" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Tiedostonimi" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Esittäjä + Kappale" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Haku" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Hakutyyli: %s" @@ -1056,105 +1076,106 @@ msgstr "Säveltäjä" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Nimi" +#, fuzzy +msgid "Performer" +msgstr "esittäjä" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Levy" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Kappale" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" -msgstr "" +msgstr "Tyylilaji" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" -msgstr "" +msgstr "Kommentti" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" -msgstr "" +msgstr "Polku" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" -msgstr "" +msgstr "Bittinopeus" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" -msgstr "" +msgstr "Muoto" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" -msgstr "" +msgstr "Esittäjien lukumäärä" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" -msgstr "" +msgstr "Albumien lukumäärä" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" -msgstr "" +msgstr "Kappaleiden lukumäärä" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" -msgstr "" +msgstr "Toistoaika" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" -msgstr "" +msgstr "MPD-tilastot" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" -msgstr "" +msgstr "Valittu kappale" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" -msgstr "" +msgstr "%d kb/s" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" -msgstr "" +msgstr "Kappale" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" -msgstr "" +msgstr "Toistetaan:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" -msgstr "" +msgstr "Keskeytetty" #: src/Styles.cxx:252 src/Styles.cxx:313 msgid "Unknown color" -msgstr "" +msgstr "Tuntematon väri" #: src/Styles.cxx:323 msgid "Unknown color field" @@ -1162,7 +1183,7 @@ #: src/Styles.cxx:356 msgid "Terminal lacks color capabilities" -msgstr "" +msgstr "Pääte ei tue värejä" #: src/TagListPage.cxx:71 msgid "All tracks" @@ -1170,36 +1191,36 @@ #: src/time_format.cxx:44 msgid "year" -msgstr "" +msgstr "vuosi" #: src/time_format.cxx:46 msgid "years" -msgstr "" +msgstr "vuotta" #: src/time_format.cxx:54 msgid "week" -msgstr "" +msgstr "viikko" #: src/time_format.cxx:57 msgid "weeks" -msgstr "" +msgstr "viikkoa" #: src/time_format.cxx:65 msgid "day" -msgstr "" +msgstr "päivä" #: src/time_format.cxx:68 msgid "days" -msgstr "" +msgstr "päivää" #: src/TitleBar.cxx:101 msgid "Volume n/a" -msgstr "" +msgstr "Äänenvoimakkuus n/a" #: src/TitleBar.cxx:103 #, c-format msgid "Volume %d%%" -msgstr "" +msgstr "Äänenvoimakkuus %d%%" #~ msgid "Albums of artist: %s" #~ msgstr "Kaikki albumit esittäjältä: %s"
View file
ncmpc-0.36.tar.xz/po/fr.po -> ncmpc-0.47.tar.xz/po/fr.po
Changed
@@ -9,9 +9,9 @@ msgstr "" "Project-Id-Version: ncmpc 0.14.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2019-01-22 14:05+0000\n" -"Last-Translator: Nathan <bonnemainsnathan@gmail.com>\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2022-04-01 16:10+0000\n" +"Last-Translator: lionelvaux <lionel.vaux@univ-amu.fr>\n" "Language-Team: French <https://hosted.weblate.org/projects/ncmpc/" "translations/fr/>\n" "Language: fr\n" @@ -19,10 +19,10 @@ "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 3.4\n" +"X-Generator: Weblate 4.12-dev\n" "X-Launchpad-Export-Date: 2011-01-05 20:00+0000\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "La touche %s est assignée à %s et à %s" @@ -39,309 +39,309 @@ msgid "Message could not be sent" msgstr "Le message n'a pas pu être envoyé" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" -msgstr "Ecran de configuration des touches" +msgstr "Écran de configuration des touches" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Quitter" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "Déplacer le curseur vers le haut" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "Déplacer le curseur vers le bas" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "Déplacer le curseur vers le haut de l'écran" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "Déplacer le curseur vers le milieu de l'écran" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "Déplacer le curseur vers le bas de l'écran" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "Déplacer le curseur vers le haut de la liste" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "Déplacer le curseur vers le bas de la liste" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "Monter d'une page" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "Descendre d'une page" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "Sélection multi-ligne" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "Défiler d'une ligne vers le bas" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "Défiler d'une ligne vers le haut" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "Défiler d'une moitié d'écran vers le haut" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "Défiler d'une moitié d'écran vers le bas" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "Sélectionner la chanson actuellement jouée" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" -msgstr "Ecran d'aide" +msgstr "Écran d'aide" -#: src/Command.cxx:71 src/HelpPage.cxx:140 +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" msgstr "Écran de file d'attente" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" -msgstr "Ecran de Navigation" +msgstr "Écran de navigation" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" -msgstr "Jouer/Entrer dans le répertoire" +msgstr "Lire/Entrer dans le répertoire" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Pause" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" -msgstr "Stop" +msgstr "Arrêter" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "Couper" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "Piste suivante" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Piste précédente" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "Avancer" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "Reculer" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "Augmenter le volume" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "Diminuer le volume" -#: src/Command.cxx:98 +#: src/Command.cxx:99 msgid "Select/deselect song in queue" msgstr "Sélectionner/désélectionner un morceau dans la file d'attente" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Selectionner tous les éléments listés" -#: src/Command.cxx:102 +#: src/Command.cxx:103 msgid "Delete song from queue" msgstr "Supprimer un morceau de la file d'attente" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" msgstr "Mélanger la file d'attente" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" msgstr "Vider la file d'attente" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "Activer/désactiver le mode répétition" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "Activer/désactiver le mode aléatoire" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "Basculer le mode seul" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "Basculer le mode consommation" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "Activer/désactiver le mode de fondu" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "Mettre à jour la base de données musicale" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" msgstr "Enregistrer la file d'attente" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" msgstr "Ajouter la chanson à la file d'attente" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "Aller au répertoire racine" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "Aller au répertoire supérieur" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "Localiser la chanson dans le navigateur" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "Déplacer l'élément vers le haut" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "Déplacer l'élément vers le bas" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "Rafraîchir l'écran" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "Activer le mode de recherche" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "Activer le mode d'auto-centrage" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" -msgstr "Ecran suivant" +msgstr "Écran suivant" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" -msgstr "Ecran précédent" +msgstr "Écran précédent" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "Passer à l'écran le plus récent" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "Chercher après" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "Chercher après/suivant" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "Chercher avant" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "Chercher avant/précédent" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "Aller à" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" -msgstr "" +msgstr "Page de la bibliothèque" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Ecran de recherche" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "Changer le mode de recherche" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "Voir la chanson sélectionnée et actuellement jouée" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" -msgstr "Ecran des paroles" +msgstr "Écran des paroles" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "Interrompre l'action" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "Mettre à jour les paroles" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "Modifier l'élément en cours" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" -msgstr "Ecran des sorties" +msgstr "Écran des sorties" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" msgstr "Écran de discussion" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "Mot attendu" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "Définition de raccourci malformée" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "Configuration de raccourci incomplète" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "Commande inconnue" @@ -353,29 +353,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "Mauvais type d'affichage du temps" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "Manque '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "Mauvais nom de couleur" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "Définition de couleur incomplète" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "Nombre invalide" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "Définition de couleur malformée" @@ -384,24 +384,23 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "Nom d'écran inconnu" -#: src/ConfigParser.cxx:403 -#, fuzzy +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" -msgstr "Commande inconnue" +msgstr "Étiquette MPD inconnue" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "Mode de recherche invalide" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "Mode de recherche inconnu" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "Paramètre de configuration inconnu" @@ -412,138 +411,138 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "Impossible d'effacer ce type d'objet" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, c-format msgid "Delete playlist %s?" msgstr "Supprimer la liste de lecture de %s ?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Annulé" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "Liste de lecture effacée" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Parcourir" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, c-format msgid "Loading playlist '%s'" -msgstr "Chargement de la liste de lecture '%s'" +msgstr "Chargement de la liste de lecture « %s »" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 #, c-format msgid "Adding '%s' to queue" -msgstr "Ajout de '%s' à la file d’attente" +msgstr "Ajout de « %s » à la file d’attente" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Déplacements" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Globales" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Lire" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "Centrer" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Entrer dans le répertoire/Sélectionner et lire la chanson" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Effacer la liste de lecture" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 msgid "New search" msgstr "Nouvelle recherche" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Sélectionner et Lire" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" -msgstr "Voir les Paroles" +msgstr "Voir les paroles" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "(Re)charger les paroles" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Récupération interrompue" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "Télécharger les paroles de la chanson en lecture" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" msgstr "Ajouter ou modifier des paroles" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "Enregistrer les paroles" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" -msgstr "Supprimer les paroles sauvées" +msgstr "Supprimer les paroles enregistrées" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Activer/désactiver une sortie" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" msgstr "Écrire un message" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Écran du paramétrage des raccourcis" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Éditer les raccourcis pour la commande sélectionnée" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "Supprimer le raccourci sélectionné" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 msgid "Add a keydef" msgstr "Ajouter un nouveau raccourci" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Aller au dossier parent" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Appliquer et sauvegarder les changements" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Aide" @@ -555,153 +554,155 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Effacé" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " -msgstr "Entrez la nouvelle touche pour %s: " +msgstr "Entrez la nouvelle touche pour %s : " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" msgstr "Ctrl-Espace ne peut être utilisé" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" -msgstr "Erreur: la touche %s est déja attribuée à %s" +msgstr "Erreur : la touche %s est déjà attribuée à %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "%s assignée à %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Ajouter une nouvelle touche" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" -msgstr "Editer les touches pour %s" +msgstr "Modifier les touches pour %s" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "Vous avez une nouvelle correspondance de touches" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "La correspondance des touches n'a pas été changée." -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" msgstr "Échec de sauvegarde de la configuration" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "Erreur" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "%s écrit" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "===> Appliquer la correspondance des touches " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "===> Appliquer et Enregistrer la correspondance des touches " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" -msgstr "Editer les correspondances de touches" +msgstr "Modifier les correspondances de touches" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" -msgstr "Note : Auriez-vous oublié d'« Appliquer » vos changements ?" +msgstr "Remarque : avez-vous oublié d'« Appliquer » vos changements ?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "Touches" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "Indéfini" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Espace" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Entrée" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" -msgstr "Backspace" +msgstr "Retour arrière" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Suppr" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Haut" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Bas" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "Gauche" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "Droite" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Début" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "Fin" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "PageBas" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "PageHaut" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" -msgstr "Shift+Tab" +msgstr "Maj+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" -msgstr "Echap" +msgstr "Échap" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Inser" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "Ctrl-%c" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "Alt-%c" @@ -710,22 +711,21 @@ msgid "Artists" msgstr "Artistes" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 msgid "Albums" msgstr "Albums" #: src/LibraryPage.cxx:123 msgid "All" -msgstr "" +msgstr "Tous" -#: src/LibraryPage.cxx:199 -#, fuzzy +#: src/LibraryPage.cxx:197 msgid "Songs" -msgstr "Morceau" +msgstr "Morceaux" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" -msgstr "" +msgstr "Bibliothèque" #: src/ListWindow.cxx:213 msgid "Range selection disabled" @@ -743,7 +743,7 @@ #: src/LyricsPage.cxx:270 #, c-format msgid "Lyrics timeout occurred after %d seconds" -msgstr "Expiration du délai après %d secondes pour les Paroles" +msgstr "Expiration du délai après %d secondes pour les paroles" #: src/LyricsPage.cxx:353 src/LyricsPage.cxx:361 src/LyricsPage.cxx:371 #: src/LyricsPage.cxx:507 @@ -785,12 +785,12 @@ msgid "No saved lyrics" msgstr "Aucune parole sauvée" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, c-format msgid "Connecting to %s" msgstr "Connexion à %s" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "Erreur : la version %d.%d.%d de MPD est trop ancienne (%s requise)" @@ -810,20 +810,37 @@ " Thibault Févry https://launchpad.net/~thibaultfevry\n" " Yann Cézard https://launchpad.net/~eesprit" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "Passé à la partition « %s »" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Nom" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "Sortie %s activée" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "Sortie %s désactivée" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Sorties" +#: src/OutputsPage.cxx:383 +msgid "Partition" +msgstr "Partition" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "Créer une nouvelle partition" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" msgstr "File d'attente mélangée" @@ -864,7 +881,7 @@ #: src/screen_client.cxx:41 msgid "Database update running" -msgstr "Mise à jour de la base de données en cours …" +msgstr "Mise à jour de la base de données en cours" #: src/screen_client.cxx:48 #, c-format @@ -914,7 +931,7 @@ #: src/screen.cxx:183 msgid "Consume mode is off" -msgstr "Mode consommateur activé" +msgstr "Mode consommateur désactivé" #: src/screen.cxx:186 #, c-format @@ -927,19 +944,19 @@ #: src/screen.cxx:248 msgid "Find mode: Wrapped" -msgstr "Mode de recherche: Enveloppe" +msgstr "Mode de recherche : Enveloppe" #: src/screen.cxx:249 msgid "Find mode: Normal" -msgstr "Mode de recherche: Normal" +msgstr "Mode de recherche : Normal" #: src/screen.cxx:254 msgid "Auto center mode: On" -msgstr "Mode d'auto-centrage: Actif" +msgstr "Mode d'auto-centrage : Actif" #: src/screen.cxx:255 msgid "Auto center mode: Off" -msgstr "Mode d'auto-centrage: Inactif" +msgstr "Mode d'autocentrage : Inactif" #: src/screen_find.cxx:33 msgid "Find" @@ -956,92 +973,96 @@ #: src/screen_find.cxx:81 #, c-format msgid "Unable to find '%s'" -msgstr "Impossible de trouver '%s'" +msgstr "Impossible de trouver « %s »" #: src/screen_utils.cxx:150 msgid "Password" msgstr "Mot de passe" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "artiste" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "album" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "titre" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "piste" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "nom" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "genre" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "date" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "compositeur" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "interprète" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "commentaire" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "fichier" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Titre" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Artiste" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Album" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Nom de fichier" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Artiste + Titre" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "Suffixe non reconnu" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Mauvais champ recherché %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "Pas d'argument pour le champ recherché %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Rechercher" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Mode de recherche : %s" @@ -1059,99 +1080,99 @@ msgstr "Compositeur" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Nom" +msgid "Performer" +msgstr "Interprète" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Disque" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Piste" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Date" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Style" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Commentaire" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Chemin" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Débit" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" msgstr "Format" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Nombre d'artistes" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Nombre d'albums" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Nombre de chansons" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "Temps de service" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "Mise à jour de la BD la plus récente" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "Temps de lecture" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "Temps de lecture de la BD" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "Visualiseur de chanson" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "Statistiques MPD" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "Chanson sélectionnée" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "Chanson actuellement jouée" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" -msgstr "%d ko/s" +msgstr "%d ko/s" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" msgstr "Morceau" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "En Lecture :" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "En Pause"
View file
ncmpc-0.36.tar.xz/po/gl.po -> ncmpc-0.47.tar.xz/po/gl.po
Changed
@@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" "PO-Revision-Date: 2011-03-25 19:34+0000\n" "Last-Translator: Miguel Anxo Bouzada <mbouzada@gmail.com>\n" "Language-Team: galician\n" @@ -18,7 +18,7 @@ "X-Launchpad-Export-Date: 2011-06-23 08:56+0000\n" "X-Generator: Launchpad (build 13265)\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "A tecla %s asignouse a %s e a %s" @@ -35,314 +35,314 @@ msgid "Message could not be sent" msgstr "" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "Pantalla de configuración dos atallos" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Saír" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "Mover o cursor cara enriba" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "Mover o cursor cara embaixo" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "Mover o cursor até ao comezo da pantalla" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "Mover o cursor até á metade da pantalla" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "Mover o cursor até ao pe da pantalla" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "Mover o cursor até ao comezo da lista" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "Mover o cursor até ao pe da lista" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "Páxina enriba" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "Páxina embaixo" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "Selección do rango" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "Baixar unha liña" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "Subir unha liña" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "Subir media pantalla" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "Baixar media pantalla" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "Seleccionar a cannción actual canción en reprodución" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "Pantalla de axuda" -#: src/Command.cxx:71 src/HelpPage.cxx:140 +#: src/Command.cxx:72 src/HelpPage.cxx:141 #, fuzzy msgid "Queue screen" msgstr "Pantalla de atallos" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "Pantalla do explorador" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "Reproducir/Entrar nun cartafol" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Pausa" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "Deter" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "Cortar" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "Seguinte pista" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Pista anterior" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "Avanzar" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "Retroceder" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "Aumentar volume" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "Diminuir volume" -#: src/Command.cxx:98 +#: src/Command.cxx:99 #, fuzzy msgid "Select/deselect song in queue" msgstr "Seleccionar/deseleccionar a canción na lista de reprodución" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Seleccionar todos os elementos da lista" -#: src/Command.cxx:102 +#: src/Command.cxx:103 #, fuzzy msgid "Delete song from queue" msgstr "Borrar a canción da lista de reproducción" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" msgstr "" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" msgstr "" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "Activar/desactivar o modo repetición" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "Activar/desactivar o modo aleatorio" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "Alternar o modo compacto" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "Alternar o modo completo" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "Activar/desactivar o modo de esvaecimento cruzado" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "Comezar unha actualización da BD" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" msgstr "" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 #, fuzzy msgid "Append song to queue" msgstr "Engadir a canción á lista de reprodución" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "Ir ao cartafol raíz" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "Ir ao cartafol pai" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "Atopar a canción no explorador" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "Movera o elemento cara arriba." -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "Mover o elemento cara abaixo" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "Actualizar a pantalla" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "Alternar o modo de busca" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "Alternar o modo de autocentrado" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "Seguinte pantalla" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "Pantalla anterior" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "Volvar á pantalla anterior" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "Buscar cara adiante" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "Buscar cara adiante, seguinte" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "Buscar cara atrás" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "Buscar cara atrás, anterior" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "Ir a" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" msgstr "" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Pantalla de busca" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "Cambiar o modo de buscas" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "Ver a canción seleccionada e a que se está a reproducir" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "Pantalla das letras de cancións" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "Interromper a acción" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "Actualizar as letras de cancións" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "Pantalla de saída" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 #, fuzzy msgid "Chat screen" msgstr "Seguinte pantalla" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "Definición incorrecta da tecla de acceso rápido." #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "Configuraión incompleta da tecla de acceso rápido" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "Orde descoñecida" @@ -354,29 +354,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "Configuración incorrecta da duración mostrada" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "Falta o signo «=»" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "Nome de cor incorrecto" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "Definición incompleta da cor" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "Número incorrecto" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "Definición incorrecta da cor" @@ -385,24 +385,24 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "Nome de pantalla descoñecido" -#: src/ConfigParser.cxx:403 +#: src/ConfigParser.cxx:388 #, fuzzy msgid "Unknown MPD tag" msgstr "Orde descoñecida" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "O modo de busca é incorrecto" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "Modo de busca descoñecido" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "Parámetro de configuración descoñecido" @@ -413,141 +413,141 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "Non é possíbel borrar este elemento" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, fuzzy, c-format msgid "Delete playlist %s?" msgstr "Borrar a lista de reprodución" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Interrompido" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "Lista de reprodución borrada" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Explorar" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, fuzzy, c-format msgid "Loading playlist '%s'" msgstr "Cargando a lista de reprodución %s..." -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 #, fuzzy, c-format msgid "Adding '%s' to queue" msgstr "Engadindo «%s» á lista de reprodución" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Movemento" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Global" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Reproducir" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "Centrar" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Entre no cartafol/Seleccione e reproduza a canción" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Borrar a lista de reprodución" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 #, fuzzy msgid "New search" msgstr "Buscar" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Seleccionar e reproducir" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "Ver as letras de cancións" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "(Re)cargar as letras de cancións" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Interromper a descarga" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "Obter as letras da canción reproducida" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 #, fuzzy msgid "Add or edit lyrics" msgstr "Letras de cancións sen gardar" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "Guardar as letras de cancións" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" msgstr "Eliminar as letras de cancións gardadas" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Activar/Desactivar a saída" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" msgstr "" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Pantalla de atallos" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Editar atallos para a orde seleccionada" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "Eliminar o atallo seleccionado" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 #, fuzzy msgid "Add a keydef" msgstr "Engadir un novo atallo" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Subir un nivel" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Aplicar e gardar os cambios" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Axuda" @@ -559,154 +559,156 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Borrada" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "Introduza un novo atallo para %s: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" msgstr "" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Erro: a tecla %s xá está sendo utilizada por %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "Asignouse %s a %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Engadir un novo atallo" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "Editar atallos para %s" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "Ten novos atallos de teclado" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "Non se cambiaron os atallos de teclado" -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 #, fuzzy msgid "Unable to write configuration" msgstr "Configuraión incompleta da tecla de acceso rápido" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "Erro" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "Escribiuse %s" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "===> Aplicar os atallos de teclado " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "===> Aplicar e guardar os atallos de teclado " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "Editar os atallos de teclado" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "Nota: Esquecuse de «Aplicar» os cambios?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "Sen definir" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Espazo" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Entrar" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "Retroceso" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Borrar" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Arriba" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Abaixo" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "Esquerda" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "Direita" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Inicio" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "Fin" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "PáxEmbaixo" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "PáxEnriba" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tabulador" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Maiús + Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Inserir" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "" @@ -716,7 +718,7 @@ msgid "Artists" msgstr "Artista" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 #, fuzzy msgid "Albums" msgstr "Álbum" @@ -725,11 +727,11 @@ msgid "All" msgstr "" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" msgstr "" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" msgstr "" @@ -791,12 +793,12 @@ msgid "No saved lyrics" msgstr "Letras de cancións sen gardar" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, fuzzy, c-format msgid "Connecting to %s" msgstr "Conectado a %s" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, fuzzy, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "Erro: a versión %d.%d.%d do MPD é moi antiga (precisase a %s)" @@ -813,20 +815,38 @@ " Johám-Luís Miguéns Vila https://launchpad.net/~miluxovi\n" " Miguel Anxo Bouzada https://launchpad.net/~mbouzada" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Nome" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "Activouse a saída «%s»" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "Desactivouse a saída «%s»" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Saídas" +#: src/OutputsPage.cxx:383 +#, fuzzy +msgid "Partition" +msgstr "artista" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" msgstr "" @@ -966,86 +986,90 @@ msgid "Password" msgstr "Contrasinal" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "artista" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "álbum" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "título" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "pista" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "nome" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "xénero" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "data" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "compositor" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "interprete" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "comentário" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "ficheiro" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Título" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Artista" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Álbum" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Nome do ficheiro" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Artista + Título" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Etiqueta de busca errónea %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "Sen argumento para a busca da etiqueta %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Buscar" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Modo da busca: %s" @@ -1063,99 +1087,100 @@ msgstr "Compositor" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Nome" +#, fuzzy +msgid "Performer" +msgstr "interprete" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Disco" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Pista" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Data" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Xénero" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Comentario" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Ruta" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Taxa de bits" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" msgstr "" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Número de artistas" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Número de álbumes" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Número de cancións" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "Tempo de execución" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "Actualización máis recente da BD" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "Tempo de reprodución" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "Duraciónacumulada da BD" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "Visor da canción" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "Estatísticas do MPD" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "Canción seleccionada" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "Canción que se está reproducindo" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d kbps" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" msgstr "" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Reproducindo:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "En Pausa"
View file
ncmpc-0.36.tar.xz/po/he.po -> ncmpc-0.47.tar.xz/po/he.po
Changed
@@ -2,342 +2,340 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2010-09-07 20:35+0200\n" -"Last-Translator: zeltak <Unknown>\n" -"Language-Team: he <he@li.org>\n" -"Language: \n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2021-11-08 13:50+0000\n" +"Last-Translator: Yaron Shahrabani <sh.yaron@gmail.com>\n" +"Language-Team: Hebrew <https://hosted.weblate.org/projects/ncmpc/" +"translations/he/>\n" +"Language: he\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 && " +"n % 10 == 0) ? 2 : 3));\n" +"X-Generator: Weblate 4.9-dev\n" "X-Launchpad-Export-Date: 2010-09-07 18:28+0000\n" -"X-Generator: Launchpad (build Unknown)\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" -msgstr "מקש %s מוקצה ל %s ו %s" +msgstr "מקש %s מוקצה ל %s ול־%s" #: src/ChatPage.cxx:64 src/ChatPage.cxx:182 msgid "Chat" -msgstr "" +msgstr "צ׳אט" #: src/ChatPage.cxx:163 msgid "Your message" -msgstr "" +msgstr "ההודעה שלך" #: src/ChatPage.cxx:172 msgid "Message could not be sent" -msgstr "" +msgstr "לא ניתן לשלוח את ההודעה" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" -msgstr "מסך קינפוג מקשים" +msgstr "מסך הגדרת מקשים" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" -msgstr "צא מהתוכנה" +msgstr "יציאה" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" -msgstr "הזז סמן למעלה" +msgstr "הזזת הסמן למעלה" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" -msgstr "הזז סמן למטה" +msgstr "הזזת הסמן למטה" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" -msgstr "הזז סמן לקצה העליון של המסך" +msgstr "הזזת הסמן לראש המסך" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" -msgstr "הזז סמן לאמצע של המסך" +msgstr "הזזת הסמן למרכז המסך" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" -msgstr "הזז סמן לקצה התחתון של המסך" +msgstr "הזזת הסמן לתחתית המסך" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" -msgstr "הזז סמן לקצה העליון של הרשימה" +msgstr "הזזת הסמן לראש הרשימה" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" -msgstr "הזז סמן לקצה התחתון של הרשימה" +msgstr "הזזת הסמן לתחתית הרשימה" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" -msgstr "דף למעלה" +msgstr "עמוד למעלה" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" -msgstr "דף למטה" +msgstr "עמוד למטה" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "בחירת טווח" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" -msgstr "גלול שורה אחת" +msgstr "גלילת שורה אחת" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" -msgstr "גלול שורה אחת למעלה" +msgstr "גלילת שורה אחת למעלה" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" -msgstr "גלול חצי מסך למעלה" +msgstr "גלילת חצי מסך למעלה" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" -msgstr "גלול חצי מסך למטה" +msgstr "גלילת חצי מסך למטה" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "בחר בשיר שכרגע מנגן" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "מסך עזרה" -#: src/Command.cxx:71 src/HelpPage.cxx:140 -#, fuzzy +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" -msgstr "מסך שוני מקשים" +msgstr "מסך תור" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" -msgstr "דפדף במסך" +msgstr "מסך דפדוף" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "נגן/הכנס תיקיה" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "הפסק" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "עצור" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "חתוך" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "רצועה הבאה" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "רצועה קודמת" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "דלג קדימה" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "דלג אחורה" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "הגבר" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "הנמך" -#: src/Command.cxx:98 -#, fuzzy +#: src/Command.cxx:99 msgid "Select/deselect song in queue" -msgstr "בחר/הסר שיר ברשימת שירים" +msgstr "בחירת/ביטול שיר בתור" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "בחר את הכל" -#: src/Command.cxx:102 -#, fuzzy +#: src/Command.cxx:103 msgid "Delete song from queue" -msgstr "מחק שיר מרשימת השירים" +msgstr "מחיקת שיר מהתור" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" -msgstr "" +msgstr "ערבוב תור" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" -msgstr "" +msgstr "פינוי תור" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "הפעל מצב חזרה" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "הפעל מצב רנדומלי" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "הפעל מצב יחיד" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "הפעל מצב מתכלה" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "הפעל קרוספייד" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "התחל עדכון בסיס הנתונים המוזיקלי" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" -msgstr "" +msgstr "שמירת תור" -#: src/Command.cxx:122 src/HelpPage.cxx:174 -#, fuzzy +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" -msgstr "הוסף שיר לרשימת שירים" +msgstr "הוספת שיר לתור" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "לך לתיקיה שורש" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "לך לתיקיה עליונה" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "מצא שיר בדפדפן" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "הזז למעלה" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "הזז למטה" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "רענן מסך" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "הפעל מצב חיפוש" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "הפעל מירכוז אוטומטי" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "מסך הבא" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "מסך קודם" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "החלף למסך אחרון" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "מצא קדימה" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "מצא קדימה הבא" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "מצא אחורה" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "מצא אחורה הבא" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "קפוץ ל" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" -msgstr "" +msgstr "עמוד ספריה" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "חפש במסך" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "שנה תצורת מסך" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "הראה את השיר הנבחר והמנגן" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "מסך מילות השיר" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "הפסק פעולה" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "רענן מילים לשיר" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" -msgstr "" +msgstr "עריכת הפריט הנוכחי" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "מסך הפלט" -#: src/Command.cxx:214 src/HelpPage.cxx:203 -#, fuzzy +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" -msgstr "מסך הבא" +msgstr "מסך צ׳אט" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" -msgstr "" +msgstr "מילה צפויה" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "הגדרת המקשים החמים שגויה" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "הגדרת המקשים החמים חסרה" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "פקודה לא ידועה" @@ -349,29 +347,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "תצוגת זמן שגויה" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "חסר '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "צבע שגוי" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "הגדרת צבעים חסרה" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "מספר לא תקין" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "הגדרת צבעים שגויה" @@ -380,24 +378,23 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "שם מסך לא ידוע" -#: src/ConfigParser.cxx:403 -#, fuzzy +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" -msgstr "פקודה לא ידועה" +msgstr "תגית MPD בלתי מוכרת" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "חיפוש לא תקין" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "מצב חיפוש לא ידוע" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "פרמטר קונפיג לא ידוע" @@ -408,140 +405,139 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "מחיקת פריט זה בלתי אפשרית" -#: src/FileBrowserPage.cxx:256 -#, fuzzy, c-format +#: src/FileBrowserPage.cxx:254 +#, c-format msgid "Delete playlist %s?" -msgstr "מחק רשימת שירים" +msgstr "למחוק את רשימת השירים %s?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "בוטל" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "רשימת שירים נמחקה" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "דפדף" -#: src/FileListPage.cxx:119 -#, fuzzy, c-format +#: src/FileListPage.cxx:125 +#, c-format msgid "Loading playlist '%s'" -msgstr "טוען רשימת שירים %s...." +msgstr "רשימת הנגינה ‚%s’ נטענת" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 -#, fuzzy, c-format +#, c-format msgid "Adding '%s' to queue" -msgstr "מוסיף %s לרשימת השירים" +msgstr "‚%s’ נוסף לרשימת הנגינה" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "תנועה" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "גלובלי" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "נגן" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "מרכז" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "הכנס תיקיה/בחר ונגן שיר" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "מחק רשימת שירים" -#: src/HelpPage.cxx:171 -#, fuzzy +#: src/HelpPage.cxx:172 msgid "New search" -msgstr "חיפוש" +msgstr "חיפוש חדש" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "בחר ונגן" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "הצג מילים לשיר" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "הטען מחדש מילים לשיר" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "שליפת המידע הופסקה" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "הורד מילים לשיר המנגן כרגע" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" -msgstr "" +msgstr "עריכת או הוספת מילות שיר" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "שמור מילים לשיר" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" -msgstr "" +msgstr "מחיקת מילות שירים שמורות" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" -msgstr "אשר/אסור על פלט" +msgstr "הפעלת/השבתת פלט" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" -msgstr "" +msgstr "כתיבת הודעה" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "מסך שוני מקשים" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "ערוך שוני מקשים לפקודות שונות" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "הסר שוני מקשים" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 #, fuzzy msgid "Add a keydef" msgstr "הוסף מקש חדש" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "עלה רמה אחת" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "ישם ושמור שינויים" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "עזרה" @@ -553,179 +549,178 @@ msgid "n" msgstr "לא" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "נמחק" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "הכנס מקש חדש ל %s " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" -msgstr "" +msgstr "אי אפשר להשתמש ב־Ctrl-רווח" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "שגיאה: המקש %s כבר קיים ל %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" -msgstr "הוקצה %s ל %s" +msgstr "הוקצה %s אל %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "הוסף מקש חדש" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "ערוך את המקש ל %s" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "יש תצורת מקשים חדשה" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "תצורת מקשים לא שונתה." -#: src/KeyDefPage.cxx:406 -#, fuzzy +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" -msgstr "הגדרת המקשים החמים חסרה" +msgstr "לא ניתן לכתוב את ההגדרות" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "שגיאה" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "נכתב %s" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "=====> ישם תצורת מקשים " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "=====> ישם ושמור תצורת מקשים " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "ערוך את תצורת המקשים" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" -msgstr "הזהרה: האם שכחת 'לישם' את השינוים" +msgstr "אזהרה: שכחת ‚להחיל’ את השינויים?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" -msgstr "" +msgstr "מקשים" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "לא מוגדר" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "רווח" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "הכנס" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "אחורה" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "מחק" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "למעלה" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "למטה" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "שמאלה" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "חמינה" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "בית" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "סוף" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "דף למטה" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "דף למעלה" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "טאב" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Shift+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Insert" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" -msgstr "" +msgstr "Ctrl-%c" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" -msgstr "" +msgstr "Alt-%c" #: src/LibraryPage.cxx:45 -#, fuzzy msgid "Artists" -msgstr "אומן" +msgstr "אומנים" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 -#, fuzzy +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 msgid "Albums" -msgstr "אלבום" +msgstr "אלבומים" #: src/LibraryPage.cxx:123 msgid "All" -msgstr "" +msgstr "הכול" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" -msgstr "" +msgstr "שירים" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" -msgstr "" +msgstr "ספרייה" #: src/ListWindow.cxx:213 msgid "Range selection disabled" @@ -743,7 +738,7 @@ #: src/LyricsPage.cxx:270 #, c-format msgid "Lyrics timeout occurred after %d seconds" -msgstr "" +msgstr "אירעה שגיאת תום זמן המתנה לאחר %d שניות" #: src/LyricsPage.cxx:353 src/LyricsPage.cxx:361 src/LyricsPage.cxx:371 #: src/LyricsPage.cxx:507 @@ -758,19 +753,19 @@ #: src/LyricsPage.cxx:378 msgid "Editor not configured" -msgstr "" +msgstr "העורך לא מוגדר" #: src/LyricsPage.cxx:385 msgid "Do you really want to start an editor and edit these lyrics?" -msgstr "" +msgstr "להפעיל את העורך ולערוך את מילות השירים האלה?" #: src/LyricsPage.cxx:403 src/LyricsPage.cxx:427 msgid "Can't start editor" -msgstr "" +msgstr "אי אפשר להפעיל את העורך" #: src/LyricsPage.cxx:430 src/LyricsPage.cxx:434 msgid "Editor exited unexpectedly" -msgstr "" +msgstr "העורך נעצר באופן פתאומי" #. lyrics for the song were saved on hard disk #: src/LyricsPage.cxx:456 @@ -779,21 +774,21 @@ #: src/LyricsPage.cxx:462 msgid "Lyrics deleted" -msgstr "" +msgstr "מילות השירים נמחקו" #: src/LyricsPage.cxx:463 msgid "No saved lyrics" -msgstr "" +msgstr "אין מילות שירים שנשמרו" -#: src/Main.cxx:132 -#, fuzzy, c-format +#: src/Main.cxx:133 +#, c-format msgid "Connecting to %s" -msgstr "מתחבר ל %s" +msgstr "מתבצעת התחברות אל %s" -#: src/Main.cxx:148 -#, fuzzy, c-format +#: src/Main.cxx:149 +#, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" -msgstr "שגיאה: גרסת התוכנה %d.%d.%d ישנה מדי (צריך %s)" +msgstr "שגיאה: גרסת ה־MPD %d.%d.%d ישנה מדי (צריך %s)" #. To translators: these credits are shown #. when ncmpc is started with "--version" @@ -803,27 +798,44 @@ "Launchpad Contributions:\n" " zeltak https://launchpad.net/~zeltak" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "שם" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" -msgstr "פלט '%s' אפשרי" +msgstr "הפלט ‚%s’ מופעל" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" -msgstr "פלט '%s' אינו אפשרי" +msgstr "הפלט ‚%s’ מושבת" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "פלטים" +#: src/OutputsPage.cxx:383 +msgid "Partition" +msgstr "מחיצה" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "יצירת מחיצה חדשה" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" -msgstr "" +msgstr "תור מעורבב" #: src/player_command.cxx:100 msgid "Cleared queue" -msgstr "" +msgstr "התור התפנה" #. get path #: src/QueuePage.cxx:314 @@ -832,22 +844,22 @@ #: src/QueuePage.cxx:379 src/QueuePage.cxx:697 msgid "Queue" -msgstr "" +msgstr "תור" #: src/QueuePage.cxx:381 #, c-format msgid "Queue on %s" -msgstr "" +msgstr "תור על %s" #. query the user for a filename #: src/save_playlist.cxx:86 msgid "Save queue as" -msgstr "" +msgstr "שמירת התור בשם" #: src/save_playlist.cxx:108 -#, fuzzy, c-format +#, c-format msgid "Replace %s?" -msgstr "החלף %s %s/%s ? " +msgstr "להחליף את %s?" #. success #: src/save_playlist.cxx:129 @@ -856,9 +868,8 @@ msgstr "שמירת %s" #: src/screen_client.cxx:41 -#, fuzzy msgid "Database update running" -msgstr "עדכון בסיס הנתנונים פועל...." +msgstr "עדכון מסד נתונים פעיל" #: src/screen_client.cxx:48 #, c-format @@ -956,212 +967,214 @@ msgid "Password" msgstr "סיסמה" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "אומן" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "אלבום" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "שם" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "רצועה" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "שם" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "ג'אנר" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "תאריך" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "מלחין" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "מבצע" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "הערות" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "קובץ" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "שם" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "אומן" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "אלבום" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "שם קובץ" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "אומן+שם" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "סיומת לא מוכרת" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "חיפוש לא תקין של תגית %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "אין טעון לחיפוש תגית %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "חיפוש" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "צורת חיפוש: %s" #: src/SongPage.cxx:65 msgid "Length" -msgstr "" +msgstr "משך" #: src/SongPage.cxx:66 msgid "Position" -msgstr "" +msgstr "מיקום" #: src/SongPage.cxx:67 msgid "Composer" msgstr "מלחון" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "שם" +msgid "Performer" +msgstr "מבצע" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "דיסק" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "רצועה" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "תאריך" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "ג'אנר" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "הערה" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "נתיב" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "ביטרייט" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" -msgstr "" +msgstr "תצורה" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "מספר אומנים" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "מספר אלבומים" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "מספר שירים" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "זמן פעילות" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "עדכון עדכני אחרון של בסיב נתונים" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "זמן נגינה" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "זמן נגינה בסיס נתונים" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "הצגת השיר" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "סטטיסטיקה MPD" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "בחר שיר" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "שיר עכשווי" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d kbps" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" -msgstr "" +msgstr "שיר" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "מנגן:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "הפסקה" #: src/Styles.cxx:252 src/Styles.cxx:313 -#, fuzzy msgid "Unknown color" -msgstr "פקודה לא ידועה" +msgstr "צבע לא ידוע" #: src/Styles.cxx:323 -#, fuzzy msgid "Unknown color field" -msgstr "אזהרה: צבע לא מוכ בתחום - %s\n" +msgstr "שדה הצבע אינו מוכר" #: src/Styles.cxx:356 msgid "Terminal lacks color capabilities" -msgstr "המסוף ללא יכולת תמיכה בצבעים" +msgstr "למסוף אין תמיכה בצבעים" #: src/TagListPage.cxx:71 msgid "All tracks" @@ -1169,27 +1182,27 @@ #: src/time_format.cxx:44 msgid "year" -msgstr "" +msgstr "שנה" #: src/time_format.cxx:46 msgid "years" -msgstr "" +msgstr "שנים" #: src/time_format.cxx:54 msgid "week" -msgstr "" +msgstr "שבוע" #: src/time_format.cxx:57 msgid "weeks" -msgstr "" +msgstr "שבועות" #: src/time_format.cxx:65 msgid "day" -msgstr "" +msgstr "יום" #: src/time_format.cxx:68 msgid "days" -msgstr "" +msgstr "ימים" #: src/TitleBar.cxx:101 msgid "Volume n/a"
View file
ncmpc-0.36.tar.xz/po/hu.po -> ncmpc-0.47.tar.xz/po/hu.po
Changed
@@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" "PO-Revision-Date: 2009-09-24 21:45+0000\n" "Last-Translator: Kiszel Kristóf <Unknown>\n" "Language-Team: Hungarian <hu@li.org>\n" @@ -18,7 +18,7 @@ "X-Launchpad-Export-Date: 2010-09-07 18:28+0000\n" "X-Generator: Launchpad (build Unknown)\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "A(z) %s gomb a követlezőkhoz van rendelve: %s és %s" @@ -35,314 +35,314 @@ msgid "Message could not be sent" msgstr "" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "Billentyű beállító képernyő" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Kilép" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "Kurzormozgatás felfelé" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "Kurzormozgatás lefelé" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "Kurzor mozgatása a képernyő tetejére" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "Kurzor mozgatása a képernyő közepére" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "Kurzor mozgatása a képernyő aljára" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "Kurzor mozgatása a lista tetejére" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "Kurzor mozgatása a lista aljára" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "Egy oldalt fel" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "Egy oldalt le" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "Tartomány kiválasztása" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "Görgetés egy sorral le" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "Görgetés egy sorral fel" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "Görgetés fél képernyőnyivel fel" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "Görgetés fél képernyőnyivel le" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "Most lejátszott szám kiválasztása" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "Segítség" -#: src/Command.cxx:71 src/HelpPage.cxx:140 +#: src/Command.cxx:72 src/HelpPage.cxx:141 #, fuzzy msgid "Queue screen" msgstr "Billentyű beállító képernyő" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "Tallózás" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "Lejátszás/Belépés könyvtárba" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Szüneteltetés" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "Leállítás" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "Vágás" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "Következő szám" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Előző szám" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "Tekerés előre" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "Tekerés hátra" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "Hangerő növelése" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "Hangerő csökkentése" -#: src/Command.cxx:98 +#: src/Command.cxx:99 #, fuzzy msgid "Select/deselect song in queue" msgstr "Szám kiválasztása a lejátszólistában" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Minden listázott elem kiválasztása" -#: src/Command.cxx:102 +#: src/Command.cxx:103 #, fuzzy msgid "Delete song from queue" msgstr "Szám törlése a lejátszólistából" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" msgstr "" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" msgstr "" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "Ismétlő mód ki- és bekapcsolása" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "Véletlenszerű lejátszás ki- és bekapcsolása" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "Egyszeri mód átkapcsolása" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "Fogyasztó mód átkapcsolása" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "Egymásba mosás ki- és bekapcsolása" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "A zenei adatbázis frissítésének indítása" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" msgstr "" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 #, fuzzy msgid "Append song to queue" msgstr "Szám hozzáadása a lejátszólistához" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "Mozgás a gyökér könyvtárba" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "Mozgás a szülő könyvtárba" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "Szám megtekintése a tallozóban" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "Elem mozgatása fel" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "Elem mozgatása le" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "Képernyő frissítése" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "Kereső mód ki- és bekapcsolása" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "Középre igazítás ki- és bekapcsolása" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "Kövezkező képernyő" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "Előző képernyő" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "Váltás a legutóbbi képernyőre" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "Keresés előre" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "Következő keresése előre" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "Keresés hátra" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "Előző keresése hátra" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "Ugrás oda" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" msgstr "" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Kereső képernyő" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "Kereső mód váltása" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "A kiválasztott és épp lejátszott szám megtekintése" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "Dalszöveg képernyő" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "parancs megszakítása" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "Dalszövegek frissítése" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "Kimenetek" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 #, fuzzy msgid "Chat screen" msgstr "Kövezkező képernyő" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "Hibás gyorsbillentyű definíció" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "Hiányos gyorsbillentyű definíció" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "Ismeretlen parancs" @@ -354,29 +354,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "Hibás időkijelzési típus" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "Hiányzó egyenlőség jel" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "Hibás szín megnevezés" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "Hiányos szín megadás" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "Érvénytelen szám" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "Hibás szín megadás" @@ -385,24 +385,24 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "Ismeretlen képernyő név" -#: src/ConfigParser.cxx:403 +#: src/ConfigParser.cxx:388 #, fuzzy msgid "Unknown MPD tag" msgstr "Ismeretlen parancs" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "Érvénytelen keresési mód" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "Ismeretlen keresési mód" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "Ismeretlen konfigurációs paraméter" @@ -413,140 +413,140 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "Ez az elem nem törölhető" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, fuzzy, c-format msgid "Delete playlist %s?" msgstr "Lejátszólista törlése" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Megszakítva" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "Lejátszólista törölve" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Tallózás" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, fuzzy, c-format msgid "Loading playlist '%s'" msgstr "%s lejátszólista betöltése..." -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 #, fuzzy, c-format msgid "Adding '%s' to queue" msgstr "'%s' hozzáadása a lejátszólistához" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Mozgás" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Általános" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Lejátszás" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "Közép" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Könyvtár megadása/szám kiválasztása és lejátszása" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Lejátszólista törlése" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 #, fuzzy msgid "New search" msgstr "Keresés" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Kiválasztás és lejátszás" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "Dalszövegek megtekintése" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "Dalszövegek (újra)töltése" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Újrapróbálkozás megszakítása" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "Dalszöveg letöltése a jelenlegi zenéhez" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" msgstr "" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "Dalszövegek mentése" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" msgstr "" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Kimenet engedélyezése/tiltása" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" msgstr "" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Billentyű beállító képernyő" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Billentyű szerkesztése a kiválasztott parancshoz" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "Billentyű hozzárendelés megszűntetése" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 #, fuzzy msgid "Add a keydef" msgstr "Új gomb hozzáadása" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Egy szinttel feljebb" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Alkalmaz és menti a változásokat" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Súgó" @@ -558,154 +558,156 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Törölve" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "Nyomd meg az új gombot a következőhöz: %s: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" msgstr "" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Hiba: %s gombot már a következő funkció használja: %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "%s hozzárendelve a következőhöz: %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Új gomb hozzáadása" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "Gombok módosítása a következőhöz: %s" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "Új billentyű beállításaid vannak" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "A billentyű beállítások változatlanok." -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 #, fuzzy msgid "Unable to write configuration" msgstr "Hiányos gyorsbillentyű definíció" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "Hiba" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "%s elmentve" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "===> Billentyű beállítások használata " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "===> Alkalmaz és Menti a billentyű beállításokat " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "Billentyűk változtatása" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "Észrevétel: nem felejtetted el érvényesíteni a változtatásaidat?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "Meghatározatlan" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Szóköz" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Enter" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "Backspace" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Delete" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Up" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Down" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "Left" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "Right" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Home" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "End" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "PageDown" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "PageUp" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Shift+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Insert" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "" @@ -715,7 +717,7 @@ msgid "Artists" msgstr "Előadó" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 #, fuzzy msgid "Albums" msgstr "Album" @@ -724,11 +726,11 @@ msgid "All" msgstr "" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" msgstr "" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" msgstr "" @@ -790,12 +792,12 @@ msgid "No saved lyrics" msgstr "" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, fuzzy, c-format msgid "Connecting to %s" msgstr "Csatlakoztatva ide: %s" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, fuzzy, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "Hiba: a(z) %d.%d.%d MPD verzió túl régi (%s kell)" @@ -809,20 +811,38 @@ " Kiszel Kristóf https://launchpad.net/~ulysses\n" " Laszlo Ashin https://launchpad.net/~kodest" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Név" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "Kimenet engedélyezve: %s" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "Kimenet tiltva: %s" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Kimenetek" +#: src/OutputsPage.cxx:383 +#, fuzzy +msgid "Partition" +msgstr "előadó" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" msgstr "" @@ -962,86 +982,90 @@ msgid "Password" msgstr "Jelszó" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "előadó" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "album" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "cím" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "szám" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "név" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "műfaj" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "dátum" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "zeneszerző" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "előadó" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "megjegyzés" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "fájl" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Cím" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Előadó" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Album" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Fájlnév" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Előadó és Cím" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Hibás keresési elem %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "Nincs argumentuma a(z) %s keresési elemnek" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Keresés" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Keresési mód: %s" @@ -1059,99 +1083,100 @@ msgstr "Zeneszerző" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Név" +#, fuzzy +msgid "Performer" +msgstr "előadó" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Lemez" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Szám" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Dátum" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Műfaj" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Megjegyzés" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Elérési út" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Bitráta" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" msgstr "" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Előadók száma" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Albumok száma" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Zenék száma" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "Üzemidő" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "Legutóbbi adatbázis frissítés" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "Lejátszási idő" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "Teljes adatbázis lejátszási ideje" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "Szám néző" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "MPD statisztika" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "Kiválasztott zene" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "Jelenlegi zene" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d kbps" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" msgstr "" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Ami szól:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "Szüneteltetve"
View file
ncmpc-0.36.tar.xz/po/it.po -> ncmpc-0.47.tar.xz/po/it.po
Changed
@@ -7,342 +7,341 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2010-10-31 19:53+0000\n" -"Last-Translator: simone.sandri <Unknown>\n" -"Language-Team: Italian <it@li.org>\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2020-09-08 16:36+0000\n" +"Last-Translator: IvanDan <ivandanza@gmail.com>\n" +"Language-Team: Italian <https://hosted.weblate.org/projects/ncmpc/" +"translations/it/>\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3-dev\n" "X-Launchpad-Export-Date: 2011-01-05 20:00+0000\n" -"X-Generator: Launchpad (build 12138)\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" -msgstr "" +msgstr "Il tasto %s assegnato a %s e %s" #: src/ChatPage.cxx:64 src/ChatPage.cxx:182 msgid "Chat" -msgstr "" +msgstr "Chat" #: src/ChatPage.cxx:163 msgid "Your message" -msgstr "" +msgstr "Il tuo messaggio" #: src/ChatPage.cxx:172 msgid "Message could not be sent" -msgstr "" +msgstr "Il messaggio non ha potuto essere inviato" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" -msgstr "" +msgstr "Schermata di configurazione dei tasti" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Esci" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "Muovi cursore in alto" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "Muovi cursore in basso" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "Muovi cursore in cima allo schermo" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "Muovi cursore in mezzo allo schermo" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "Muovi cursore in fondo allo schermo" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "Muovi cursore in cima alla lista" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "Muovi cursore in fondo alla lista" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "Pagina sopra" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "Pagina sotto" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" -msgstr "" +msgstr "Selezione sottoinsieme" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" -msgstr "" +msgstr "Scorri giù di una linea" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" -msgstr "" +msgstr "Scorri su di una linea" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" -msgstr "" +msgstr "Scorri su mezza schermata" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" -msgstr "" +msgstr "Scorri giù mezza schermata" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" -msgstr "" +msgstr "Seleziona il brano attualmente in riproduzione" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" -msgstr "" +msgstr "Schermata di aiuto" -#: src/Command.cxx:71 src/HelpPage.cxx:140 -#, fuzzy +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" -msgstr "Schermo di tasti di acceso" +msgstr "Schermata della coda" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" -msgstr "" +msgstr "Navigatore" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "Esegui/Entra nella cartella" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Pausa" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "Ferma" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" -msgstr "" +msgstr "Ritaglia lista di canzoni" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "Prossima traccia" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Traccia precedente" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" -msgstr "" +msgstr "Avanza" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" -msgstr "" +msgstr "Retrocedi" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "Alza volume" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "Abbassa volume" -#: src/Command.cxx:98 +#: src/Command.cxx:99 msgid "Select/deselect song in queue" -msgstr "" +msgstr "Seleziona/deseleziona il brano in coda" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Seleziona tutti gli oggetti della lista" -#: src/Command.cxx:102 +#: src/Command.cxx:103 msgid "Delete song from queue" -msgstr "" +msgstr "Cancellare una canzone dalla coda" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" -msgstr "" +msgstr "Mescola coda" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" -msgstr "" +msgstr "Svuota coda" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" -msgstr "" +msgstr "Commuta modalità ripetizione" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" -msgstr "" +msgstr "Commuta modalità casuale" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" -msgstr "" +msgstr "Commuta modalità singola" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" -msgstr "" +msgstr "Commuta modalità consuma" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" -msgstr "" +msgstr "Commuta modalità crossfade" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" -msgstr "" +msgstr "Avvia un aggiornamento della base di dati musicale" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" -msgstr "" +msgstr "Salva coda" -#: src/Command.cxx:122 src/HelpPage.cxx:174 -#, fuzzy +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" -msgstr "Aggiungere la canzone alla lista" +msgstr "Aggiungere la canzone alla coda" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" -msgstr "" +msgstr "Vai alla cartella radice" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" -msgstr "" +msgstr "Vai alla cartella superiore" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" -msgstr "" +msgstr "Trova la canzone nel browser" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" -msgstr "" +msgstr "Muovi su" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" -msgstr "" +msgstr "Muovi giù" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" -msgstr "" +msgstr "Aggiorna schermata" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" -msgstr "" +msgstr "Commuta modalità di ricerca" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" -msgstr "" +msgstr "Commuta la modalità di centramento automatico" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" -msgstr "" +msgstr "Prossima schermata" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" -msgstr "" +msgstr "Schermata precedente" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" -msgstr "" +msgstr "Vai alla schermata più recente" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" -msgstr "" +msgstr "Ricerca in avanti" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" -msgstr "" +msgstr "Cerca seguente" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" -msgstr "" +msgstr "Ricerca all'indietro" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" -msgstr "" +msgstr "Cerca precedente" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" -msgstr "" +msgstr "Salta a" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" -msgstr "" +msgstr "Pagina della libreria" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Ricerca" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" -msgstr "" +msgstr "Cambia modalità di ricerca" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" -msgstr "" +msgstr "Vedi la canzone selezionata e riprodotta" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" -msgstr "Lettere" +msgstr "Schermo dei testi" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" -msgstr "" +msgstr "Interrompi azione" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" -msgstr "" +msgstr "Aggiorna il testo" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" -msgstr "" +msgstr "Modifica l'elemento corrente" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "Schermo di uscite" -#: src/Command.cxx:214 src/HelpPage.cxx:203 -#, fuzzy +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" -msgstr "Lista di canzoni" +msgstr "Schermata chat" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" -msgstr "" +msgstr "Attesa una parola" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" -msgstr "" +msgstr "Definizione malformata del tasto rapido" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" -msgstr "" +msgstr "Configurazione incompleta del tasto rapido" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" -msgstr "" +msgstr "Comando sconosciuto" #. translators: ncmpc #. supports displaying the @@ -352,199 +351,196 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" -msgstr "" +msgstr "Configurazione incorretta del tipo di durata mostrata" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" -msgstr "" +msgstr "Manca un '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" -msgstr "" +msgstr "Nome del colore incorretto" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" -msgstr "" +msgstr "Definizione del colore incompleta" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" -msgstr "" +msgstr "Numero non valido" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" -msgstr "" +msgstr "Definizione del colore sbagliata" #. an unknown screen #. name was specified #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" -msgstr "" +msgstr "Nome della schermata sconosciuto" -#: src/ConfigParser.cxx:403 +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" -msgstr "" +msgstr "Etichetta MPD sconosciuta" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" -msgstr "" +msgstr "Modalità di ricerca invalida" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" -msgstr "" +msgstr "Modalità di ricerca sconosciuta" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" -msgstr "" +msgstr "Parametro di configurazione sconosciuto" #: src/CustomColors.cxx:57 msgid "Terminal lacks support for changing colors" -msgstr "" +msgstr "Il terminale non supporta il cambio dei colori" #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" -msgstr "Non è possibile rimuovere questo elemento." +msgstr "Non è possibile rimuovere questo elemento" -#: src/FileBrowserPage.cxx:256 -#, fuzzy, c-format +#: src/FileBrowserPage.cxx:254 +#, c-format msgid "Delete playlist %s?" -msgstr "Rimuove la playlist" +msgstr "Rimuovere lista %s?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Annullato" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" -msgstr "Playlist rimossa." +msgstr "Elenco di riproduzione eliminato" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Esplora" -#: src/FileListPage.cxx:119 -#, fuzzy, c-format +#: src/FileListPage.cxx:125 +#, c-format msgid "Loading playlist '%s'" -msgstr "Caricando la lista %s" +msgstr "Caricando la lista '%s'" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 -#, fuzzy, c-format +#, c-format msgid "Adding '%s' to queue" -msgstr "Aggiungendo '%s' alla lista di canzoni" +msgstr "Aggiungo '%s' alla coda" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Movimento" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Globale" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" -msgstr "Play" +msgstr "Riproduci" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "Centrare" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Accedere alla cartella/Selezionare e riprodurre la canzone" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Rimuove la playlist" -#: src/HelpPage.cxx:171 -#, fuzzy +#: src/HelpPage.cxx:172 msgid "New search" -msgstr "Cerca" +msgstr "Nuova ricerca" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Seleziona e riprodurre" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "Vedere le lettere" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "(Ri)caricare le lettere" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" -msgstr "Annullare la scarica." +msgstr "Annullare la scarica" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" -msgstr "Ottenere le lettere della canzone riprodotta" +msgstr "Scarica il testo della canzone riprodotta" -#: src/HelpPage.cxx:189 -#, fuzzy +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" -msgstr "Non ci sono testi salvati" +msgstr "Aggiungi o modifica testo della canzone" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "Salvare le lettere" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" msgstr "Rimuovere le lettere" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Attivare/disattivare le uscite" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" -msgstr "" +msgstr "Scrivi un messaggio" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Schermo di tasti di acceso" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Cambia i tasti di acceso veloce per il commando selezionato" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "Rimuovere il tasto di acceso veloce selezionato" -#: src/HelpPage.cxx:214 -#, fuzzy +#: src/HelpPage.cxx:215 msgid "Add a keydef" -msgstr "Introduce un nuovo tasto" +msgstr "Aggiungi una nuova definizione di tasti" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Salire un livello" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Applicare e salvare i cambiamenti" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Aiuto" @@ -556,186 +552,186 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Rimosso" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "Introduce tasto di acceso veloce per %s: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" -msgstr "" +msgstr "Ctrl-Spazio non può essere usato" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Errore: il tasto %s già sta assegnato a %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "%s assegnato a %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Introduce un nuovo tasto" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "Cambia i tasti per %s" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" -msgstr "" +msgstr "Hai definito nuove combinazioni di tasti" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." -msgstr "" +msgstr "Combinazioni di tasti immutate." -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" -msgstr "" +msgstr "Non sono in grado di scrivere la configurazione" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" -msgstr "" +msgstr "Errore" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "%s creato" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " -msgstr "" +msgstr "===> Applica combinazioni di tasti " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " -msgstr "" +msgstr "===> Applica e salva combinazioni di tasti " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "Cambia i tasti di acceso veloce" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "Nota: Hai dimenticato 'Applicare' i tuoi cambiamenti?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" -msgstr "" +msgstr "Tasti" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" -msgstr "" +msgstr "Indefinito" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" -msgstr "" +msgstr "Spazio" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" -msgstr "" +msgstr "Invio" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" -msgstr "" +msgstr "Backspace" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" -msgstr "" +msgstr "Canc" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" -msgstr "" +msgstr "Su" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" -msgstr "" +msgstr "Giù" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" -msgstr "" +msgstr "Sinistra" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" -msgstr "" +msgstr "Destra" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" -msgstr "" +msgstr "Inizio" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" -msgstr "" +msgstr "Fine" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" -msgstr "" +msgstr "Pag↑" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" -msgstr "" +msgstr "Pag↓" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" -msgstr "" +msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" -msgstr "" +msgstr "Maiusc+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" -msgstr "" +msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" -msgstr "" +msgstr "Ins" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" -msgstr "" +msgstr "Ctrl-%c" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" -msgstr "" +msgstr "Alt-%c" #: src/LibraryPage.cxx:45 -#, fuzzy msgid "Artists" -msgstr "Artista" +msgstr "Artisti" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 -#, fuzzy +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 msgid "Albums" msgstr "Album" #: src/LibraryPage.cxx:123 msgid "All" -msgstr "" +msgstr "Tutti" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" -msgstr "" +msgstr "Brani" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" -msgstr "" +msgstr "Biblioteca" #: src/ListWindow.cxx:213 msgid "Range selection disabled" -msgstr "" +msgstr "Selezione di sottoinsieme disabilitata" #: src/ListWindow.cxx:216 msgid "Range selection enabled" -msgstr "" +msgstr "Seleziona gamma abilitata" #. translators: no lyrics were found for the song #: src/LyricsPage.cxx:253 @@ -745,7 +741,7 @@ #: src/LyricsPage.cxx:270 #, c-format msgid "Lyrics timeout occurred after %d seconds" -msgstr "" +msgstr "Il timeout del testo si è verificato dopo %d secondi" #: src/LyricsPage.cxx:353 src/LyricsPage.cxx:361 src/LyricsPage.cxx:371 #: src/LyricsPage.cxx:507 @@ -760,19 +756,19 @@ #: src/LyricsPage.cxx:378 msgid "Editor not configured" -msgstr "" +msgstr "Editore non configurato" #: src/LyricsPage.cxx:385 msgid "Do you really want to start an editor and edit these lyrics?" -msgstr "" +msgstr "Vuoi davvero avviare un editor e modificare questo testo?" #: src/LyricsPage.cxx:403 src/LyricsPage.cxx:427 msgid "Can't start editor" -msgstr "" +msgstr "Impossibile avviare l'editor" #: src/LyricsPage.cxx:430 src/LyricsPage.cxx:434 msgid "Editor exited unexpectedly" -msgstr "" +msgstr "Editor terminato in modo imprevisto" #. lyrics for the song were saved on hard disk #: src/LyricsPage.cxx:456 @@ -787,17 +783,15 @@ msgid "No saved lyrics" msgstr "Non ci sono testi salvati" -#: src/Main.cxx:132 -#, fuzzy, c-format +#: src/Main.cxx:133 +#, c-format msgid "Connecting to %s" -msgstr "Connesso a %s" +msgstr "Mi sto collegando con %s" -#: src/Main.cxx:148 -#, fuzzy, c-format +#: src/Main.cxx:149 +#, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" -msgstr "" -"Errore: La versione di MPD %d.%d.%d è troppo vecchia (bisogna avere al meno " -"la %s)" +msgstr "Errore: la versione MPD %d.%d.%d è troppo vecchia (%s necessaria)" #. To translators: these credits are shown #. when ncmpc is started with "--version" @@ -809,27 +803,45 @@ " Max Kellermann https://launchpad.net/~max-duempel\n" " simone.sandri https://launchpad.net/~lexluxsox" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Nome" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" -msgstr "La uscita '%s' è attivata" +msgstr "L'uscita «%s» è attivata" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" -msgstr "La uscita '%s' è disattivata" +msgstr "L'uscita «%s» è disattivata" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Uscite" +#: src/OutputsPage.cxx:383 +#, fuzzy +msgid "Partition" +msgstr "Posizione" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" -msgstr "" +msgstr "Coda mescolata" #: src/player_command.cxx:100 msgid "Cleared queue" -msgstr "" +msgstr "Coda cancellata" #. get path #: src/QueuePage.cxx:314 @@ -838,22 +850,22 @@ #: src/QueuePage.cxx:379 src/QueuePage.cxx:697 msgid "Queue" -msgstr "" +msgstr "Coda" #: src/QueuePage.cxx:381 #, c-format msgid "Queue on %s" -msgstr "" +msgstr "Coda su %s" #. query the user for a filename #: src/save_playlist.cxx:86 msgid "Save queue as" -msgstr "" +msgstr "Salva coda come" #: src/save_playlist.cxx:108 -#, fuzzy, c-format +#, c-format msgid "Replace %s?" -msgstr "Sostituire %s %s%s ? " +msgstr "Sostituire %s?" #. success #: src/save_playlist.cxx:129 @@ -862,18 +874,17 @@ msgstr "%s salvato" #: src/screen_client.cxx:41 -#, fuzzy msgid "Database update running" -msgstr "Aggiornamento del database in corso..." +msgstr "Aggiornamento del database in esecuzione" #: src/screen_client.cxx:48 #, c-format msgid "Database update of %s started" -msgstr "Iniziato l'aggiornamento del database %s" +msgstr "Iniziato l'aggiornamento della banca dati %s" #: src/screen_client.cxx:51 msgid "Database update started" -msgstr "Iniziato l'aggiornamento del database." +msgstr "Iniziato l'aggiornamento della banca dati" #: src/screen.cxx:158 msgid "Repeat mode is on" @@ -919,11 +930,11 @@ #: src/screen.cxx:186 #, c-format msgid "Crossfade %d seconds" -msgstr "" +msgstr "Dissolvenza incrociata di %d secondi" #: src/screen.cxx:198 msgid "Database updated" -msgstr "Database aggiornato" +msgstr "Banca dati aggiornata" #: src/screen.cxx:248 msgid "Find mode: Wrapped" @@ -947,7 +958,7 @@ #: src/screen_find.cxx:34 msgid "Find backward" -msgstr "" +msgstr "Trova all'indietro" #: src/screen_find.cxx:35 msgid "Jump" @@ -962,89 +973,93 @@ msgid "Password" msgstr "Password" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "artista" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "album" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "titolo" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" -msgstr "track" +msgstr "traccia" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "nome" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "genero" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "data" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "compositore" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "interprete" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "commentare" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "file" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Titolo" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Artista" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Album" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Nome del file" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Artista + Titolo" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "Suffisso non riconosciuto" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Etichetta di ricerca invalida: %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "Senza argomenti per la etichetta di ricerca %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Cerca" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" -msgstr "" +msgstr "Modalità di ricerca: %s" #: src/SongPage.cxx:65 msgid "Length" @@ -1052,152 +1067,153 @@ #: src/SongPage.cxx:66 msgid "Position" -msgstr "" +msgstr "Posizione" #: src/SongPage.cxx:67 msgid "Composer" msgstr "Compositore" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Nome" +#, fuzzy +msgid "Performer" +msgstr "Interprete" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Disco" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" -msgstr "Brano" +msgstr "Traccia" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Data" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Genero" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Commento" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" -msgstr "Path" +msgstr "Percorso" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Bitrate" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" -msgstr "" +msgstr "Formato" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Numero di artisti" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Numero di albums" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Numero di brani" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "Tempo in attività" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" -msgstr "Aggiornamento più recente del database" +msgstr "Aggiornamento più recente della banca dati" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "Tempo di riproduzione" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" -msgstr "Durata del database" +msgstr "Durata della banca dati" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "Visore di canzoni" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "Statistiche del MPD" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "Brano selezionato" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "Brano riprodotto" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" -msgstr "%d kbps" +msgstr "%d kB/s" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" -msgstr "" +msgstr "Brano" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Riproducendo:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "Pausato" #: src/Styles.cxx:252 src/Styles.cxx:313 msgid "Unknown color" -msgstr "" +msgstr "Colore sconosciuto" #: src/Styles.cxx:323 msgid "Unknown color field" -msgstr "" +msgstr "Campo di colore sconosciuto" #: src/Styles.cxx:356 msgid "Terminal lacks color capabilities" -msgstr "" +msgstr "Terminale manca la funzionalità dei colori differenti" #: src/TagListPage.cxx:71 msgid "All tracks" -msgstr "Tutte le piste" +msgstr "Tutte le traccie" #: src/time_format.cxx:44 msgid "year" -msgstr "" +msgstr "anno" #: src/time_format.cxx:46 msgid "years" -msgstr "" +msgstr "anni" #: src/time_format.cxx:54 msgid "week" -msgstr "" +msgstr "settimana" #: src/time_format.cxx:57 msgid "weeks" -msgstr "" +msgstr "settimane" #: src/time_format.cxx:65 msgid "day" -msgstr "" +msgstr "giorno" #: src/time_format.cxx:68 msgid "days" -msgstr "" +msgstr "giorni" #: src/TitleBar.cxx:101 msgid "Volume n/a" -msgstr "Volume n/a" +msgstr "Volume n/d" #: src/TitleBar.cxx:103 #, c-format
View file
ncmpc-0.47.tar.xz/po/ja.po
Added
@@ -0,0 +1,1214 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the ncmpc package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: ncmpc\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2020-12-17 04:29+0000\n" +"Last-Translator: Takuro Onoue <kusanaginoturugi@gmail.com>\n" +"Language-Team: Japanese <https://hosted.weblate.org/projects/ncmpc/" +"translations/ja/>\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.4-dev\n" + +#: src/Bindings.cxx:80 src/Bindings.cxx:86 +#, c-format +msgid "Key %s assigned to %s and %s" +msgstr "" + +#: src/ChatPage.cxx:64 src/ChatPage.cxx:182 +msgid "Chat" +msgstr "チャット" + +#: src/ChatPage.cxx:163 +msgid "Your message" +msgstr "あなたのメッセージ" + +#: src/ChatPage.cxx:172 +msgid "Message could not be sent" +msgstr "メッセージを送信できませんでした" + +#: src/Command.cxx:30 +msgid "Key configuration screen" +msgstr "キー設定画面" + +#: src/Command.cxx:33 +msgid "Quit" +msgstr "終了" + +#: src/Command.cxx:37 +msgid "Move cursor up" +msgstr "カーソルを上に移動" + +#: src/Command.cxx:39 +msgid "Move cursor down" +msgstr "カーソルを下に移動" + +#: src/Command.cxx:41 +msgid "Move cursor to the top of screen" +msgstr "画面上部にカーソルを移動" + +#: src/Command.cxx:43 +msgid "Move cursor to the middle of screen" +msgstr "画面中央にカーソルを移動" + +#: src/Command.cxx:45 +msgid "Move cursor to the bottom of screen" +msgstr "画面下部にカーソルを移動" + +#: src/Command.cxx:47 +msgid "Move cursor to the top of the list" +msgstr "リストの一番上にカーソルを移動" + +#: src/Command.cxx:49 +msgid "Move cursor to the bottom of the list" +msgstr "リストの一番下にカーソルを移動" + +#: src/Command.cxx:51 +msgid "Page up" +msgstr "ページアップ" + +#: src/Command.cxx:53 +msgid "Page down" +msgstr "ページダウン" + +#: src/Command.cxx:55 +msgid "Range selection" +msgstr "範囲選択" + +#: src/Command.cxx:57 +msgid "Scroll down one line" +msgstr "1行スクロールダウン" + +#: src/Command.cxx:59 +msgid "Scroll up one line" +msgstr "1行スクロールアップ" + +#: src/Command.cxx:61 +msgid "Scroll up half a screen" +msgstr "半画面スクロールアップ" + +#: src/Command.cxx:63 +msgid "Scroll down half a screen" +msgstr "半画面スクロールダウン" + +#: src/Command.cxx:65 +msgid "Select currently playing song" +msgstr "再生中の曲を選択" + +#: src/Command.cxx:70 +msgid "Help screen" +msgstr "ヘルプ画面" + +#: src/Command.cxx:72 src/HelpPage.cxx:141 +msgid "Queue screen" +msgstr "キュー画面" + +#: src/Command.cxx:74 src/HelpPage.cxx:156 +msgid "Browse screen" +msgstr "ブラウズ画面" + +#: src/Command.cxx:79 +msgid "Play/Enter directory" +msgstr "再生/入力 ディレクトリ" + +#: src/Command.cxx:81 +msgid "Pause" +msgstr "一時停止" + +#: src/Command.cxx:83 +msgid "Stop" +msgstr "停止" + +#: src/Command.cxx:85 +msgid "Crop" +msgstr "クロップ" + +#: src/Command.cxx:87 +msgid "Next track" +msgstr "次のトラック" + +#: src/Command.cxx:89 +msgid "Previous track" +msgstr "前のトラック" + +#: src/Command.cxx:91 +msgid "Seek forward" +msgstr "早送り" + +#: src/Command.cxx:93 +msgid "Seek backward" +msgstr "巻き戻し" + +#: src/Command.cxx:95 +msgid "Increase volume" +msgstr "音量上げ" + +#: src/Command.cxx:97 +msgid "Decrease volume" +msgstr "音量下げ" + +#: src/Command.cxx:99 +msgid "Select/deselect song in queue" +msgstr "キュー内の曲を選択/選択解除" + +#: src/Command.cxx:101 +msgid "Select all listed items" +msgstr "リストされているすべてのアイテムを選択" + +#: src/Command.cxx:103 +msgid "Delete song from queue" +msgstr "キューから曲を削除" + +#: src/Command.cxx:105 +msgid "Shuffle queue" +msgstr "キューをシャッフル" + +#: src/Command.cxx:107 +msgid "Clear queue" +msgstr "キューをクリア" + +#: src/Command.cxx:109 +msgid "Toggle repeat mode" +msgstr "リピートモードの切り替え" + +#: src/Command.cxx:111 +msgid "Toggle random mode" +msgstr "ランダムモードの切り替え" + +#: src/Command.cxx:113 +msgid "Toggle single mode" +msgstr "シンプルモードに切り替え" + +#: src/Command.cxx:115 +msgid "Toggle consume mode" +msgstr "" + +#: src/Command.cxx:117 +msgid "Toggle crossfade mode" +msgstr "" + +#: src/Command.cxx:119 +msgid "Start a music database update" +msgstr "" + +#: src/Command.cxx:121 +msgid "Save queue" +msgstr "" + +#: src/Command.cxx:123 src/HelpPage.cxx:175 +msgid "Append song to queue" +msgstr "" + +#: src/Command.cxx:126 +msgid "Go to root directory" +msgstr "" + +#: src/Command.cxx:128 +msgid "Go to parent directory" +msgstr "" + +#: src/Command.cxx:131 +msgid "Locate song in browser" +msgstr "" + +#: src/Command.cxx:135 +msgid "Move item up" +msgstr "" + +#: src/Command.cxx:137 +msgid "Move item down" +msgstr "" + +#: src/Command.cxx:139 +msgid "Refresh screen" +msgstr "" + +#. translators: toggle between wrapping and non-wrapping +#. search +#: src/Command.cxx:146 +msgid "Toggle find mode" +msgstr "" + +#. translators: the auto center mode always centers the song +#. currently being played +#: src/Command.cxx:150 +msgid "Toggle auto center mode" +msgstr "" + +#: src/Command.cxx:155 +msgid "Next screen" +msgstr "" + +#: src/Command.cxx:157 +msgid "Previous screen" +msgstr "" + +#: src/Command.cxx:159 +msgid "Swap to most recent screen" +msgstr "" + +#: src/Command.cxx:164 +msgid "Forward find" +msgstr "" + +#: src/Command.cxx:166 +msgid "Forward find next" +msgstr "" + +#: src/Command.cxx:168 +msgid "Backward find" +msgstr "" + +#: src/Command.cxx:170 +msgid "Backward find previous" +msgstr "" + +#. translators: this queries the user for a string +#. * and jumps directly (while the user is typing) +#. * to the entry which begins with this string +#: src/Command.cxx:175 +msgid "Jump to" +msgstr "" + +#: src/Command.cxx:181 +msgid "Library page" +msgstr "" + +#: src/Command.cxx:185 src/HelpPage.cxx:170 +msgid "Search screen" +msgstr "" + +#: src/Command.cxx:187 +msgid "Change search mode" +msgstr "" + +#: src/Command.cxx:191 +msgid "View the selected and the currently playing song" +msgstr "" + +#: src/Command.cxx:195 src/HelpPage.cxx:182 +msgid "Lyrics screen" +msgstr "" + +#. translators: interrupt the current background action, +#. e.g. stop loading lyrics from the internet +#: src/Command.cxx:199 +msgid "Interrupt action" +msgstr "" + +#: src/Command.cxx:201 +msgid "Update Lyrics" +msgstr "" + +#: src/Command.cxx:205 +msgid "Edit the current item" +msgstr "" + +#: src/Command.cxx:210 src/HelpPage.cxx:197 +msgid "Outputs screen" +msgstr "" + +#: src/Command.cxx:215 src/HelpPage.cxx:204 +msgid "Chat screen" +msgstr "" + +#: src/ConfigParser.cxx:120 +msgid "Word expected" +msgstr "" + +#: src/ConfigParser.cxx:139 +msgid "Malformed hotkey definition" +msgstr "" + +#. the hotkey configuration +#. line is incomplete +#: src/ConfigParser.cxx:158 +msgid "Incomplete hotkey configuration" +msgstr "" + +#. the hotkey configuration +#. contains an unknown +#. command +#: src/ConfigParser.cxx:172 +msgid "Unknown command" +msgstr "" + +#. translators: ncmpc +#. supports displaying the +#. "elapsed" or "remaining" +#. time of a song being +#. played; in this case, the +#. configuration file +#. contained an invalid +#. setting +#: src/ConfigParser.cxx:210 +msgid "Bad time display type" +msgstr "" + +#. an equals sign '=' was expected while parsing a +#. configuration file line +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 +msgid "Missing '='" +msgstr "" + +#: src/ConfigParser.cxx:273 +msgid "Bad color name" +msgstr "" + +#: src/ConfigParser.cxx:282 +msgid "Incomplete color definition" +msgstr "" + +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 +msgid "Invalid number" +msgstr "" + +#: src/ConfigParser.cxx:295 +msgid "Malformed color definition" +msgstr "" + +#. an unknown screen +#. name was specified +#. in the +#. configuration +#. file +#: src/ConfigParser.cxx:359 +msgid "Unknown screen name" +msgstr "" + +#: src/ConfigParser.cxx:388 +msgid "Unknown MPD tag" +msgstr "" + +#: src/ConfigParser.cxx:415 +msgid "Invalid search mode" +msgstr "" + +#: src/ConfigParser.cxx:433 +msgid "Unknown search mode" +msgstr "" + +#: src/ConfigParser.cxx:621 +msgid "Unknown configuration parameter" +msgstr "" + +#: src/CustomColors.cxx:57 +msgid "Terminal lacks support for changing colors" +msgstr "" + +#. translators: the "delete" command is only possible +#. for playlists; the user attempted to delete a song +#. or a directory or something else +#: src/FileBrowserPage.cxx:246 +msgid "Deleting this item is not possible" +msgstr "" + +#: src/FileBrowserPage.cxx:254 +#, c-format +msgid "Delete playlist %s?" +msgstr "" + +#. translators: a dialog was aborted by the user +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 +#: src/save_playlist.cxx:111 +msgid "Aborted" +msgstr "" + +#. translators: MPD deleted the playlist, as requested by the +#. user +#: src/FileBrowserPage.cxx:272 +msgid "Playlist deleted" +msgstr "" + +#. translators: caption of the browser screen +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 +msgid "Browse" +msgstr "" + +#: src/FileListPage.cxx:125 +#, c-format +msgid "Loading playlist '%s'" +msgstr "" + +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 +#: src/TagListPage.cxx:184 +#, c-format +msgid "Adding '%s' to queue" +msgstr "" + +#: src/HelpPage.cxx:61 +msgid "Movement" +msgstr "" + +#: src/HelpPage.cxx:106 +msgid "Global" +msgstr "" + +#: src/HelpPage.cxx:143 +msgid "Play" +msgstr "" + +#: src/HelpPage.cxx:150 +msgid "Center" +msgstr "" + +#: src/HelpPage.cxx:158 +msgid "Enter directory/Select and play song" +msgstr "" + +#: src/HelpPage.cxx:162 +msgid "Delete playlist" +msgstr "" + +#: src/HelpPage.cxx:172 +msgid "New search" +msgstr "" + +#: src/HelpPage.cxx:173 +msgid "Select and play" +msgstr "" + +#: src/HelpPage.cxx:184 +msgid "View Lyrics" +msgstr "" + +#: src/HelpPage.cxx:185 +msgid "(Re)load lyrics" +msgstr "" + +#. to translators: this hotkey aborts the retrieval of lyrics +#. from the server +#: src/HelpPage.cxx:188 +msgid "Interrupt retrieval" +msgstr "" + +#: src/HelpPage.cxx:189 +msgid "Download lyrics for currently playing song" +msgstr "" + +#: src/HelpPage.cxx:190 +msgid "Add or edit lyrics" +msgstr "" + +#: src/HelpPage.cxx:191 +msgid "Save lyrics" +msgstr "" + +#: src/HelpPage.cxx:192 +msgid "Delete saved lyrics" +msgstr "" + +#: src/HelpPage.cxx:199 +msgid "Enable/disable output" +msgstr "" + +#: src/HelpPage.cxx:206 +msgid "Write a message" +msgstr "" + +#: src/HelpPage.cxx:211 +msgid "Keydef screen" +msgstr "" + +#: src/HelpPage.cxx:213 +msgid "Edit keydefs for selected command" +msgstr "" + +#: src/HelpPage.cxx:214 +msgid "Remove selected keydef" +msgstr "" + +#: src/HelpPage.cxx:215 +msgid "Add a keydef" +msgstr "" + +#: src/HelpPage.cxx:216 +msgid "Go up a level" +msgstr "" + +#: src/HelpPage.cxx:217 +msgid "Apply and save changes" +msgstr "" + +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 +msgid "Help" +msgstr "" + +#: src/i18n.h:43 +msgid "y" +msgstr "" + +#: src/i18n.h:44 +msgid "n" +msgstr "" + +#: src/KeyDefPage.cxx:161 +msgid "Deleted" +msgstr "" + +#: src/KeyDefPage.cxx:177 +#, c-format +msgid "Enter new key for %s: " +msgstr "" + +#: src/KeyDefPage.cxx:187 +msgid "Ctrl-Space can't be used" +msgstr "" + +#: src/KeyDefPage.cxx:193 +#, c-format +msgid "Error: key %s is already used for %s" +msgstr "" + +#: src/KeyDefPage.cxx:203 +#, c-format +msgid "Assigned %s to %s" +msgstr "" + +#: src/KeyDefPage.cxx:230 +msgid "Add new key" +msgstr "" + +#: src/KeyDefPage.cxx:252 +#, c-format +msgid "Edit keys for %s" +msgstr "" + +#: src/KeyDefPage.cxx:395 +msgid "You have new key bindings" +msgstr "" + +#: src/KeyDefPage.cxx:397 +msgid "Keybindings unchanged." +msgstr "" + +#: src/KeyDefPage.cxx:407 +msgid "Unable to write configuration" +msgstr "" + +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 +msgid "Error" +msgstr "" + +#: src/KeyDefPage.cxx:423 +#, c-format +msgid "Wrote %s" +msgstr "" + +#: src/KeyDefPage.cxx:436 +msgid "===> Apply key bindings " +msgstr "" + +#: src/KeyDefPage.cxx:438 +msgid "===> Apply & Save key bindings " +msgstr "" + +#: src/KeyDefPage.cxx:475 +msgid "Edit key bindings" +msgstr "" + +#: src/KeyDefPage.cxx:557 +msgid "Note: Did you forget to 'Apply' your changes?" +msgstr "" + +#: src/KeyDefPage.cxx:607 +msgid "Keys" +msgstr "" + +#: src/KeyName.cxx:115 +msgid "Undefined" +msgstr "" + +#: src/KeyName.cxx:117 +msgid "Space" +msgstr "" + +#: src/KeyName.cxx:119 +msgid "Enter" +msgstr "" + +#: src/KeyName.cxx:121 +msgid "Backspace" +msgstr "" + +#: src/KeyName.cxx:123 +msgid "Delete" +msgstr "" + +#: src/KeyName.cxx:125 +msgid "Up" +msgstr "" + +#: src/KeyName.cxx:127 +msgid "Down" +msgstr "" + +#: src/KeyName.cxx:129 +msgid "Left" +msgstr "" + +#: src/KeyName.cxx:131 +msgid "Right" +msgstr "" + +#: src/KeyName.cxx:133 +msgid "Home" +msgstr "" + +#: src/KeyName.cxx:135 +msgid "End" +msgstr "" + +#: src/KeyName.cxx:137 +msgid "PageDown" +msgstr "" + +#: src/KeyName.cxx:139 +msgid "PageUp" +msgstr "" + +#: src/KeyName.cxx:141 +msgid "Tab" +msgstr "" + +#: src/KeyName.cxx:143 +msgid "Shift+Tab" +msgstr "" + +#: src/KeyName.cxx:145 +msgid "Esc" +msgstr "" + +#: src/KeyName.cxx:147 +msgid "Insert" +msgstr "" + +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 +#, c-format +msgid "Ctrl-%c" +msgstr "" + +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 +#, c-format +msgid "Alt-%c" +msgstr "" + +#: src/LibraryPage.cxx:45 +msgid "Artists" +msgstr "" + +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 +msgid "Albums" +msgstr "" + +#: src/LibraryPage.cxx:123 +msgid "All" +msgstr "" + +#: src/LibraryPage.cxx:197 +msgid "Songs" +msgstr "" + +#: src/LibraryPage.cxx:314 +msgid "Library" +msgstr "" + +#: src/ListWindow.cxx:213 +msgid "Range selection disabled" +msgstr "" + +#: src/ListWindow.cxx:216 +msgid "Range selection enabled" +msgstr "" + +#. translators: no lyrics were found for the song +#: src/LyricsPage.cxx:253 +msgid "No lyrics" +msgstr "" + +#: src/LyricsPage.cxx:270 +#, c-format +msgid "Lyrics timeout occurred after %d seconds" +msgstr "" + +#: src/LyricsPage.cxx:353 src/LyricsPage.cxx:361 src/LyricsPage.cxx:371 +#: src/LyricsPage.cxx:507 +msgid "Lyrics" +msgstr "" + +#. translators: this message is displayed +#. while data is retrieved +#: src/LyricsPage.cxx:356 +msgid "loading..." +msgstr "" + +#: src/LyricsPage.cxx:378 +msgid "Editor not configured" +msgstr "" + +#: src/LyricsPage.cxx:385 +msgid "Do you really want to start an editor and edit these lyrics?" +msgstr "" + +#: src/LyricsPage.cxx:403 src/LyricsPage.cxx:427 +msgid "Can't start editor" +msgstr "" + +#: src/LyricsPage.cxx:430 src/LyricsPage.cxx:434 +msgid "Editor exited unexpectedly" +msgstr "" + +#. lyrics for the song were saved on hard disk +#: src/LyricsPage.cxx:456 +msgid "Lyrics saved" +msgstr "" + +#: src/LyricsPage.cxx:462 +msgid "Lyrics deleted" +msgstr "" + +#: src/LyricsPage.cxx:463 +msgid "No saved lyrics" +msgstr "" + +#: src/Main.cxx:133 +#, c-format +msgid "Connecting to %s" +msgstr "" + +#: src/Main.cxx:149 +#, c-format +msgid "Error: MPD version %d.%d.%d is too old (%s needed)" +msgstr "" + +#. To translators: these credits are shown +#. when ncmpc is started with "--version" +#: src/Options.cxx:216 src/Options.cxx:219 +msgid "translator-credits" +msgstr "" + +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "" + +#: src/OutputsPage.cxx:230 +#, c-format +msgid "Output '%s' enabled" +msgstr "" + +#: src/OutputsPage.cxx:241 +#, c-format +msgid "Output '%s' disabled" +msgstr "" + +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 +msgid "Outputs" +msgstr "" + +#: src/OutputsPage.cxx:383 +msgid "Partition" +msgstr "" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "" + +#: src/player_command.cxx:94 src/QueuePage.cxx:651 +msgid "Shuffled queue" +msgstr "" + +#: src/player_command.cxx:100 +msgid "Cleared queue" +msgstr "" + +#. get path +#: src/QueuePage.cxx:314 +msgid "Add" +msgstr "" + +#: src/QueuePage.cxx:379 src/QueuePage.cxx:697 +msgid "Queue" +msgstr "" + +#: src/QueuePage.cxx:381 +#, c-format +msgid "Queue on %s" +msgstr "" + +#. query the user for a filename +#: src/save_playlist.cxx:86 +msgid "Save queue as" +msgstr "" + +#: src/save_playlist.cxx:108 +#, c-format +msgid "Replace %s?" +msgstr "" + +#. success +#: src/save_playlist.cxx:129 +#, c-format +msgid "Saved %s" +msgstr "" + +#: src/screen_client.cxx:41 +msgid "Database update running" +msgstr "" + +#: src/screen_client.cxx:48 +#, c-format +msgid "Database update of %s started" +msgstr "" + +#: src/screen_client.cxx:51 +msgid "Database update started" +msgstr "" + +#: src/screen.cxx:158 +msgid "Repeat mode is on" +msgstr "" + +#: src/screen.cxx:159 +msgid "Repeat mode is off" +msgstr "" + +#: src/screen.cxx:163 +msgid "Random mode is on" +msgstr "" + +#: src/screen.cxx:164 +msgid "Random mode is off" +msgstr "" + +#. "single" mode means +#. that MPD will +#. automatically stop +#. after playing one +#. single song +#: src/screen.cxx:173 +msgid "Single mode is on" +msgstr "" + +#: src/screen.cxx:174 +msgid "Single mode is off" +msgstr "" + +#. "consume" mode means +#. that MPD removes each +#. song which has +#. finished playing +#: src/screen.cxx:182 +msgid "Consume mode is on" +msgstr "" + +#: src/screen.cxx:183 +msgid "Consume mode is off" +msgstr "" + +#: src/screen.cxx:186 +#, c-format +msgid "Crossfade %d seconds" +msgstr "" + +#: src/screen.cxx:198 +msgid "Database updated" +msgstr "" + +#: src/screen.cxx:248 +msgid "Find mode: Wrapped" +msgstr "" + +#: src/screen.cxx:249 +msgid "Find mode: Normal" +msgstr "" + +#: src/screen.cxx:254 +msgid "Auto center mode: On" +msgstr "" + +#: src/screen.cxx:255 +msgid "Auto center mode: Off" +msgstr "" + +#: src/screen_find.cxx:33 +msgid "Find" +msgstr "" + +#: src/screen_find.cxx:34 +msgid "Find backward" +msgstr "" + +#: src/screen_find.cxx:35 +msgid "Jump" +msgstr "" + +#: src/screen_find.cxx:81 +#, c-format +msgid "Unable to find '%s'" +msgstr "" + +#: src/screen_utils.cxx:150 +msgid "Password" +msgstr "" + +#: src/SearchPage.cxx:51 +msgid "artist" +msgstr "" + +#: src/SearchPage.cxx:52 +msgid "album" +msgstr "" + +#: src/SearchPage.cxx:53 +msgid "title" +msgstr "" + +#: src/SearchPage.cxx:54 +msgid "track" +msgstr "" + +#: src/SearchPage.cxx:55 +msgid "name" +msgstr "" + +#: src/SearchPage.cxx:56 +msgid "genre" +msgstr "" + +#: src/SearchPage.cxx:57 +msgid "date" +msgstr "" + +#: src/SearchPage.cxx:58 +msgid "composer" +msgstr "" + +#: src/SearchPage.cxx:59 +msgid "performer" +msgstr "" + +#: src/SearchPage.cxx:60 +msgid "comment" +msgstr "" + +#: src/SearchPage.cxx:68 +msgid "file" +msgstr "" + +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 +msgid "Title" +msgstr "" + +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 +msgid "Artist" +msgstr "" + +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 +msgid "Album" +msgstr "" + +#: src/SearchPage.cxx:93 +msgid "Filename" +msgstr "" + +#: src/SearchPage.cxx:94 +msgid "Artist + Title" +msgstr "" + +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "" + +#: src/SearchPage.cxx:337 +#, c-format +msgid "Bad search tag %s" +msgstr "" + +#: src/SearchPage.cxx:351 +#, c-format +msgid "No argument for search tag %s" +msgstr "" + +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 +msgid "Search" +msgstr "" + +#: src/SearchPage.cxx:509 +#, c-format +msgid "Search mode: %s" +msgstr "" + +#: src/SongPage.cxx:65 +msgid "Length" +msgstr "" + +#: src/SongPage.cxx:66 +msgid "Position" +msgstr "" + +#: src/SongPage.cxx:67 +msgid "Composer" +msgstr "" + +#: src/SongPage.cxx:68 +msgid "Performer" +msgstr "" + +#: src/SongPage.cxx:70 +msgid "Disc" +msgstr "" + +#: src/SongPage.cxx:71 +msgid "Track" +msgstr "" + +#: src/SongPage.cxx:72 +msgid "Date" +msgstr "" + +#: src/SongPage.cxx:73 +msgid "Genre" +msgstr "" + +#: src/SongPage.cxx:74 +msgid "Comment" +msgstr "" + +#: src/SongPage.cxx:75 +msgid "Path" +msgstr "" + +#: src/SongPage.cxx:76 +msgid "Bitrate" +msgstr "" + +#: src/SongPage.cxx:77 +msgid "Format" +msgstr "" + +#: src/SongPage.cxx:94 +msgid "Number of artists" +msgstr "" + +#: src/SongPage.cxx:95 +msgid "Number of albums" +msgstr "" + +#: src/SongPage.cxx:96 +msgid "Number of songs" +msgstr "" + +#: src/SongPage.cxx:97 +msgid "Uptime" +msgstr "" + +#: src/SongPage.cxx:98 +msgid "Most recent db update" +msgstr "" + +#: src/SongPage.cxx:99 +msgid "Playtime" +msgstr "" + +#: src/SongPage.cxx:100 +msgid "DB playtime" +msgstr "" + +#: src/SongPage.cxx:205 +msgid "Song viewer" +msgstr "" + +#: src/SongPage.cxx:371 +msgid "MPD statistics" +msgstr "" + +#: src/SongPage.cxx:457 +msgid "Selected song" +msgstr "" + +#: src/SongPage.cxx:467 +msgid "Currently playing song" +msgstr "" + +#: src/SongPage.cxx:472 +#, c-format +msgid "%d kbps" +msgstr "" + +#: src/SongPage.cxx:556 +msgid "Song" +msgstr "" + +#: src/StatusBar.cxx:165 +msgid "Playing:" +msgstr "" + +#: src/StatusBar.cxx:169 +msgid "Paused" +msgstr "" + +#: src/Styles.cxx:252 src/Styles.cxx:313 +msgid "Unknown color" +msgstr "" + +#: src/Styles.cxx:323 +msgid "Unknown color field" +msgstr "" + +#: src/Styles.cxx:356 +msgid "Terminal lacks color capabilities" +msgstr "" + +#: src/TagListPage.cxx:71 +msgid "All tracks" +msgstr "" + +#: src/time_format.cxx:44 +msgid "year" +msgstr "" + +#: src/time_format.cxx:46 +msgid "years" +msgstr "" + +#: src/time_format.cxx:54 +msgid "week" +msgstr "" + +#: src/time_format.cxx:57 +msgid "weeks" +msgstr "" + +#: src/time_format.cxx:65 +msgid "day" +msgstr "" + +#: src/time_format.cxx:68 +msgid "days" +msgstr "" + +#: src/TitleBar.cxx:101 +msgid "Volume n/a" +msgstr "" + +#: src/TitleBar.cxx:103 +#, c-format +msgid "Volume %d%%" +msgstr ""
View file
ncmpc-0.36.tar.xz/po/ko.po -> ncmpc-0.47.tar.xz/po/ko.po
Changed
@@ -7,8 +7,8 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2019-09-16 09:02+0000\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2020-10-10 15:26+0000\n" "Last-Translator: Min Ho Park <parkmino@gmail.com>\n" "Language-Team: Korean <https://hosted.weblate.org/projects/ncmpc/" "translations/ko/>\n" @@ -17,10 +17,10 @@ "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 3.9-dev\n" +"X-Generator: Weblate 4.3-dev\n" "X-Launchpad-Export-Date: 2009-10-19 13:36+0000\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "%s 키가 %s 및 %s 에 지정됨" @@ -37,309 +37,309 @@ msgid "Message could not be sent" msgstr "메시지를 보낼 수 없습니다" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "키 설정 화면" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "나가기" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "커서를 위로 올리기" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "커서를 아래로 내리기" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "커서를 화면 맨 위로 옮기기" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "커서를 화면 가운데로 옮기기" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "커서를 화면 맨 아래로 옮기기" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "커서를 목록 맨 위로 옮기기" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "커서를 목록 맨 아래로 옮기기" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "위쪽 페이지" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "아래쪽 페이지" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "범위 선택" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "한 줄 아래로 내리기" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "한 줄 위로 올리기" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "화면 반 위로 올리기" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "화면 반 아래로 내리기" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "지금 연주 중인 곡을 선택" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "도움 화면" -#: src/Command.cxx:71 src/HelpPage.cxx:140 +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" msgstr "순서 화면" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "음원 화면" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "연주/디렉터리 입력" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "잠깐 멈춤" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "멈춤" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "선택" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "다음 곡" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "이전 곡" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "앞으로 찾기" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "뒤로 찾기" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "음량 높이기" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "음량 낮추기" -#: src/Command.cxx:98 +#: src/Command.cxx:99 msgid "Select/deselect song in queue" msgstr "순서에서 곡 선택함/안 함" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "목록의 모든 항목 선택" -#: src/Command.cxx:102 +#: src/Command.cxx:103 msgid "Delete song from queue" msgstr "순서에서 곡 지우기" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" msgstr "순서 뒤섞기" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" msgstr "순서 지우기" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "반복연주 모드 토글" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "무작위연주 모드 토글" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "한 곡 모드 토글" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "소비 모드 토글" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "크로스페이드 모드 토글" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "음악 데이터베이스 업데이트 시작" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" msgstr "순서 저장" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" msgstr "순서에 곡 더하기" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "루트 디렉터리로 가기" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "상위 디렉터리로 가기" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "음원에서 곡 찾기" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "항목 위로 올리기" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "항목 아래로 내리기" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "화면 새로 고치기" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "찾기 모드 토글" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "자동 가운데 모드 토글" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "다음 화면" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "이전 화면" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "최근 화면으로 바꾸기" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "앞으로 찾기" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "앞으로 다음 찾기" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "뒤로 찾기" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "뒤로 이전 찾기" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "바로 이동" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" msgstr "라이브러리 페이지" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "찾기 화면" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "찾기 모드 변경" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "선택하고 지금 연주 중인 곡 보기" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "가사 화면" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "백그라운드 실행 중지" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "가사 업데이트" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "현재 항목 수정" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "출력 화면" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" msgstr "채팅 화면" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "단어 요구됨" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "잘못된 단축키 정의" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "불완전한 단축키 설정" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "모르는 명령어" @@ -351,29 +351,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "잘못된 시간 표시 형식" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "'=' 기호가 없음" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "잘못된 색상 이름" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "불완전한 색상 지정" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "잘못된 숫자" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "잘못된 색상 지정" @@ -382,23 +382,23 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "모르는 화면 이름" -#: src/ConfigParser.cxx:403 +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" msgstr "모르는 MPD 태그" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "잘못된 검색 모드" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "모르는 검색 모드" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "모르는 설정 요소" @@ -409,138 +409,138 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "이 항목을 지울 수 없습니다" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, c-format msgid "Delete playlist %s?" msgstr "%s 연주목록을 지울까요?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "중단됨" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "연주목록을 지움" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "음원" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, c-format msgid "Loading playlist '%s'" msgstr "'%s' 연주목록을 읽는 중" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 #, c-format msgid "Adding '%s' to queue" msgstr "순서에 '%s' 추가" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "이동" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "전체" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "연주" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "가운데" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "디렉터리를 입력/곡을 선택하고 연주" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "연주목록 지우기" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 msgid "New search" msgstr "새로 찾기" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "선택하고 연주" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "가사 보기" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "가사 (다시)읽기" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "가사 가져오기 중지" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "연주 중인 노래의 가사 내려받기" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" msgstr "가사를 추가하거나 수정하기" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "가사 저장하기" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" msgstr "저장된 가사 지우기" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "출력 사용함/안 함" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" msgstr "메시지 작성" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "키설정 화면" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "선택한 명령을 위한 키설정 편집" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "선택한 키설정 삭제" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 msgid "Add a keydef" msgstr "키 설정 추가" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "한 단계 위로 가기" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "적용하고 변경사항을 저장" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "도움" @@ -552,153 +552,155 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "삭제됨" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "%s의 새 키 입력: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" msgstr "Ctrl-Space 사용할 수 없음" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "오류: %s 키는 이미 %s에 사용함" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "%s 키가 %s에 지정됨" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "새로운 키 추가" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "%s 키 편집" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "새로운 키 조합입니다" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "키 조합이 바뀌지 않았습니다." -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" msgstr "설정 쓰기가 안 됨" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "오류" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "%s 쓰기" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "===> 키 조합을 적용 " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "===> 키 조합을 적용하고 저장 " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "키 조합 편집" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "주의: 변경사항 '적용하기'를 잊었나요?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "키" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "정의되지 않음" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Space" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Enter" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "Backspace" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Delete" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Up" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Down" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "Left" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "Right" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Home" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "End" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "PageDown" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "PageUp" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Shift+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Insert" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "Ctrl-%c" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "Alt-%c" @@ -707,7 +709,7 @@ msgid "Artists" msgstr "연주가" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 msgid "Albums" msgstr "음반" @@ -715,11 +717,11 @@ msgid "All" msgstr "모두" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" msgstr "곡" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" msgstr "라이브러리" @@ -781,12 +783,12 @@ msgid "No saved lyrics" msgstr "저장된 가사가 없음" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, c-format msgid "Connecting to %s" msgstr "%s로 연결 중" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "오류: 너무 오래된 MPD %d.%d.%d 버전 (%s 필요)" @@ -797,20 +799,37 @@ msgid "translator-credits" msgstr "번역자-기여" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "'%s' 칸막이로 바꾸기" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "이름" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "출력 '%s' 사용함" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "출력 '%s' 사용 안 함" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "출력" +#: src/OutputsPage.cxx:383 +msgid "Partition" +msgstr "칸막이" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "새 칸막이 만들기" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" msgstr "순서 뒤섞음" @@ -949,86 +968,90 @@ msgid "Password" msgstr "열쇠글" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "연주가" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "음반" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "제목" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "곡" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "이름" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "장르" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "날짜" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "작곡가" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "연주가" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "설명" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "파일" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "제목" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "연주가" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "음반" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "파일이름" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "연주가 + 제목" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "미 인식 서픽스" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "잘못된 찾기 태그 %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "%s 찾기 태그의 인자가 없음" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "찾기" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "찾기 방식: %s" @@ -1046,99 +1069,99 @@ msgstr "작곡가" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "이름" +msgid "Performer" +msgstr "연주가" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "디스크" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "곡" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "날짜" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "장르" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "설명" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "경로" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "비트 전송률" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" msgstr "형식" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "연주가 수" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "음반 수" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "곡 수" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "가동시간" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "마지막 데이터베이스 업데이트" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "연주시간" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "데이터베이스 연주시간" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "곡 보기" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "MPD 통계" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "선택한 곡" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "지금 연주 중인 곡" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d kbps" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" msgstr "곡" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "연주 중:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "잠깐 멈춤"
View file
ncmpc-0.47.tar.xz/po/lt.po
Added
@@ -0,0 +1,1216 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the ncmpc package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: ncmpc\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2021-08-27 09:34+0000\n" +"Last-Translator: Gediminas Murauskas <muziejusinfo@gmail.com>\n" +"Language-Team: Lithuanian <https://hosted.weblate.org/projects/ncmpc/" +"translations/lt/>\n" +"Language: lt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n % 10 == 1 && (n % 100 < 11 || n % 100 > " +"19)) ? 0 : ((n % 10 >= 2 && n % 10 <= 9 && (n % 100 < 11 || n % 100 > 19)) ? " +"1 : 2);\n" +"X-Generator: Weblate 4.8.1-dev\n" + +#: src/Bindings.cxx:80 src/Bindings.cxx:86 +#, c-format +msgid "Key %s assigned to %s and %s" +msgstr "Klavišas %s priskirtas %s ir %s" + +#: src/ChatPage.cxx:64 src/ChatPage.cxx:182 +msgid "Chat" +msgstr "Pokalbiai" + +#: src/ChatPage.cxx:163 +msgid "Your message" +msgstr "Tavo žinutė" + +#: src/ChatPage.cxx:172 +msgid "Message could not be sent" +msgstr "Žinutės nepavyko išsiųsti" + +#: src/Command.cxx:30 +msgid "Key configuration screen" +msgstr "Klavišų konfigūracijos ekranas" + +#: src/Command.cxx:33 +msgid "Quit" +msgstr "Išeiti" + +#: src/Command.cxx:37 +msgid "Move cursor up" +msgstr "Perkelti žymeklį aukštyn" + +#: src/Command.cxx:39 +msgid "Move cursor down" +msgstr "Perkelti žymeklį žemyn" + +#: src/Command.cxx:41 +msgid "Move cursor to the top of screen" +msgstr "Perkelti žymeklį į ekrano viršų" + +#: src/Command.cxx:43 +msgid "Move cursor to the middle of screen" +msgstr "Perkelti žymeklį į ekrano vidurį" + +#: src/Command.cxx:45 +msgid "Move cursor to the bottom of screen" +msgstr "Perkelti žymeklį į ekrano apačią" + +#: src/Command.cxx:47 +msgid "Move cursor to the top of the list" +msgstr "Perkelti žymeklį į sąrašo viršų" + +#: src/Command.cxx:49 +msgid "Move cursor to the bottom of the list" +msgstr "Perkelti žymeklį į sąrašo apačią" + +#: src/Command.cxx:51 +msgid "Page up" +msgstr "Puslapis aukštyn" + +#: src/Command.cxx:53 +msgid "Page down" +msgstr "Puslapis žemyn" + +#: src/Command.cxx:55 +msgid "Range selection" +msgstr "Diapazono pasirinkimas" + +#: src/Command.cxx:57 +msgid "Scroll down one line" +msgstr "Slinkti viena eilute žemyn" + +#: src/Command.cxx:59 +msgid "Scroll up one line" +msgstr "Slinkti viena eilute aukštyn" + +#: src/Command.cxx:61 +msgid "Scroll up half a screen" +msgstr "Slinkti aukštyn pusę ekrano" + +#: src/Command.cxx:63 +msgid "Scroll down half a screen" +msgstr "Slinkti žemyn pusę ekrano" + +#: src/Command.cxx:65 +msgid "Select currently playing song" +msgstr "Pasirinkti šiuo metu leidžiamą dainą" + +#: src/Command.cxx:70 +msgid "Help screen" +msgstr "Žinyno ekranas" + +#: src/Command.cxx:72 src/HelpPage.cxx:141 +msgid "Queue screen" +msgstr "Eilės ekranas" + +#: src/Command.cxx:74 src/HelpPage.cxx:156 +msgid "Browse screen" +msgstr "Naršymo ekranas" + +#: src/Command.cxx:79 +msgid "Play/Enter directory" +msgstr "Groti/eiti į katalogą" + +#: src/Command.cxx:81 +msgid "Pause" +msgstr "Pauzė" + +#: src/Command.cxx:83 +msgid "Stop" +msgstr "Sustabdyti" + +#: src/Command.cxx:85 +msgid "Crop" +msgstr "Apkarpyti" + +#: src/Command.cxx:87 +msgid "Next track" +msgstr "Kitas kūrinys" + +#: src/Command.cxx:89 +msgid "Previous track" +msgstr "Ankstesnis kūrinys" + +#: src/Command.cxx:91 +msgid "Seek forward" +msgstr "Persukti pirmyn" + +#: src/Command.cxx:93 +msgid "Seek backward" +msgstr "Persukti atgal" + +#: src/Command.cxx:95 +msgid "Increase volume" +msgstr "Padidinti garsą" + +#: src/Command.cxx:97 +msgid "Decrease volume" +msgstr "Sumažinti garsą" + +#: src/Command.cxx:99 +msgid "Select/deselect song in queue" +msgstr "Pasirinkti/panaikinti dainos pasirinkimą eilėje" + +#: src/Command.cxx:101 +msgid "Select all listed items" +msgstr "Pasirinkti visus išvardintus elementus" + +#: src/Command.cxx:103 +msgid "Delete song from queue" +msgstr "Ištrinti dainą iš eilės" + +#: src/Command.cxx:105 +msgid "Shuffle queue" +msgstr "Maišyti eilę" + +#: src/Command.cxx:107 +msgid "Clear queue" +msgstr "Išvalyti eilę" + +#: src/Command.cxx:109 +msgid "Toggle repeat mode" +msgstr "Perjungti kartojimo režimą" + +#: src/Command.cxx:111 +msgid "Toggle random mode" +msgstr "Perjungti atsitiktinį režimą" + +#: src/Command.cxx:113 +msgid "Toggle single mode" +msgstr "Perjungti vienos dainos režimą" + +#: src/Command.cxx:115 +msgid "Toggle consume mode" +msgstr "Perjungti panaikinimo iš eilės po perklausimo režimą" + +#: src/Command.cxx:117 +msgid "Toggle crossfade mode" +msgstr "Perjungti kryžminimo režimą" + +#: src/Command.cxx:119 +msgid "Start a music database update" +msgstr "Pradėti muzikos duomenų bazės atnaujinimą" + +#: src/Command.cxx:121 +msgid "Save queue" +msgstr "Išsaugoti eilę" + +#: src/Command.cxx:123 src/HelpPage.cxx:175 +msgid "Append song to queue" +msgstr "Įtraukti dainą į eilę" + +#: src/Command.cxx:126 +msgid "Go to root directory" +msgstr "Eiti į šakninį katalogą" + +#: src/Command.cxx:128 +msgid "Go to parent directory" +msgstr "Eiti į pirminį katalogą" + +#: src/Command.cxx:131 +msgid "Locate song in browser" +msgstr "Surasti dainą naršyklėje" + +#: src/Command.cxx:135 +msgid "Move item up" +msgstr "Perkelti elementą aukštyn" + +#: src/Command.cxx:137 +msgid "Move item down" +msgstr "Perkelti elementą žemyn" + +#: src/Command.cxx:139 +msgid "Refresh screen" +msgstr "Atnaujinti ekraną" + +#. translators: toggle between wrapping and non-wrapping +#. search +#: src/Command.cxx:146 +msgid "Toggle find mode" +msgstr "Perjungti paieškos režimą" + +#. translators: the auto center mode always centers the song +#. currently being played +#: src/Command.cxx:150 +msgid "Toggle auto center mode" +msgstr "Perjungti automatinio centravimo režimą" + +#: src/Command.cxx:155 +msgid "Next screen" +msgstr "Kitas ekranas" + +#: src/Command.cxx:157 +msgid "Previous screen" +msgstr "Ankstesnis ekranas" + +#: src/Command.cxx:159 +msgid "Swap to most recent screen" +msgstr "Perjungti į paskiausią ekraną" + +#: src/Command.cxx:164 +msgid "Forward find" +msgstr "Rasti toliau" + +#: src/Command.cxx:166 +msgid "Forward find next" +msgstr "Rasti toliau sekantį" + +#: src/Command.cxx:168 +msgid "Backward find" +msgstr "Rasti prieš tai" + +#: src/Command.cxx:170 +msgid "Backward find previous" +msgstr "Rasti prieš tai sekantį" + +#. translators: this queries the user for a string +#. * and jumps directly (while the user is typing) +#. * to the entry which begins with this string +#: src/Command.cxx:175 +msgid "Jump to" +msgstr "Pereiti prie" + +#: src/Command.cxx:181 +msgid "Library page" +msgstr "Bibliotekos puslapis" + +#: src/Command.cxx:185 src/HelpPage.cxx:170 +msgid "Search screen" +msgstr "Paieškos ekranas" + +#: src/Command.cxx:187 +msgid "Change search mode" +msgstr "Pakeiskite paieškos režimą" + +#: src/Command.cxx:191 +msgid "View the selected and the currently playing song" +msgstr "Peržiūrėti pasirinktą ir šiuo metu grojamą dainą" + +#: src/Command.cxx:195 src/HelpPage.cxx:182 +msgid "Lyrics screen" +msgstr "Dainos teksto ekranas" + +#. translators: interrupt the current background action, +#. e.g. stop loading lyrics from the internet +#: src/Command.cxx:199 +msgid "Interrupt action" +msgstr "Nutraukti veiksmą" + +#: src/Command.cxx:201 +msgid "Update Lyrics" +msgstr "Atnaujinti dainos tekstą" + +#: src/Command.cxx:205 +msgid "Edit the current item" +msgstr "Redaguoti dabartinį elementą" + +#: src/Command.cxx:210 src/HelpPage.cxx:197 +msgid "Outputs screen" +msgstr "Išvesties ekranas" + +#: src/Command.cxx:215 src/HelpPage.cxx:204 +msgid "Chat screen" +msgstr "Pokalbių ekranas" + +#: src/ConfigParser.cxx:120 +msgid "Word expected" +msgstr "Laukiamas žodis" + +#: src/ConfigParser.cxx:139 +msgid "Malformed hotkey definition" +msgstr "Netinkamai suformuota sparčiojo klavišo apibrėžtis" + +#. the hotkey configuration +#. line is incomplete +#: src/ConfigParser.cxx:158 +msgid "Incomplete hotkey configuration" +msgstr "Nebaigta sparčiųjų klavišų konfigūracija" + +#. the hotkey configuration +#. contains an unknown +#. command +#: src/ConfigParser.cxx:172 +msgid "Unknown command" +msgstr "Nežinoma komanda" + +#. translators: ncmpc +#. supports displaying the +#. "elapsed" or "remaining" +#. time of a song being +#. played; in this case, the +#. configuration file +#. contained an invalid +#. setting +#: src/ConfigParser.cxx:210 +msgid "Bad time display type" +msgstr "Netinkamas laiko rodymo tipas" + +#. an equals sign '=' was expected while parsing a +#. configuration file line +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 +msgid "Missing '='" +msgstr "Trūksta „=“" + +#: src/ConfigParser.cxx:273 +msgid "Bad color name" +msgstr "Blogas spalvos pavadinimas" + +#: src/ConfigParser.cxx:282 +msgid "Incomplete color definition" +msgstr "Nebaigtas spalvos apibrėžimas" + +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 +msgid "Invalid number" +msgstr "Netinkamas skaičius" + +#: src/ConfigParser.cxx:295 +msgid "Malformed color definition" +msgstr "Netinkamai suformuotas spalvos apibrėžimas" + +#. an unknown screen +#. name was specified +#. in the +#. configuration +#. file +#: src/ConfigParser.cxx:359 +msgid "Unknown screen name" +msgstr "Nežinomas ekrano pavadinimas" + +#: src/ConfigParser.cxx:388 +msgid "Unknown MPD tag" +msgstr "Nežinoma MPD žyma" + +#: src/ConfigParser.cxx:415 +msgid "Invalid search mode" +msgstr "Netinkamas paieškos režimas" + +#: src/ConfigParser.cxx:433 +msgid "Unknown search mode" +msgstr "Nežinomas paieškos režimas" + +#: src/ConfigParser.cxx:621 +msgid "Unknown configuration parameter" +msgstr "Nežinomas konfigūracijos parametras" + +#: src/CustomColors.cxx:57 +msgid "Terminal lacks support for changing colors" +msgstr "Terminale nėra spalvų keitimo palaikymo" + +#. translators: the "delete" command is only possible +#. for playlists; the user attempted to delete a song +#. or a directory or something else +#: src/FileBrowserPage.cxx:246 +msgid "Deleting this item is not possible" +msgstr "Šio elemento ištrinti neįmanoma" + +#: src/FileBrowserPage.cxx:254 +#, c-format +msgid "Delete playlist %s?" +msgstr "Ištrinti grojaraštį %s?" + +#. translators: a dialog was aborted by the user +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 +#: src/save_playlist.cxx:111 +msgid "Aborted" +msgstr "Nutraukta" + +#. translators: MPD deleted the playlist, as requested by the +#. user +#: src/FileBrowserPage.cxx:272 +msgid "Playlist deleted" +msgstr "Grojaraštis ištrintas" + +#. translators: caption of the browser screen +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 +msgid "Browse" +msgstr "Naršyti" + +#: src/FileListPage.cxx:125 +#, c-format +msgid "Loading playlist '%s'" +msgstr "Įkeliamas grojaraštis „%s“" + +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 +#: src/TagListPage.cxx:184 +#, c-format +msgid "Adding '%s' to queue" +msgstr "„%s“ įtraukiama į eilę" + +#: src/HelpPage.cxx:61 +msgid "Movement" +msgstr "Judėjimas" + +#: src/HelpPage.cxx:106 +msgid "Global" +msgstr "Visuotiniai" + +#: src/HelpPage.cxx:143 +msgid "Play" +msgstr "Groti" + +#: src/HelpPage.cxx:150 +msgid "Center" +msgstr "Centruoti" + +#: src/HelpPage.cxx:158 +msgid "Enter directory/Select and play song" +msgstr "Įeiti į katalogą/pasirinkti ir paleisti dainą" + +#: src/HelpPage.cxx:162 +msgid "Delete playlist" +msgstr "Ištrinti grojaraštį" + +#: src/HelpPage.cxx:172 +msgid "New search" +msgstr "Nauja paieška" + +#: src/HelpPage.cxx:173 +msgid "Select and play" +msgstr "Pasirinkti ir groti" + +#: src/HelpPage.cxx:184 +msgid "View Lyrics" +msgstr "Peržiūrėti dainos tekstą" + +#: src/HelpPage.cxx:185 +msgid "(Re)load lyrics" +msgstr "(Iš naujo) įkelti dainos žodžius" + +#. to translators: this hotkey aborts the retrieval of lyrics +#. from the server +#: src/HelpPage.cxx:188 +msgid "Interrupt retrieval" +msgstr "Nutraukti gavimą" + +#: src/HelpPage.cxx:189 +msgid "Download lyrics for currently playing song" +msgstr "Atsisiųsti šiuo metu grojamos dainos žodžius" + +#: src/HelpPage.cxx:190 +msgid "Add or edit lyrics" +msgstr "Pridėti arba redaguoti dainos tekstą" + +#: src/HelpPage.cxx:191 +msgid "Save lyrics" +msgstr "Išsaugoti dainos žodžius" + +#: src/HelpPage.cxx:192 +msgid "Delete saved lyrics" +msgstr "Ištrinti išsaugotus dainų tekstus" + +#: src/HelpPage.cxx:199 +msgid "Enable/disable output" +msgstr "Įjungti/išjungti išvestį" + +#: src/HelpPage.cxx:206 +msgid "Write a message" +msgstr "Rašyti žinutę" + +#: src/HelpPage.cxx:211 +msgid "Keydef screen" +msgstr "Klavišų priskyrimo ekranas" + +#: src/HelpPage.cxx:213 +msgid "Edit keydefs for selected command" +msgstr "Redaguoti pasirinktos komandos klavišų nustatymus" + +#: src/HelpPage.cxx:214 +msgid "Remove selected keydef" +msgstr "Pašalinti pasirinktą klaviatūros klavišo nustatymą" + +#: src/HelpPage.cxx:215 +msgid "Add a keydef" +msgstr "Pridėti klavišo nustatymą" + +#: src/HelpPage.cxx:216 +msgid "Go up a level" +msgstr "Pakilti vienu lygiu" + +#: src/HelpPage.cxx:217 +msgid "Apply and save changes" +msgstr "Taikyti ir išsaugoti pakeitimus" + +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 +msgid "Help" +msgstr "Pagalba" + +#: src/i18n.h:43 +msgid "y" +msgstr "t" + +#: src/i18n.h:44 +msgid "n" +msgstr "n" + +#: src/KeyDefPage.cxx:161 +msgid "Deleted" +msgstr "Ištrinta" + +#: src/KeyDefPage.cxx:177 +#, c-format +msgid "Enter new key for %s: " +msgstr "Įveskite naują %s klavišą: " + +#: src/KeyDefPage.cxx:187 +msgid "Ctrl-Space can't be used" +msgstr "Ctrl-Space negalima naudoti" + +#: src/KeyDefPage.cxx:193 +#, c-format +msgid "Error: key %s is already used for %s" +msgstr "Klaida: klavišas %s jau naudojamas %s" + +#: src/KeyDefPage.cxx:203 +#, c-format +msgid "Assigned %s to %s" +msgstr "%s priskirta %s" + +#: src/KeyDefPage.cxx:230 +msgid "Add new key" +msgstr "Pridėti naują klavišą" + +#: src/KeyDefPage.cxx:252 +#, c-format +msgid "Edit keys for %s" +msgstr "Redaguoti %s klavišus" + +#: src/KeyDefPage.cxx:395 +msgid "You have new key bindings" +msgstr "Turite naujus klavišų susiejimus" + +#: src/KeyDefPage.cxx:397 +msgid "Keybindings unchanged." +msgstr "Klavišų sąsajos nepakeistos." + +#: src/KeyDefPage.cxx:407 +msgid "Unable to write configuration" +msgstr "Nepavyksta įrašyti konfigūracijos" + +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 +msgid "Error" +msgstr "Klaida" + +#: src/KeyDefPage.cxx:423 +#, c-format +msgid "Wrote %s" +msgstr "Parašė %s" + +#: src/KeyDefPage.cxx:436 +msgid "===> Apply key bindings " +msgstr "===> Taikyti klavišų susiejimus " + +#: src/KeyDefPage.cxx:438 +msgid "===> Apply & Save key bindings " +msgstr "===> Taikyti ir išsaugoti klavišų susiejimus " + +#: src/KeyDefPage.cxx:475 +msgid "Edit key bindings" +msgstr "Redaguoti klavišų susiejimus" + +#: src/KeyDefPage.cxx:557 +msgid "Note: Did you forget to 'Apply' your changes?" +msgstr "Pastaba: ar pamiršote „Taikyti“ pakeitimus?" + +#: src/KeyDefPage.cxx:607 +msgid "Keys" +msgstr "Klavišai" + +#: src/KeyName.cxx:115 +msgid "Undefined" +msgstr "Neapibrėžta" + +#: src/KeyName.cxx:117 +msgid "Space" +msgstr "Tarpas" + +#: src/KeyName.cxx:119 +msgid "Enter" +msgstr "Enter" + +#: src/KeyName.cxx:121 +msgid "Backspace" +msgstr "Backspace" + +#: src/KeyName.cxx:123 +msgid "Delete" +msgstr "Delete" + +#: src/KeyName.cxx:125 +msgid "Up" +msgstr "Rodyklė aukštyn" + +#: src/KeyName.cxx:127 +msgid "Down" +msgstr "Rodyklė žemyn" + +#: src/KeyName.cxx:129 +msgid "Left" +msgstr "Rodyklė kairėn" + +#: src/KeyName.cxx:131 +msgid "Right" +msgstr "Rodyklė dešinėn" + +#: src/KeyName.cxx:133 +msgid "Home" +msgstr "Home" + +#: src/KeyName.cxx:135 +msgid "End" +msgstr "End" + +#: src/KeyName.cxx:137 +msgid "PageDown" +msgstr "Puslapis žemyn" + +#: src/KeyName.cxx:139 +msgid "PageUp" +msgstr "Puslapis aukštyn" + +#: src/KeyName.cxx:141 +msgid "Tab" +msgstr "Tab" + +#: src/KeyName.cxx:143 +msgid "Shift+Tab" +msgstr "Shift+Tab" + +#: src/KeyName.cxx:145 +msgid "Esc" +msgstr "Esc" + +#: src/KeyName.cxx:147 +msgid "Insert" +msgstr "Insert" + +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 +#, c-format +msgid "Ctrl-%c" +msgstr "Ctrl-%c" + +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 +#, c-format +msgid "Alt-%c" +msgstr "Alt-%c" + +#: src/LibraryPage.cxx:45 +msgid "Artists" +msgstr "Atlikėjai" + +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 +msgid "Albums" +msgstr "Albumai" + +#: src/LibraryPage.cxx:123 +msgid "All" +msgstr "Viskas" + +#: src/LibraryPage.cxx:197 +msgid "Songs" +msgstr "Dainos" + +#: src/LibraryPage.cxx:314 +msgid "Library" +msgstr "Biblioteka" + +#: src/ListWindow.cxx:213 +msgid "Range selection disabled" +msgstr "Diapazono pasirinkimas išjungtas" + +#: src/ListWindow.cxx:216 +msgid "Range selection enabled" +msgstr "Diapazono pasirinkimas įjungtas" + +#. translators: no lyrics were found for the song +#: src/LyricsPage.cxx:253 +msgid "No lyrics" +msgstr "Nėra dainų žodžių" + +#: src/LyricsPage.cxx:270 +#, c-format +msgid "Lyrics timeout occurred after %d seconds" +msgstr "Dainų žodžiams skirtasis laikas baigėsi po %d sekundžių" + +#: src/LyricsPage.cxx:353 src/LyricsPage.cxx:361 src/LyricsPage.cxx:371 +#: src/LyricsPage.cxx:507 +msgid "Lyrics" +msgstr "Dainos žodžiai" + +#. translators: this message is displayed +#. while data is retrieved +#: src/LyricsPage.cxx:356 +msgid "loading..." +msgstr "įkeliama…" + +#: src/LyricsPage.cxx:378 +msgid "Editor not configured" +msgstr "Redaktorius nesukonfigūruotas" + +#: src/LyricsPage.cxx:385 +msgid "Do you really want to start an editor and edit these lyrics?" +msgstr "Ar tikrai norite paleisti redaktorių ir redaguoti šiuos dainos žodžius?" + +#: src/LyricsPage.cxx:403 src/LyricsPage.cxx:427 +msgid "Can't start editor" +msgstr "Nepavyksta paleisti redaktoriaus" + +#: src/LyricsPage.cxx:430 src/LyricsPage.cxx:434 +msgid "Editor exited unexpectedly" +msgstr "Redaktorius išsijungė netikėtai" + +#. lyrics for the song were saved on hard disk +#: src/LyricsPage.cxx:456 +msgid "Lyrics saved" +msgstr "Dainos žodžiai išsaugoti" + +#: src/LyricsPage.cxx:462 +msgid "Lyrics deleted" +msgstr "Dainos žodžiai ištrinti" + +#: src/LyricsPage.cxx:463 +msgid "No saved lyrics" +msgstr "Nėra išsaugotų dainų žodžių" + +#: src/Main.cxx:133 +#, c-format +msgid "Connecting to %s" +msgstr "Jungiamasi prie %s" + +#: src/Main.cxx:149 +#, c-format +msgid "Error: MPD version %d.%d.%d is too old (%s needed)" +msgstr "Klaida: MPD versija %d.%d.%d yra per sena (reikalinga %s)" + +#. To translators: these credits are shown +#. when ncmpc is started with "--version" +#: src/Options.cxx:216 src/Options.cxx:219 +msgid "translator-credits" +msgstr "Gediminas Murauskas" + +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "Perjungta į skaidinį „%s“" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Pavadinimas" + +#: src/OutputsPage.cxx:230 +#, c-format +msgid "Output '%s' enabled" +msgstr "Išvestis „%s“ įjungta" + +#: src/OutputsPage.cxx:241 +#, c-format +msgid "Output '%s' disabled" +msgstr "Išvestis „%s“ išjungta" + +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 +msgid "Outputs" +msgstr "Išvestys" + +#: src/OutputsPage.cxx:383 +msgid "Partition" +msgstr "Skaidinys" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "Sukurti naują skaidinį" + +#: src/player_command.cxx:94 src/QueuePage.cxx:651 +msgid "Shuffled queue" +msgstr "Eilė sumaišyta" + +#: src/player_command.cxx:100 +msgid "Cleared queue" +msgstr "Eilė išvalyta" + +#. get path +#: src/QueuePage.cxx:314 +msgid "Add" +msgstr "Pridėti" + +#: src/QueuePage.cxx:379 src/QueuePage.cxx:697 +msgid "Queue" +msgstr "Eilė" + +#: src/QueuePage.cxx:381 +#, c-format +msgid "Queue on %s" +msgstr "Eilė ties %s" + +#. query the user for a filename +#: src/save_playlist.cxx:86 +msgid "Save queue as" +msgstr "Išsaugoti eilę kaip" + +#: src/save_playlist.cxx:108 +#, c-format +msgid "Replace %s?" +msgstr "Pakeisti %s?" + +#. success +#: src/save_playlist.cxx:129 +#, c-format +msgid "Saved %s" +msgstr "%s išsaugota" + +#: src/screen_client.cxx:41 +msgid "Database update running" +msgstr "Vykdomas duomenų bazės atnaujinimas" + +#: src/screen_client.cxx:48 +#, c-format +msgid "Database update of %s started" +msgstr "Pradėtas duomenų bazės %s atnaujinimas" + +#: src/screen_client.cxx:51 +msgid "Database update started" +msgstr "Duomenų bazės atnaujinimas pradėtas" + +#: src/screen.cxx:158 +msgid "Repeat mode is on" +msgstr "Kartojimo režimas įjungtas" + +#: src/screen.cxx:159 +msgid "Repeat mode is off" +msgstr "Kartojimo režimas išjungtas" + +#: src/screen.cxx:163 +msgid "Random mode is on" +msgstr "Atsitiktinis režimas įjungtas" + +#: src/screen.cxx:164 +msgid "Random mode is off" +msgstr "Atsitiktinis režimas išjungtas" + +#. "single" mode means +#. that MPD will +#. automatically stop +#. after playing one +#. single song +#: src/screen.cxx:173 +msgid "Single mode is on" +msgstr "Vienos dainos rėžimas įjungtas" + +#: src/screen.cxx:174 +msgid "Single mode is off" +msgstr "Vienos dainos rėžimas išjungtas" + +#. "consume" mode means +#. that MPD removes each +#. song which has +#. finished playing +#: src/screen.cxx:182 +msgid "Consume mode is on" +msgstr "Panaikinimo iš eilės po perklausimo rėžimas įjungtas" + +#: src/screen.cxx:183 +msgid "Consume mode is off" +msgstr "Panaikinimo iš eilės po perklausimo rėžimas išjungtas" + +#: src/screen.cxx:186 +#, c-format +msgid "Crossfade %d seconds" +msgstr "Kryžminis perėjimas %d sekundžių" + +#: src/screen.cxx:198 +msgid "Database updated" +msgstr "Duomenų bazė atnaujinta" + +#: src/screen.cxx:248 +msgid "Find mode: Wrapped" +msgstr "Paieškos režimas: ciklinis" + +#: src/screen.cxx:249 +msgid "Find mode: Normal" +msgstr "Radimo režimas: įprastas" + +#: src/screen.cxx:254 +msgid "Auto center mode: On" +msgstr "Automatinio centravimo režimas: įjungtas" + +#: src/screen.cxx:255 +msgid "Auto center mode: Off" +msgstr "Automatinio centravimo režimas: išjungtas" + +#: src/screen_find.cxx:33 +msgid "Find" +msgstr "Rasti" + +#: src/screen_find.cxx:34 +msgid "Find backward" +msgstr "Rasti atgal" + +#: src/screen_find.cxx:35 +msgid "Jump" +msgstr "Peršokti" + +#: src/screen_find.cxx:81 +#, c-format +msgid "Unable to find '%s'" +msgstr "Nepavyko rasti „%s“" + +#: src/screen_utils.cxx:150 +msgid "Password" +msgstr "Slaptažodis" + +#: src/SearchPage.cxx:51 +msgid "artist" +msgstr "atlikėjas" + +#: src/SearchPage.cxx:52 +msgid "album" +msgstr "albumas" + +#: src/SearchPage.cxx:53 +msgid "title" +msgstr "pavadinimas" + +#: src/SearchPage.cxx:54 +msgid "track" +msgstr "kūrinys" + +#: src/SearchPage.cxx:55 +msgid "name" +msgstr "pavadinimas" + +#: src/SearchPage.cxx:56 +msgid "genre" +msgstr "žanras" + +#: src/SearchPage.cxx:57 +msgid "date" +msgstr "data" + +#: src/SearchPage.cxx:58 +msgid "composer" +msgstr "kompozitorius" + +#: src/SearchPage.cxx:59 +msgid "performer" +msgstr "atlikėjas" + +#: src/SearchPage.cxx:60 +msgid "comment" +msgstr "komentaras" + +#: src/SearchPage.cxx:68 +msgid "file" +msgstr "failas" + +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 +msgid "Title" +msgstr "Pavadinimas" + +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 +msgid "Artist" +msgstr "Atlikėjas" + +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 +msgid "Album" +msgstr "Albumas" + +#: src/SearchPage.cxx:93 +msgid "Filename" +msgstr "Failo pavadinimas" + +#: src/SearchPage.cxx:94 +msgid "Artist + Title" +msgstr "Atlikėjas + pavadinimas" + +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "Neatpažinta priesaga" + +#: src/SearchPage.cxx:337 +#, c-format +msgid "Bad search tag %s" +msgstr "Bloga paieškos žyma %s" + +#: src/SearchPage.cxx:351 +#, c-format +msgid "No argument for search tag %s" +msgstr "Nėra paieškos žymos argumento %s" + +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 +msgid "Search" +msgstr "Ieškoti" + +#: src/SearchPage.cxx:509 +#, c-format +msgid "Search mode: %s" +msgstr "Paieškos režimas: %s" + +#: src/SongPage.cxx:65 +msgid "Length" +msgstr "Ilgis" + +#: src/SongPage.cxx:66 +msgid "Position" +msgstr "Pozicija" + +#: src/SongPage.cxx:67 +msgid "Composer" +msgstr "Kompozitorius" + +#: src/SongPage.cxx:68 +msgid "Performer" +msgstr "Atlikėjas" + +#: src/SongPage.cxx:70 +msgid "Disc" +msgstr "Diskas" + +#: src/SongPage.cxx:71 +msgid "Track" +msgstr "Kūrinys" + +#: src/SongPage.cxx:72 +msgid "Date" +msgstr "Data" + +#: src/SongPage.cxx:73 +msgid "Genre" +msgstr "Žanras" + +#: src/SongPage.cxx:74 +msgid "Comment" +msgstr "Komentaras" + +#: src/SongPage.cxx:75 +msgid "Path" +msgstr "Kelias" + +#: src/SongPage.cxx:76 +msgid "Bitrate" +msgstr "Bitų dažnis" + +#: src/SongPage.cxx:77 +msgid "Format" +msgstr "Formatas" + +#: src/SongPage.cxx:94 +msgid "Number of artists" +msgstr "Atlikėjų skaičius" + +#: src/SongPage.cxx:95 +msgid "Number of albums" +msgstr "Albumų skaičius" + +#: src/SongPage.cxx:96 +msgid "Number of songs" +msgstr "Dainų skaičius" + +#: src/SongPage.cxx:97 +msgid "Uptime" +msgstr "Veikimo laikas" + +#: src/SongPage.cxx:98 +msgid "Most recent db update" +msgstr "Vėliausias db atnaujinimas" + +#: src/SongPage.cxx:99 +msgid "Playtime" +msgstr "Grojimo laikas" + +#: src/SongPage.cxx:100 +msgid "DB playtime" +msgstr "DB grojimo laikas" + +#: src/SongPage.cxx:205 +msgid "Song viewer" +msgstr "Dainų peržiūra" + +#: src/SongPage.cxx:371 +msgid "MPD statistics" +msgstr "MPD statistika" + +#: src/SongPage.cxx:457 +msgid "Selected song" +msgstr "Pasirinkta daina" + +#: src/SongPage.cxx:467 +msgid "Currently playing song" +msgstr "Šiuo metu grojama daina" + +#: src/SongPage.cxx:472 +#, c-format +msgid "%d kbps" +msgstr "%d kbps" + +#: src/SongPage.cxx:556 +msgid "Song" +msgstr "Daina" + +#: src/StatusBar.cxx:165 +msgid "Playing:" +msgstr "Grojama:" + +#: src/StatusBar.cxx:169 +msgid "Paused" +msgstr "Pristabdyta" + +#: src/Styles.cxx:252 src/Styles.cxx:313 +msgid "Unknown color" +msgstr "Nežinoma spalva" + +#: src/Styles.cxx:323 +msgid "Unknown color field" +msgstr "Nežinomas spalvos laukas" + +#: src/Styles.cxx:356 +msgid "Terminal lacks color capabilities" +msgstr "Terminalas neturi spalvinimo galimybių" + +#: src/TagListPage.cxx:71 +msgid "All tracks" +msgstr "Visi kūriniai" + +#: src/time_format.cxx:44 +msgid "year" +msgstr "metai" + +#: src/time_format.cxx:46 +msgid "years" +msgstr "m." + +#: src/time_format.cxx:54 +msgid "week" +msgstr "savaitė" + +#: src/time_format.cxx:57 +msgid "weeks" +msgstr "sav." + +#: src/time_format.cxx:65 +msgid "day" +msgstr "diena" + +#: src/time_format.cxx:68 +msgid "days" +msgstr "d." + +#: src/TitleBar.cxx:101 +msgid "Volume n/a" +msgstr "Garsas n/a" + +#: src/TitleBar.cxx:103 +#, c-format +msgid "Volume %d%%" +msgstr "Garsas %d%%"
View file
ncmpc-0.36.tar.xz/po/nb.po -> ncmpc-0.47.tar.xz/po/nb.po
Changed
@@ -7,8 +7,8 @@ msgstr "" "Project-Id-Version: ncmpc 0.11.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2019-09-09 12:25+0000\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2020-09-08 16:36+0000\n" "Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n" "Language-Team: Norwegian Bokmål <https://hosted.weblate.org/projects/ncmpc/" "translations/nb_NO/>\n" @@ -17,10 +17,10 @@ "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 3.9-dev\n" +"X-Generator: Weblate 4.3-dev\n" "X-Launchpad-Export-Date: 2010-07-21 05:36+0000\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "%s-tasten satt til %s og %s" @@ -37,313 +37,313 @@ msgid "Message could not be sent" msgstr "Meldingen kunne ikke sendes" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "Tastaturkonfigurasjon" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Avslutt" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "Flytt markør opp" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "Flytt markør ned" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "Flytt peker til toppen av skjermen" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "Flytt pekeren til midten av skjermen" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "Flytt pekeren til bunnen av skjermen" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "Flytt pekeren til toppen av listen" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "Flytt pekeren til bunnen av listen" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "Markøren en side opp" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "Markøren en side ned" -#: src/Command.cxx:54 +#: src/Command.cxx:55 #, fuzzy msgid "Range selection" msgstr "Områdevalg" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "Rull nedover én linje" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "Rull oppover én linje" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "Rull oppover en halv skjerm" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "Rull nedover en halv skjerm" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "Velg sangen som spilles" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "Hjelp" -#: src/Command.cxx:71 src/HelpPage.cxx:140 +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" msgstr "Køskjerm" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "Filer" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "Spill/Velg mappe" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Pause" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "Stopp" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "Beskjær" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "Neste" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Forrige" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "Blafre forover" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "Blafre bakover" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "Øk volumet" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "Demp volumet" -#: src/Command.cxx:98 +#: src/Command.cxx:99 #, fuzzy msgid "Select/deselect song in queue" msgstr "Velg/fravelg i spillelisten" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Velg alle i listen" -#: src/Command.cxx:102 +#: src/Command.cxx:103 msgid "Delete song from queue" msgstr "Fjern sang fra kø" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" msgstr "Stokk om kø" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" msgstr "Tøm kø" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "Repeat På/Av" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "Random På/Av" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "Veksle enkelt modus" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "Veksle konsumentmodus" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "Crossfade På/Av" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "Oppdater databasen" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" msgstr "Lagre kø" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 #, fuzzy msgid "Append song to queue" msgstr "Legg sang til spillelisten" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "Gå til rotmappe" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "Gå ett nivå opp" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "Finn sang i filutforsker" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "Flytt opp" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "Flytt ned" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "Oppdater skjermbilde" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "Endre søkeinnstillinger" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "Automatisk sentrering på/av" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "Neste skjerm" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "Forrige skjerm" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "Bytt til nyligste skjerm" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "Søk fremover" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "Søk neste (fremover)" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "Søk bakover" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "Søk neste (bakover)" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "Gå til" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" msgstr "Biblioteksside" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Database søk" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "Endre søkemodus" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "Vis valgt og sang som spilles nå" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "Tekstskjerm" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "Avbryt handling" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "Oppdater sangtekster" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "Rediger gjeldende element" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 #, fuzzy msgid "Outputs screen" msgstr "Utganger" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" msgstr "Sludreskjerm" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "Ord forventet" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "Malformert hurtigtastdefinisjon" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "Uferdig hurtigtastkonfigurasjon" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "Ukjent kommando" @@ -355,29 +355,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "Ugyldig tidsvisningstype" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "Mangler '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "Ugyldig fargenavn" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "Uferdig fargedefinisjon" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "Ugyldig tall" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "Malformert fargedefinisjon" @@ -386,24 +386,24 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "Ukjent skjermnavn" -#: src/ConfigParser.cxx:403 +#: src/ConfigParser.cxx:388 #, fuzzy msgid "Unknown MPD tag" msgstr "Ukjent kommando" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "Ugyldig søkemodus" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "Ukjent søkemodus" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "Ukjent konfiurasjonsparameter" @@ -414,140 +414,140 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "Kan ikke slette dette elementet" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, c-format msgid "Delete playlist %s?" msgstr "Slett spillelisten %s?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Avbrutt" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "Spillelisten slettet" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Filer" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, fuzzy, c-format msgid "Loading playlist '%s'" msgstr "Henter spilleliste \"%s...\"" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 #, c-format msgid "Adding '%s' to queue" msgstr "Legger til \"%s\" i spillelisten" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Navigasjon" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Global" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Start/spill markert" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "Sentrer" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Velg bibliotek/Legg til spillisten og spill sang" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Slett spilleliste" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 #, fuzzy msgid "New search" msgstr "Søk" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Legg til spillelisten og spill" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "Vis tekster" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "(Gjen)innlast tekster" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Avbryt henting" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "Last ned tekster for sangens som spilles nå" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" msgstr "Legg til eller rediger tekster" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "Lagre tekster" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" msgstr "Slett lagrede tekster" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Skru på/av utgang" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" msgstr "Skriv en melding" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Tastedefinisjonsskjerm" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Rediger tastedefinisjoner for valgt kommando" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "Fjern valgt tastedefinisjon" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 #, fuzzy msgid "Add a keydef" msgstr "Legg til ny tast" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Gå opp et nivå" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Legg til og lagre endringer" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Hjelp" @@ -559,158 +559,160 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Slettet" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "Ny tast for %s: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 #, fuzzy msgid "Ctrl-Space can't be used" msgstr "Ctrl+mellomrom kan ikke brukes" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Tasten %s brukes allerede for %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "Satte %s = %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Legg til ny tast" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "Endre taster for '%s'" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "Du har nye tastatursnarveier" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "Tastatursnarveier uforandret." -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 #, fuzzy msgid "Unable to write configuration" msgstr "Kunne ikke lagre oppsett" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "Feil" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "Skrev %s" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "==> Bruk snarveier " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "==> Bruk og Lagre snarveier " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "Endre tast" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "OBS! Du glemte vel ikke å legge til de nye endringene?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "Taster" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "Ikke definert" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Mellomrom" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Enter" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "Tilbaketast" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Del" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Opp" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Ned" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "Venstrepil" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "Høyrepil" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Hjem" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "Slutt" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 #, fuzzy msgid "PageDown" msgstr "Page Down" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 #, fuzzy msgid "PageUp" msgstr "Page Up" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Shift+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 #, fuzzy msgid "Esc" msgstr "Escape" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Ins" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "Ctrl-%c" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "Alt-%c" @@ -720,7 +722,7 @@ msgid "Artists" msgstr "Artist" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 msgid "Albums" msgstr "Album" @@ -728,12 +730,12 @@ msgid "All" msgstr "Alle" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 #, fuzzy msgid "Songs" msgstr "Sang" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" msgstr "Bibliotek" @@ -796,12 +798,12 @@ msgid "No saved lyrics" msgstr "Ingen lagrede tekster" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, c-format msgid "Connecting to %s" msgstr "Kobler til %s" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, fuzzy, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "Feil: MPD-versjon %d.%d.%d er for gammel - oppgrader til versjon %s" @@ -811,27 +813,46 @@ #: src/Options.cxx:216 src/Options.cxx:219 msgid "translator-credits" msgstr "" -"Launchpad Contributions:\n" -" Espen Jones https://launchpad.net/~epqr\n" -" Jon Bergli Heier https://launchpad.net/~snakebite-jvnv\n" -" Mathias Bøhn Grytemark https://launchpad.net/~mboehn\n" -" Ole R. Thorsen https://launchpad.net/~ole-rth\n" -" Niels Anker https://launchpad.net/~nanker" - -#: src/OutputsPage.cxx:87 +"Allan Nordhøy\n" +"Tidligere:\n" +" Espen Jones\n" +" Jon Bergli Heier\n" +" Mathias Bøhn Grytemark\n" +" Ole R. Thorsen\n" +" Niels Anker" + +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "Byttet til partisjon «%s»" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Navn" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "Utgang \"%s\" påslått" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "Utgang \"%s\" avslått" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Utganger" +#: src/OutputsPage.cxx:383 +#, fuzzy +msgid "Partition" +msgstr "Posisjon" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "Opprett ny partisjon" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" msgstr "Stokket om kø" @@ -972,86 +993,91 @@ msgid "Password" msgstr "Passord" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "artist" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "album" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "tittel" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "spor" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "navn" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "sjanger" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "dato" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "komponist" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "utøver" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "kommentar" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "fil" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Tittel" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Artist" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Album" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Filnavn" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Artist + tittel" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +#, fuzzy +msgid "Unrecognized suffix" +msgstr "Ugjenkjent filendelse" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Feilaktig søkeetikett %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "Inget argument for søkeetikett %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Søk" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Søk etter: %s" @@ -1069,99 +1095,100 @@ msgstr "Komponist" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Navn" +#, fuzzy +msgid "Performer" +msgstr "utøver" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Plate" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Spor" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Dato" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Sjanger" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Kommentar" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Sti" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Bitrate" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" msgstr "Format" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Antall artister" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Antall albumer" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Antall sanger" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "Oppetid" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "Nyeste db oppdatering" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "Spilletid" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "DB spilletid" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "Sangframviser" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "MPD statestikk" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "Valg sang" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "Sang som spilles nå" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d kbps" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" msgstr "Sang" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Spiller:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "Pause"
View file
ncmpc-0.36.tar.xz/po/ncmpc.pot -> ncmpc-0.47.tar.xz/po/ncmpc.pot
Changed
@@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,7 +17,7 @@ "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "" @@ -34,309 +34,309 @@ msgid "Message could not be sent" msgstr "" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "" -#: src/Command.cxx:71 src/HelpPage.cxx:140 +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" msgstr "" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "" -#: src/Command.cxx:98 +#: src/Command.cxx:99 msgid "Select/deselect song in queue" msgstr "" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "" -#: src/Command.cxx:102 +#: src/Command.cxx:103 msgid "Delete song from queue" msgstr "" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" msgstr "" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" msgstr "" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" msgstr "" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" msgstr "" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" msgstr "" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" msgstr "" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "" @@ -348,29 +348,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "" @@ -379,23 +379,23 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "" -#: src/ConfigParser.cxx:403 +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" msgstr "" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "" @@ -406,138 +406,138 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, c-format msgid "Delete playlist %s?" msgstr "" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, c-format msgid "Loading playlist '%s'" msgstr "" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 #, c-format msgid "Adding '%s' to queue" msgstr "" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 msgid "New search" msgstr "" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" msgstr "" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" msgstr "" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" msgstr "" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 msgid "Add a keydef" msgstr "" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "" @@ -549,153 +549,155 @@ msgid "n" msgstr "" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "" -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" msgstr "" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "" -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" msgstr "" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "" -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "" -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "" @@ -704,7 +706,7 @@ msgid "Artists" msgstr "" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 msgid "Albums" msgstr "" @@ -712,11 +714,11 @@ msgid "All" msgstr "" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" msgstr "" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" msgstr "" @@ -778,12 +780,12 @@ msgid "No saved lyrics" msgstr "" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, c-format msgid "Connecting to %s" msgstr "" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "" @@ -794,20 +796,37 @@ msgid "translator-credits" msgstr "" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "" +#: src/OutputsPage.cxx:383 +msgid "Partition" +msgstr "" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" msgstr "" @@ -946,86 +965,90 @@ msgid "Password" msgstr "" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "" @@ -1043,99 +1066,99 @@ msgstr "" #: src/SongPage.cxx:68 -msgid "Name" +msgid "Performer" msgstr "" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" msgstr "" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" msgstr "" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr ""
View file
ncmpc-0.36.tar.xz/po/nl.po -> ncmpc-0.47.tar.xz/po/nl.po
Changed
@@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" "PO-Revision-Date: 2010-02-24 11:17+0000\n" "Last-Translator: Tom Postma <tom-postma@hetnet.nl>\n" "Language-Team: Dutch <nl@li.org>\n" @@ -18,7 +18,7 @@ "X-Launchpad-Export-Date: 2010-04-05 17:16+0000\n" "X-Generator: Launchpad (build Unknown)\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "" @@ -35,309 +35,309 @@ msgid "Message could not be sent" msgstr "" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "" -#: src/Command.cxx:71 src/HelpPage.cxx:140 +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" msgstr "" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "" -#: src/Command.cxx:98 +#: src/Command.cxx:99 msgid "Select/deselect song in queue" msgstr "" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "" -#: src/Command.cxx:102 +#: src/Command.cxx:103 msgid "Delete song from queue" msgstr "" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" msgstr "" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" msgstr "" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" msgstr "" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" msgstr "" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" msgstr "" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" msgstr "" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "" @@ -349,29 +349,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "" @@ -380,23 +380,23 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "" -#: src/ConfigParser.cxx:403 +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" msgstr "" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "" @@ -407,140 +407,140 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, fuzzy, c-format msgid "Delete playlist %s?" msgstr "Afspeellijst verwijderen" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Afgebroken" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Blader" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, fuzzy, c-format msgid "Loading playlist '%s'" msgstr "Laden afspeellijst %s..." -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 #, fuzzy, c-format msgid "Adding '%s' to queue" msgstr "Toevoegen '%s' aan afspeellijst" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Beweging" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Algemeen" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Afspeellijst verwijderen" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 #, fuzzy msgid "New search" msgstr "Zoeken" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" msgstr "" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 #, fuzzy msgid "Delete saved lyrics" msgstr "Afspeellijst verwijderen" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" msgstr "" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 msgid "Add a keydef" msgstr "" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Documentatie" @@ -552,153 +552,155 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Verwijderd" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "" -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" msgstr "" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "" -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" msgstr "" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "" -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "" -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "" @@ -708,7 +710,7 @@ msgid "Artists" msgstr "Artiest" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 #, fuzzy msgid "Albums" msgstr "Album" @@ -717,11 +719,11 @@ msgid "All" msgstr "" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" msgstr "" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" msgstr "" @@ -784,12 +786,12 @@ msgid "No saved lyrics" msgstr "" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, fuzzy, c-format msgid "Connecting to %s" msgstr "Verbonden met %s" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "" @@ -803,20 +805,38 @@ " Hipska https://launchpad.net/~hipska\n" " Tom Postma https://launchpad.net/~bluegen89" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Naam" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Uitvoerapparaten" +#: src/OutputsPage.cxx:383 +#, fuzzy +msgid "Partition" +msgstr "artiest" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" msgstr "" @@ -956,86 +976,90 @@ msgid "Password" msgstr "Wachtwoord" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "artiest" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "album" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "titel" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "nummer" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "naam" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "genre" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "datum" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "componist" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "uitvoerder" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "opmerking" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "bestand" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Titel" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Artiest" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Album" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Bestandsnaam" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Artiest + Titel" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Zoeken" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "" @@ -1053,99 +1077,100 @@ msgstr "Componist" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Naam" +#, fuzzy +msgid "Performer" +msgstr "uitvoerder" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Schijf" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Nummer" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Datum" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Genre" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Opmerking" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Locatie" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Bitsnelheid" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" msgstr "" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Aantal artiesten" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Aantal albums" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Aantal nummers" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d kbps" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" msgstr "" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Speelt:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr ""
View file
ncmpc-0.36.tar.xz/po/pl.po -> ncmpc-0.47.tar.xz/po/pl.po
Changed
@@ -8,9 +8,9 @@ msgstr "" "Project-Id-Version: ncmpc 0.19\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2018-10-05 17:33+0000\n" -"Last-Translator: Mirosław Borodeńko <myros@outlook.com>\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2021-08-11 22:34+0000\n" +"Last-Translator: Matthaiks <kitynska@gmail.com>\n" "Language-Team: Polish <https://hosted.weblate.org/projects/ncmpc/" "translations/pl/>\n" "Language: pl\n" @@ -19,9 +19,9 @@ "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 3.2\n" +"X-Generator: Weblate 4.8-dev\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "Klawisz %s przypisany do %s oraz %s" @@ -38,309 +38,309 @@ msgid "Message could not be sent" msgstr "Wiadomość nie mogła zostać wysłana" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "Ekran konfiguracji klawiszy" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Wyjdź" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "Przesuń kursor w górę" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "Przesuń kursor w dół" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "Przesuń kursor na początek ekranu" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "Przesuń kursor na środek ekranu" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "Przesuń kursor na koniec ekranu" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "Przesuń kursor na początek listy" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "Przesuń kursor na koniec listy" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "Przesuń o stronę do góry" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "Przesuń o stronę w dół" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "Wybór zakresu" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "Przesuń o linijkę w dół" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "Przesuń o linijkę do góry" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "Przesuń o pół ekranu do góry" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "Przesuń o pół ekranu w dół" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "Zaznacz obecnie odtwarzaną piosenkę" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "Ekran pomocy" -#: src/Command.cxx:71 src/HelpPage.cxx:140 +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" msgstr "Ekran listy odtwarzania" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "Ekran przeglądania" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "Odtwarzaj/Przejdź do katalogu" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Wstrzymanie" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "Zatrzymanie" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "Przycięcie" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "Następna ścieżka" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Poprzednia ścieżka" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "Przewiń naprzód" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "Przewiń wstecz" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "Zgłośnij" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "Przycisz" -#: src/Command.cxx:98 +#: src/Command.cxx:99 msgid "Select/deselect song in queue" msgstr "Zaznacz/odznacz utwór na liście odtwarzania" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Zaznacz wszystkie wyświetlone pozycje" -#: src/Command.cxx:102 +#: src/Command.cxx:103 msgid "Delete song from queue" msgstr "Usuń utwór z listy odtwarzania" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" msgstr "Przetasuj listę odtwarzania" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" msgstr "Wyczyść listę odtwarzania" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "Przełącz tryb powtarzania" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "Przełącz tryb losowy" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "Przełącz tryb pojedynczej piosenki" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "Przełącz tryb pożerania" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "Przełącz tryb przenikania" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "Rozpocznij aktualizacje bazy piosenek" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" msgstr "Zapisz listę odtwarzania" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" msgstr "Dodaj utwór do listy odtwarzania" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "Przejdź do katalogu głównego" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "Przejdź do nadrzędnego katalogu" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "Zlokalizuj piosenkę w przeglądarce" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "Przesuń element w górę" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "Przesuń element w dół" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "Odśwież ekran" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "Przełącz tryb wyszukiwania" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "Przełącz tryb automatycznego centrowania" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "Następny ekran" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "Poprzedni ekran" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "Przełącz do najnowszego ekranu" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "Wyszukaj naprzód" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "Znajdź następne" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "Wyszukaj wstecz" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "Znajdź poprzednie" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "Skocz do" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" -msgstr "" +msgstr "Strona biblioteki" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Ekran wyszukiwania" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "Zmień tryb wyszukiwania" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "Zobacz zaznaczone i obecnie odtwarzaną piosenkę" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "Ekran z tekstem piosenki" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "Przerwij zadanie" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "Zaktualizuj tekst utworu" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "Edytuj bieżący element" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "Ekran z wyjściami dźwiękowymi" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" msgstr "Ekran rozmowy" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "Oczekiwane słowo" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "Nieprawidłowa definicja skrótu klawiszowego" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "Niekompletna konfiguracja skrótów klawiszowych" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "Nieznane polecenie" @@ -352,29 +352,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "Nieprawidłowy tryb wyświetlania czasu" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "Brakujący '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "Zła nazwa koloru" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "Niekompletna definicja koloru" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "Nieprawidłowy numer" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "Nieprawidłowa definicja koloru" @@ -383,24 +383,23 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "Nieznana nazwa ekranu" -#: src/ConfigParser.cxx:403 -#, fuzzy +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" -msgstr "Nieznane polecenie" +msgstr "Nieznany znacznik MPD" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "Nieprawidłowy tryb wyszukiwania" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "Nieznany tryb wyszukiwania" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "Nieznany parametr konfiguracyjny" @@ -411,138 +410,138 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "Usunięcie tego elementu nie jest możliwe" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, c-format msgid "Delete playlist %s?" msgstr "Czy usunąć listę odtwarzania %s?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Anulowano" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "Lista odtwarzania usunięta" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Przeglądaj" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, c-format msgid "Loading playlist '%s'" msgstr "Ładowanie listy odtwarzania %s" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 #, c-format msgid "Adding '%s' to queue" msgstr "Dodawanie '%s' do listy odtwarzania" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Poruszanie" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Globalne" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Odtwarzaj" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "Wycentruj" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Podaj katalog/Wybierz i odtwarzaj piosenkę" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Usuń listę odtwarzania" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 msgid "New search" msgstr "Nowe wyszukiwanie" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Wybierz i odtwarzaj" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "Zobacz teskt piosenki" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "(Prze)ładuj tekst" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Przerwij pobieranie" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" -msgstr "Sćiagnij słowa dla obecnie odtwarzanej piosenki" +msgstr "Pobierz słowa dla obecnie odtwarzanej piosenki" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" -msgstr "Dodaj lub edytuj treść utworu" +msgstr "Dodaj lub zmień treść utworu" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" -msgstr "Zapisz tekst piosenku" +msgstr "Zapisz tekst utworu" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" -msgstr "Usuń zapisany tekst piosenki" +msgstr "Usuń zapisany tekst utworu" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Włącz/wyłącz wyjście" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" msgstr "Napisz wiadomość" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Ekran definicji klawiszy" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Edytuj definicje klawiszy dla wybranego polecenia" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "Usuń wybraną definicję klawiszy" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 msgid "Add a keydef" msgstr "Dodaj definicję klawisza" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Idź poziom wyżej" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Zastosuj i zapisz zmiany" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Pomoc" @@ -554,186 +553,186 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Usunięto" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "Podaj nowy skrót dla %s: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" msgstr "Ctrl-Space nie może być użyte" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Błąd: klawisz %s już jest używany do %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "Przypisano klawisz %s do %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Dodaj nowy klawisz" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "Edytuj klawisze dla %s" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "Masz nowe wiązania klawiszy" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "Wiązania klawiszy niezmienione." -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" msgstr "Nie mogę zapisać konfiguracji" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "Błąd" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "Zapisano %s" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "===> Zastosuj wiązania klawiszy " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "===> Zastosuj i Zapisz wiązania klawiszy " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "Edytuj wiązania klawiszy" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" -msgstr "Informacja: Zapomniałeś 'Zastosować' swoje zmiany?" +msgstr "Informacja: Zapomniałeś „Zastosować” swoje zmiany?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "Klawisze" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "Niezdefiniowany" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Spacja" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Enter" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "Backspace" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Delete" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Góra" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Dół" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "Lewo" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "Prawo" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Home" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "End" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "PageDown" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "PageUp" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Shift+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Insert" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "Ctrl-%c" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "Alt-%c" #: src/LibraryPage.cxx:45 -#, fuzzy msgid "Artists" -msgstr "Artysta" +msgstr "Artyści" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 msgid "Albums" msgstr "Albumy" #: src/LibraryPage.cxx:123 msgid "All" -msgstr "" +msgstr "Wszystko" -#: src/LibraryPage.cxx:199 -#, fuzzy +#: src/LibraryPage.cxx:197 msgid "Songs" -msgstr "Utwór" +msgstr "Utwory" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" -msgstr "" +msgstr "Biblioteka" #: src/ListWindow.cxx:213 msgid "Range selection disabled" -msgstr "Wielozaznaczanie wyłączone" +msgstr "Zaznaczanie zakresów wyłączone" #: src/ListWindow.cxx:216 msgid "Range selection enabled" -msgstr "Wielozaznaczanie włączone" +msgstr "Zaznaczanie zakresów włączone" #. translators: no lyrics were found for the song #: src/LyricsPage.cxx:253 @@ -775,22 +774,22 @@ #. lyrics for the song were saved on hard disk #: src/LyricsPage.cxx:456 msgid "Lyrics saved" -msgstr "Tekst piosenki zapisany" +msgstr "Tekst utworu zapisany" #: src/LyricsPage.cxx:462 msgid "Lyrics deleted" -msgstr "Teskt piosenki usunięty" +msgstr "Tekst utworu usunięty" #: src/LyricsPage.cxx:463 msgid "No saved lyrics" -msgstr "Brak zapisanego tesktu piosenki" +msgstr "Brak zapisanego tekstu utworu" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, c-format msgid "Connecting to %s" msgstr "Łączenie z %s" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "Błąd: MPD w wersji %d.%d.%d jest za stary (potrzebny jest %s)" @@ -801,20 +800,37 @@ msgid "translator-credits" msgstr "" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "Przełączono na sekcję '%s'" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Nazwa" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" -msgstr "Wyjście '%s' włączone" +msgstr "Wyjście „%s” włączone" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" -msgstr "Wyjście '%s' wyłączone" +msgstr "Wyjście „%s” wyłączone" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Wyjścia" +#: src/OutputsPage.cxx:383 +msgid "Partition" +msgstr "Sekcja" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "Utwórz nową sekcję" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" msgstr "Przetasowano listę odtwarzania" @@ -889,11 +905,11 @@ #. single song #: src/screen.cxx:173 msgid "Single mode is on" -msgstr "Tryb pojedynczej piosenki jest włączony" +msgstr "Tryb pojedynczego utworu jest włączony" #: src/screen.cxx:174 msgid "Single mode is off" -msgstr "Tryb pojedynczej piosenki jest wyłączony" +msgstr "Tryb pojedynczego utworu jest wyłączony" #. "consume" mode means #. that MPD removes each @@ -953,86 +969,90 @@ msgid "Password" msgstr "Hasło" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "artysta" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "album" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" -msgstr "tutuł" +msgstr "tytuł" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" -msgstr "ściezka" +msgstr "ścieżka" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "nazwa" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "rodzaj" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "data" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "kompozytor" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "wykonawca" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "komentarz" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "plik" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Tytuł" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Artysta" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Album" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Nazwa pliku" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Artysta + Tytuł" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "Nierozpoznany sufiks" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Nieprawidłowy wyszukiwany znacznik %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "Brak argumentu przy wyszukiwaniu znacznika %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Znajdź" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Tryb szukania: %s" @@ -1050,99 +1070,99 @@ msgstr "Kompozytor" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Nazwa" +msgid "Performer" +msgstr "Wykonawca" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Dysk" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Ścieżka" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Data" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Rodzaj" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Komentarz" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Ścieżka" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Przepływność bitowa" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" msgstr "Format" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Ilość artystów" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Ilość albumów" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Ilość piosenek" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" -msgstr "Czas uruchomienia" +msgstr "Czas od uruchomienia" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "Ostatnia aktualizacja bazy" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "Czas odtwarzania" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "czas odtwarzania w bazie" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" -msgstr "Przeglądarka piosenek" +msgstr "Przeglądarka utworów" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "statystyki MPD" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" -msgstr "Wybrana piosenka" +msgstr "Wybrany utwór" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" -msgstr "Obecnie odtwarzana piosenka" +msgstr "Obecnie odtwarzany utwór" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d kbps" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" msgstr "Utwór" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Odtwarzanie:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "Pauza" @@ -1193,7 +1213,7 @@ #: src/TitleBar.cxx:103 #, c-format msgid "Volume %d%%" -msgstr "Głóśność %d%%" +msgstr "Głośność %d%%" #~ msgid "Artist screen" #~ msgstr "Ekran artysty"
View file
ncmpc-0.47.tar.xz/po/pt.po
Added
@@ -0,0 +1,1199 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the ncmpc package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: ncmpc\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-10-08 17:59+0200\n" +"PO-Revision-Date: 2021-05-10 16:33+0000\n" +"Last-Translator: ssantos <ssantos@web.de>\n" +"Language-Team: Portuguese <https://hosted.weblate.org/projects/ncmpc/" +"translations/pt/>\n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.7-dev\n" + +#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#, c-format +msgid "Key %s assigned to %s and %s" +msgstr "Tecla %s definida para %s e %s" + +#: src/ChatPage.cxx:64 src/ChatPage.cxx:182 +msgid "Chat" +msgstr "Xat" + +#: src/ChatPage.cxx:163 +msgid "Your message" +msgstr "Sua mensagem" + +#: src/ChatPage.cxx:172 +msgid "Message could not be sent" +msgstr "Mensagem não pode ser enviada" + +#: src/Command.cxx:29 +msgid "Key configuration screen" +msgstr "Ecrã de configuração de teclas" + +#: src/Command.cxx:32 +msgid "Quit" +msgstr "Sair" + +#: src/Command.cxx:36 +msgid "Move cursor up" +msgstr "Mover cursor para cima" + +#: src/Command.cxx:38 +msgid "Move cursor down" +msgstr "Mover cursor para baixo" + +#: src/Command.cxx:40 +msgid "Move cursor to the top of screen" +msgstr "Mover cursor para o topo do ecrã" + +#: src/Command.cxx:42 +msgid "Move cursor to the middle of screen" +msgstr "Mover cursor para o meio do ecrã" + +#: src/Command.cxx:44 +msgid "Move cursor to the bottom of screen" +msgstr "Mover cursor para o final do ecrã" + +#: src/Command.cxx:46 +msgid "Move cursor to the top of the list" +msgstr "Mover cursor para o topo da lista" + +#: src/Command.cxx:48 +msgid "Move cursor to the bottom of the list" +msgstr "Mover cursor para o final da lista" + +#: src/Command.cxx:50 +msgid "Page up" +msgstr "Sobe uma página" + +#: src/Command.cxx:52 +msgid "Page down" +msgstr "Desce uma página" + +#: src/Command.cxx:54 +msgid "Range selection" +msgstr "Seleção de Intervalo" + +#: src/Command.cxx:56 +msgid "Scroll down one line" +msgstr "Descer uma linha" + +#: src/Command.cxx:58 +msgid "Scroll up one line" +msgstr "Subir uma linha" + +#: src/Command.cxx:60 +msgid "Scroll up half a screen" +msgstr "Subir meio ecrã" + +#: src/Command.cxx:62 +msgid "Scroll down half a screen" +msgstr "Descer meio ecrã" + +#: src/Command.cxx:64 +msgid "Select currently playing song" +msgstr "Selecionar música atualmente em reprodução" + +#: src/Command.cxx:69 +msgid "Help screen" +msgstr "Ecrã de Ajuda" + +#: src/Command.cxx:71 src/HelpPage.cxx:140 +msgid "Queue screen" +msgstr "Ecrã de fila" + +#: src/Command.cxx:73 src/HelpPage.cxx:155 +msgid "Browse screen" +msgstr "Ecrã de Navegação" + +#: src/Command.cxx:78 +msgid "Play/Enter directory" +msgstr "Reproduzir/Adentrar diretório" + +#: src/Command.cxx:80 +msgid "Pause" +msgstr "Pause" + +#: src/Command.cxx:82 +msgid "Stop" +msgstr "Parar" + +#: src/Command.cxx:84 +msgid "Crop" +msgstr "Cortar" + +#: src/Command.cxx:86 +msgid "Next track" +msgstr "Próxima faixa" + +#: src/Command.cxx:88 +msgid "Previous track" +msgstr "Faixa anterior" + +#: src/Command.cxx:90 +msgid "Seek forward" +msgstr "Correr para frente" + +#: src/Command.cxx:92 +msgid "Seek backward" +msgstr "Correr para trás" + +#: src/Command.cxx:94 +msgid "Increase volume" +msgstr "Aumentar volume" + +#: src/Command.cxx:96 +msgid "Decrease volume" +msgstr "Abaixar volume" + +#: src/Command.cxx:98 +msgid "Select/deselect song in queue" +msgstr "Selecionar/De-selecionar musica na Lista de Reprodução" + +#: src/Command.cxx:100 +msgid "Select all listed items" +msgstr "Selecionar todos os itens listados" + +#: src/Command.cxx:102 +msgid "Delete song from queue" +msgstr "Apagar música da lista" + +#: src/Command.cxx:104 +msgid "Shuffle queue" +msgstr "Aleatório na fila" + +#: src/Command.cxx:106 +msgid "Clear queue" +msgstr "Limpar fila" + +#: src/Command.cxx:108 +msgid "Toggle repeat mode" +msgstr "Liga/Desliga modo de repetição" + +#: src/Command.cxx:110 +msgid "Toggle random mode" +msgstr "Liga/Desliga modo aleatório" + +#: src/Command.cxx:112 +msgid "Toggle single mode" +msgstr "Liga/Desliga modo de única reprodução" + +#: src/Command.cxx:114 +msgid "Toggle consume mode" +msgstr "Alterar modo de deleção de música reproduzida" + +#: src/Command.cxx:116 +msgid "Toggle crossfade mode" +msgstr "Alterar inter-mixagem" + +#: src/Command.cxx:118 +msgid "Start a music database update" +msgstr "Iniciar a atualização do banco de dados de músicas" + +#: src/Command.cxx:120 +msgid "Save queue" +msgstr "Gravar fila" + +#: src/Command.cxx:122 src/HelpPage.cxx:174 +msgid "Append song to queue" +msgstr "Adicionar trilha à lista de reprodução" + +#: src/Command.cxx:125 +msgid "Go to root directory" +msgstr "Ir para raiz" + +#: src/Command.cxx:127 +msgid "Go to parent directory" +msgstr "Ir para diretório pai" + +#: src/Command.cxx:130 +msgid "Locate song in browser" +msgstr "Localizar musica no navegador" + +#: src/Command.cxx:134 +msgid "Move item up" +msgstr "Mover item para cima" + +#: src/Command.cxx:136 +msgid "Move item down" +msgstr "Mover item para baixo" + +#: src/Command.cxx:138 +msgid "Refresh screen" +msgstr "Redesenhar ecrã" + +#. translators: toggle between wrapping and non-wrapping +#. search +#: src/Command.cxx:145 +msgid "Toggle find mode" +msgstr "Liga/Desliga modo de procura" + +#. translators: the auto center mode always centers the song +#. currently being played +#: src/Command.cxx:149 +msgid "Toggle auto center mode" +msgstr "Liga/Desliga modo de centralização automática" + +#: src/Command.cxx:154 +msgid "Next screen" +msgstr "Próximo ecrã" + +#: src/Command.cxx:156 +msgid "Previous screen" +msgstr "Ecrã anterior" + +#: src/Command.cxx:158 +msgid "Swap to most recent screen" +msgstr "Troca para o ecrã mais recente" + +#: src/Command.cxx:163 +msgid "Forward find" +msgstr "Pesquisa para frente" + +#: src/Command.cxx:165 +msgid "Forward find next" +msgstr "Pesquisa para a frente - próximo" + +#: src/Command.cxx:167 +msgid "Backward find" +msgstr "Pesquisa para trás" + +#: src/Command.cxx:169 +msgid "Backward find previous" +msgstr "Pesquisa para trás - anterior" + +#. translators: this queries the user for a string +#. * and jumps directly (while the user is typing) +#. * to the entry which begins with this string +#: src/Command.cxx:174 +msgid "Jump to" +msgstr "Pular para" + +#: src/Command.cxx:180 +msgid "Library page" +msgstr "Página da biblioteca" + +#: src/Command.cxx:184 src/HelpPage.cxx:169 +msgid "Search screen" +msgstr "Ecrã de pesquisa" + +#: src/Command.cxx:186 +msgid "Change search mode" +msgstr "Mudar modo de pesquisa" + +#: src/Command.cxx:190 +msgid "View the selected and the currently playing song" +msgstr "Ver a trilha selecionada e a em atual reprodução" + +#: src/Command.cxx:194 src/HelpPage.cxx:181 +msgid "Lyrics screen" +msgstr "Ecrã de letra de música" + +#. translators: interrupt the current background action, +#. e.g. stop loading lyrics from the internet +#: src/Command.cxx:198 +msgid "Interrupt action" +msgstr "Interromper ação" + +#: src/Command.cxx:200 +msgid "Update Lyrics" +msgstr "Atualizar letra de música" + +#: src/Command.cxx:204 +msgid "Edit the current item" +msgstr "Editar o item atual" + +#: src/Command.cxx:209 src/HelpPage.cxx:196 +msgid "Outputs screen" +msgstr "Ecrã de Saídas" + +#: src/Command.cxx:214 src/HelpPage.cxx:203 +msgid "Chat screen" +msgstr "Ecrã de bate-papo" + +#: src/ConfigParser.cxx:119 +msgid "Word expected" +msgstr "Palavra esperada" + +#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +msgid "Malformed hotkey definition" +msgstr "Definição de tecla de atalho malformada" + +#. the hotkey configuration +#. line is incomplete +#: src/ConfigParser.cxx:173 +msgid "Incomplete hotkey configuration" +msgstr "Configuração de teclas de atalho incompleta" + +#. the hotkey configuration +#. contains an unknown +#. command +#: src/ConfigParser.cxx:187 +msgid "Unknown command" +msgstr "Comando desconhecido" + +#. translators: ncmpc +#. supports displaying the +#. "elapsed" or "remaining" +#. time of a song being +#. played; in this case, the +#. configuration file +#. contained an invalid +#. setting +#: src/ConfigParser.cxx:223 +msgid "Bad time display type" +msgstr "Tipo de visualização de tempo ruim" + +#. an equals sign '=' was expected while parsing a +#. configuration file line +#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +msgid "Missing '='" +msgstr "Falta '='" + +#: src/ConfigParser.cxx:288 +msgid "Bad color name" +msgstr "Nome de cor ruim" + +#: src/ConfigParser.cxx:297 +msgid "Incomplete color definition" +msgstr "Definição de cor incompleta" + +#: src/ConfigParser.cxx:303 +msgid "Invalid number" +msgstr "Número inválido" + +#: src/ConfigParser.cxx:310 +msgid "Malformed color definition" +msgstr "Definição de cor malformada" + +#. an unknown screen +#. name was specified +#. in the +#. configuration +#. file +#: src/ConfigParser.cxx:374 +msgid "Unknown screen name" +msgstr "Nome de ecrã desconhecido" + +#: src/ConfigParser.cxx:403 +msgid "Unknown MPD tag" +msgstr "Etiqueta MPD desconhecida" + +#: src/ConfigParser.cxx:430 +msgid "Invalid search mode" +msgstr "Modo de pesquisa inválido" + +#: src/ConfigParser.cxx:448 +msgid "Unknown search mode" +msgstr "Modo de pesquisa desconhecido" + +#: src/ConfigParser.cxx:636 +msgid "Unknown configuration parameter" +msgstr "Parâmetro de configuração desconhecido" + +#: src/CustomColors.cxx:57 +msgid "Terminal lacks support for changing colors" +msgstr "Terminal não tem suporte para mudar cores" + +#. translators: the "delete" command is only possible +#. for playlists; the user attempted to delete a song +#. or a directory or something else +#: src/FileBrowserPage.cxx:248 +msgid "Deleting this item is not possible" +msgstr "Deletar este item não é possível" + +#: src/FileBrowserPage.cxx:256 +#, c-format +msgid "Delete playlist %s?" +msgstr "Deletar lista de reprodução %s?" + +#. translators: a dialog was aborted by the user +#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/save_playlist.cxx:111 +msgid "Aborted" +msgstr "Abortado" + +#. translators: MPD deleted the playlist, as requested by the +#. user +#: src/FileBrowserPage.cxx:274 +msgid "Playlist deleted" +msgstr "Lista de Reprodução deletada" + +#. translators: caption of the browser screen +#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +msgid "Browse" +msgstr "Navegar" + +#: src/FileListPage.cxx:119 +#, c-format +msgid "Loading playlist '%s'" +msgstr "Carregando lista de reprodução '%s'" + +#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/TagListPage.cxx:184 +#, c-format +msgid "Adding '%s' to queue" +msgstr "Adicionando '%s' para a fila" + +#: src/HelpPage.cxx:60 +msgid "Movement" +msgstr "Movimento" + +#: src/HelpPage.cxx:105 +msgid "Global" +msgstr "Global" + +#: src/HelpPage.cxx:142 +msgid "Play" +msgstr "Reproduzir" + +#: src/HelpPage.cxx:149 +msgid "Center" +msgstr "Centralizar" + +#: src/HelpPage.cxx:157 +msgid "Enter directory/Select and play song" +msgstr "Adentrar diretório/Selecionar e reproduzir trilha" + +#: src/HelpPage.cxx:161 +msgid "Delete playlist" +msgstr "Deletar Lista de Reprodução" + +#: src/HelpPage.cxx:171 +msgid "New search" +msgstr "Nova pesquisa" + +#: src/HelpPage.cxx:172 +msgid "Select and play" +msgstr "Selecionar e reproduzir" + +#: src/HelpPage.cxx:183 +msgid "View Lyrics" +msgstr "Ver Letra de Música" + +#: src/HelpPage.cxx:184 +msgid "(Re)load lyrics" +msgstr "(Re)Carregar letra de música" + +#. to translators: this hotkey aborts the retrieval of lyrics +#. from the server +#: src/HelpPage.cxx:187 +msgid "Interrupt retrieval" +msgstr "Interromper busca" + +#: src/HelpPage.cxx:188 +msgid "Download lyrics for currently playing song" +msgstr "Descarregar letra de música da música em reprodução" + +#: src/HelpPage.cxx:189 +msgid "Add or edit lyrics" +msgstr "Adicionar ou editar letras" + +#: src/HelpPage.cxx:190 +msgid "Save lyrics" +msgstr "Gravar letra" + +#: src/HelpPage.cxx:191 +msgid "Delete saved lyrics" +msgstr "Apagar letras salvas" + +#: src/HelpPage.cxx:198 +msgid "Enable/disable output" +msgstr "Ativar/desativar saída" + +#: src/HelpPage.cxx:205 +msgid "Write a message" +msgstr "Escrever uma mensagem" + +#: src/HelpPage.cxx:210 +msgid "Keydef screen" +msgstr "Ecrã de definição de teclas" + +#: src/HelpPage.cxx:212 +msgid "Edit keydefs for selected command" +msgstr "Editar a definição de teclas para o comando selecionado" + +#: src/HelpPage.cxx:213 +msgid "Remove selected keydef" +msgstr "Remover keydef selecionado" + +#: src/HelpPage.cxx:214 +msgid "Add a keydef" +msgstr "Adicionar um keydef" + +#: src/HelpPage.cxx:215 +msgid "Go up a level" +msgstr "Subir um nível" + +#: src/HelpPage.cxx:216 +msgid "Apply and save changes" +msgstr "Aplicar mudanças e gravar" + +#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +msgid "Help" +msgstr "Ajuda" + +#: src/i18n.h:43 +msgid "y" +msgstr "y (sim)" + +#: src/i18n.h:44 +msgid "n" +msgstr "n (não)" + +#: src/KeyDefPage.cxx:160 +msgid "Deleted" +msgstr "Deletada" + +#: src/KeyDefPage.cxx:176 +#, c-format +msgid "Enter new key for %s: " +msgstr "Entre nova tecla para %s: " + +#: src/KeyDefPage.cxx:186 +msgid "Ctrl-Space can't be used" +msgstr "Ctrl-Espaço não pode ser usado" + +#: src/KeyDefPage.cxx:192 +#, c-format +msgid "Error: key %s is already used for %s" +msgstr "Erro: tecla %s já está a ser usada para %s" + +#: src/KeyDefPage.cxx:202 +#, c-format +msgid "Assigned %s to %s" +msgstr "Tecla %s definida para %s" + +#: src/KeyDefPage.cxx:229 +msgid "Add new key" +msgstr "Adicionar nova tecla" + +#: src/KeyDefPage.cxx:251 +#, c-format +msgid "Edit keys for %s" +msgstr "Editar teclas para %s" + +#: src/KeyDefPage.cxx:394 +msgid "You have new key bindings" +msgstr "Tem novas teclas de atalho" + +#: src/KeyDefPage.cxx:396 +msgid "Keybindings unchanged." +msgstr "Teclas de atalho inalteradas." + +#: src/KeyDefPage.cxx:406 +msgid "Unable to write configuration" +msgstr "Incapaz de escrever a configuração" + +#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +msgid "Error" +msgstr "Erro" + +#: src/KeyDefPage.cxx:422 +#, c-format +msgid "Wrote %s" +msgstr "Gravei %s" + +#: src/KeyDefPage.cxx:435 +msgid "===> Apply key bindings " +msgstr "===> Aplicar teclas de atalho " + +#: src/KeyDefPage.cxx:437 +msgid "===> Apply & Save key bindings " +msgstr "===> Aplicar e gravar teclas de atalho " + +#: src/KeyDefPage.cxx:474 +msgid "Edit key bindings" +msgstr "Editar teclas de atalho" + +#: src/KeyDefPage.cxx:556 +msgid "Note: Did you forget to 'Apply' your changes?" +msgstr "Nota: esqueceu de 'Aplicar' as suas alterações?" + +#: src/KeyDefPage.cxx:606 +msgid "Keys" +msgstr "Chaves" + +#: src/KeyName.cxx:34 +msgid "Undefined" +msgstr "Não-definido" + +#: src/KeyName.cxx:36 +msgid "Space" +msgstr "Espaço" + +#: src/KeyName.cxx:38 +msgid "Enter" +msgstr "Enter" + +#: src/KeyName.cxx:40 +msgid "Backspace" +msgstr "Backspace" + +#: src/KeyName.cxx:42 +msgid "Delete" +msgstr "Delete" + +#: src/KeyName.cxx:44 +msgid "Up" +msgstr "Cima" + +#: src/KeyName.cxx:46 +msgid "Down" +msgstr "Baixo" + +#: src/KeyName.cxx:48 +msgid "Left" +msgstr "Esquerda" + +#: src/KeyName.cxx:50 +msgid "Right" +msgstr "Direita" + +#: src/KeyName.cxx:52 +msgid "Home" +msgstr "Home" + +#: src/KeyName.cxx:54 +msgid "End" +msgstr "End" + +#: src/KeyName.cxx:56 +msgid "PageDown" +msgstr "PageDown" + +#: src/KeyName.cxx:58 +msgid "PageUp" +msgstr "PageUp" + +#: src/KeyName.cxx:60 +msgid "Tab" +msgstr "Tab" + +#: src/KeyName.cxx:62 +msgid "Shift+Tab" +msgstr "Shift+Tab" + +#: src/KeyName.cxx:64 +msgid "Esc" +msgstr "Esc" + +#: src/KeyName.cxx:66 +msgid "Insert" +msgstr "Insert" + +#: src/KeyName.cxx:75 +#, c-format +msgid "Ctrl-%c" +msgstr "Ctrl-%c" + +#: src/KeyName.cxx:78 +#, c-format +msgid "Alt-%c" +msgstr "Alt-%c" + +#: src/LibraryPage.cxx:45 +msgid "Artists" +msgstr "Artistas" + +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +msgid "Albums" +msgstr "Álbuns" + +#: src/LibraryPage.cxx:123 +msgid "All" +msgstr "Todos" + +#: src/LibraryPage.cxx:199 +msgid "Songs" +msgstr "Canções" + +#: src/LibraryPage.cxx:300 +msgid "Library" +msgstr "Biblioteca" + +#: src/ListWindow.cxx:213 +msgid "Range selection disabled" +msgstr "Seleção de intervalo desativada" + +#: src/ListWindow.cxx:216 +msgid "Range selection enabled" +msgstr "Seleção de intervalo ativada" + +#. translators: no lyrics were found for the song +#: src/LyricsPage.cxx:253 +msgid "No lyrics" +msgstr "Sem letra de música" + +#: src/LyricsPage.cxx:270 +#, c-format +msgid "Lyrics timeout occurred after %d seconds" +msgstr "Timeout das letras aconteceu após %d segundos" + +#: src/LyricsPage.cxx:353 src/LyricsPage.cxx:361 src/LyricsPage.cxx:371 +#: src/LyricsPage.cxx:507 +msgid "Lyrics" +msgstr "Letra de Música" + +#. translators: this message is displayed +#. while data is retrieved +#: src/LyricsPage.cxx:356 +msgid "loading..." +msgstr "carregando..." + +#: src/LyricsPage.cxx:378 +msgid "Editor not configured" +msgstr "Editor não configurado" + +#: src/LyricsPage.cxx:385 +msgid "Do you really want to start an editor and edit these lyrics?" +msgstr "Quer realmente abrir o editor e editar essa letra?" + +#: src/LyricsPage.cxx:403 src/LyricsPage.cxx:427 +msgid "Can't start editor" +msgstr "Não foi possível abrir o editor" + +#: src/LyricsPage.cxx:430 src/LyricsPage.cxx:434 +msgid "Editor exited unexpectedly" +msgstr "Editor foi fechado inesperadamente" + +#. lyrics for the song were saved on hard disk +#: src/LyricsPage.cxx:456 +msgid "Lyrics saved" +msgstr "Letra de Música salva" + +#: src/LyricsPage.cxx:462 +msgid "Lyrics deleted" +msgstr "Letras apagadas" + +#: src/LyricsPage.cxx:463 +msgid "No saved lyrics" +msgstr "Sem letras salvas" + +#: src/Main.cxx:132 +#, c-format +msgid "Connecting to %s" +msgstr "Conectando a %s" + +#: src/Main.cxx:148 +#, c-format +msgid "Error: MPD version %d.%d.%d is too old (%s needed)" +msgstr "Erro: a versão do MPD %d.%d.%d é muito antiga (%s necessária)" + +#. To translators: these credits are shown +#. when ncmpc is started with "--version" +#: src/Options.cxx:216 src/Options.cxx:219 +msgid "translator-credits" +msgstr "" +"Traduzido por Carlos Eduardo C. B. Shinagawa <cadu.coelho at gmail.com>\n" +"\n" +"Launchpad Contributions:\n" +" Cadu https://launchpad.net/~cadu-coelho\n" +" Guilherme Lindner https://launchpad.net/~gui666\n" +" Jamerson Albuquerque Tiossi https://launchpad.net/~tiossi\n" +" Max Kellermann https://launchpad.net/~max-duempel\n" +" Osni Leandro https://launchpad.net/~osni" + +#: src/OutputsPage.cxx:87 +#, c-format +msgid "Output '%s' enabled" +msgstr "Saída '%s' ativada" + +#: src/OutputsPage.cxx:98 +#, c-format +msgid "Output '%s' disabled" +msgstr "Saída '%s' desativada" + +#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +msgid "Outputs" +msgstr "Saídas" + +#: src/player_command.cxx:94 src/QueuePage.cxx:651 +msgid "Shuffled queue" +msgstr "Fila embaralhada" + +#: src/player_command.cxx:100 +msgid "Cleared queue" +msgstr "Fila limpa" + +#. get path +#: src/QueuePage.cxx:314 +msgid "Add" +msgstr "Adicionar" + +#: src/QueuePage.cxx:379 src/QueuePage.cxx:697 +msgid "Queue" +msgstr "Fila" + +#: src/QueuePage.cxx:381 +#, c-format +msgid "Queue on %s" +msgstr "Fila em %s" + +#. query the user for a filename +#: src/save_playlist.cxx:86 +msgid "Save queue as" +msgstr "Gravar fila como" + +#: src/save_playlist.cxx:108 +#, c-format +msgid "Replace %s?" +msgstr "Substituir %s?" + +#. success +#: src/save_playlist.cxx:129 +#, c-format +msgid "Saved %s" +msgstr "%s gravado" + +#: src/screen_client.cxx:41 +msgid "Database update running" +msgstr "Atualização de Banco de Dados em progresso" + +#: src/screen_client.cxx:48 +#, c-format +msgid "Database update of %s started" +msgstr "Atualização do Banco de Dados %s começou" + +#: src/screen_client.cxx:51 +msgid "Database update started" +msgstr "Atualização de Banco de Dados iniciada" + +#: src/screen.cxx:158 +msgid "Repeat mode is on" +msgstr "Modo de Repetição está ligado" + +#: src/screen.cxx:159 +msgid "Repeat mode is off" +msgstr "Modo de Repetição está desligado" + +#: src/screen.cxx:163 +msgid "Random mode is on" +msgstr "Modo Aleatório está ligado" + +#: src/screen.cxx:164 +msgid "Random mode is off" +msgstr "Modo Aleatório está desligado" + +#. "single" mode means +#. that MPD will +#. automatically stop +#. after playing one +#. single song +#: src/screen.cxx:173 +msgid "Single mode is on" +msgstr "Modo de música única está ligado" + +#: src/screen.cxx:174 +msgid "Single mode is off" +msgstr "Modo de música única está desligado" + +#. "consume" mode means +#. that MPD removes each +#. song which has +#. finished playing +#: src/screen.cxx:182 +msgid "Consume mode is on" +msgstr "Modo de deleção de música reproduzida está ligado" + +#: src/screen.cxx:183 +msgid "Consume mode is off" +msgstr "Modo de deleção de música reproduzida está desligado" + +#: src/screen.cxx:186 +#, c-format +msgid "Crossfade %d seconds" +msgstr "Inter-mixagem de %d segundos" + +#: src/screen.cxx:198 +msgid "Database updated" +msgstr "Banco de Dados atualizado" + +#: src/screen.cxx:248 +msgid "Find mode: Wrapped" +msgstr "Modo de Busca: Envolvido" + +#: src/screen.cxx:249 +msgid "Find mode: Normal" +msgstr "Modo de Busca: Normal" + +#: src/screen.cxx:254 +msgid "Auto center mode: On" +msgstr "Modo de Auto-Centralização: Ligado" + +#: src/screen.cxx:255 +msgid "Auto center mode: Off" +msgstr "Modo de Auto-Centralização: Desligado" + +#: src/screen_find.cxx:33 +msgid "Find" +msgstr "Procurar" + +#: src/screen_find.cxx:34 +msgid "Find backward" +msgstr "Procurar para trás" + +#: src/screen_find.cxx:35 +msgid "Jump" +msgstr "Pular" + +#: src/screen_find.cxx:81 +#, c-format +msgid "Unable to find '%s'" +msgstr "'%s' não pôde ser encontrado" + +#: src/screen_utils.cxx:150 +msgid "Password" +msgstr "Palavra-passe" + +#: src/SearchPage.cxx:47 +msgid "artist" +msgstr "artista" + +#: src/SearchPage.cxx:48 +msgid "album" +msgstr "álbum" + +#: src/SearchPage.cxx:49 +msgid "title" +msgstr "título" + +#: src/SearchPage.cxx:50 +msgid "track" +msgstr "faixa" + +#: src/SearchPage.cxx:51 +msgid "name" +msgstr "nome" + +#: src/SearchPage.cxx:52 +msgid "genre" +msgstr "estilo" + +#: src/SearchPage.cxx:53 +msgid "date" +msgstr "data" + +#: src/SearchPage.cxx:54 +msgid "composer" +msgstr "compositor" + +#: src/SearchPage.cxx:55 +msgid "performer" +msgstr "intérprete" + +#: src/SearchPage.cxx:56 +msgid "comment" +msgstr "comentário" + +#: src/SearchPage.cxx:64 +msgid "file" +msgstr "ficheiro" + +#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +msgid "Title" +msgstr "Título" + +#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +msgid "Artist" +msgstr "Artista" + +#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +msgid "Album" +msgstr "Álbum" + +#: src/SearchPage.cxx:84 +msgid "Filename" +msgstr "Nome de ficheiro" + +#: src/SearchPage.cxx:85 +msgid "Artist + Title" +msgstr "Artista + Título" + +#: src/SearchPage.cxx:263 +#, c-format +msgid "Bad search tag %s" +msgstr "Tag de pesquisa ruim %s" + +#: src/SearchPage.cxx:277 +#, c-format +msgid "No argument for search tag %s" +msgstr "Sem argumento para tag de pesquisa %s" + +#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 +#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +msgid "Search" +msgstr "Pesquisa" + +#: src/SearchPage.cxx:429 +#, c-format +msgid "Search mode: %s" +msgstr "Modo de Pesquisa: %s" + +#: src/SongPage.cxx:65 +msgid "Length" +msgstr "Duração" + +#: src/SongPage.cxx:66 +msgid "Position" +msgstr "Posição" + +#: src/SongPage.cxx:67 +msgid "Composer" +msgstr "Compositor" + +#: src/SongPage.cxx:68 +msgid "Name" +msgstr "Nome" + +#: src/SongPage.cxx:69 +msgid "Disc" +msgstr "Disco" + +#: src/SongPage.cxx:70 +msgid "Track" +msgstr "Faixa" + +#: src/SongPage.cxx:71 +msgid "Date" +msgstr "Data" + +#: src/SongPage.cxx:72 +msgid "Genre" +msgstr "Estilo" + +#: src/SongPage.cxx:73 +msgid "Comment" +msgstr "Comentário" + +#: src/SongPage.cxx:74 +msgid "Path" +msgstr "Caminho" + +#: src/SongPage.cxx:75 +msgid "Bitrate" +msgstr "Taxa de Amostragem" + +#: src/SongPage.cxx:76 +msgid "Format" +msgstr "Formato" + +#: src/SongPage.cxx:93 +msgid "Number of artists" +msgstr "Quantidade de artistas" + +#: src/SongPage.cxx:94 +msgid "Number of albums" +msgstr "Quantidade de álbuns" + +#: src/SongPage.cxx:95 +msgid "Number of songs" +msgstr "Quatidade de músicas" + +#: src/SongPage.cxx:96 +msgid "Uptime" +msgstr "Tempo a executar" + +#: src/SongPage.cxx:97 +msgid "Most recent db update" +msgstr "Atualização do BD mais recente" + +#: src/SongPage.cxx:98 +msgid "Playtime" +msgstr "Tempo de reprodução" + +#: src/SongPage.cxx:99 +msgid "DB playtime" +msgstr "Tempo de reprodução do BD" + +#: src/SongPage.cxx:204 +msgid "Song viewer" +msgstr "Visualizador de Trilha" + +#: src/SongPage.cxx:370 +msgid "MPD statistics" +msgstr "Estatísticas do MPD" + +#: src/SongPage.cxx:456 +msgid "Selected song" +msgstr "Música selecionada" + +#: src/SongPage.cxx:466 +msgid "Currently playing song" +msgstr "Música atualmente em reprodução" + +#: src/SongPage.cxx:471 +#, c-format +msgid "%d kbps" +msgstr "%d kbps" + +#: src/SongPage.cxx:555 +msgid "Song" +msgstr "Música" + +#: src/StatusBar.cxx:100 +msgid "Playing:" +msgstr "Reproduzindo:" + +#: src/StatusBar.cxx:104 +msgid "Paused" +msgstr "Pausado" + +#: src/Styles.cxx:252 src/Styles.cxx:313 +msgid "Unknown color" +msgstr "Cor desconhecida" + +#: src/Styles.cxx:323 +msgid "Unknown color field" +msgstr "Campo de cor desconhecido" + +#: src/Styles.cxx:356 +msgid "Terminal lacks color capabilities" +msgstr "Terminal não tem capacidade para trabalhar com cores" + +#: src/TagListPage.cxx:71 +msgid "All tracks" +msgstr "Todas as faixas" + +#: src/time_format.cxx:44 +msgid "year" +msgstr "ano" + +#: src/time_format.cxx:46 +msgid "years" +msgstr "anos" + +#: src/time_format.cxx:54 +msgid "week" +msgstr "semana" + +#: src/time_format.cxx:57 +msgid "weeks" +msgstr "semanas" + +#: src/time_format.cxx:65 +msgid "day" +msgstr "dia" + +#: src/time_format.cxx:68 +msgid "days" +msgstr "dias" + +#: src/TitleBar.cxx:101 +msgid "Volume n/a" +msgstr "Volume n/a" + +#: src/TitleBar.cxx:103 +#, c-format +msgid "Volume %d%%" +msgstr "Volume %d%%"
View file
ncmpc-0.36.tar.xz/po/pt_BR.po -> ncmpc-0.47.tar.xz/po/pt_BR.po
Changed
@@ -2,345 +2,342 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2010-12-19 01:05+0000\n" -"Last-Translator: Jamerson Albuquerque Tiossi <jamersontiossi@yahoo.com.br>\n" -"Language-Team: \n" -"Language: \n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2020-08-23 01:43+0000\n" +"Last-Translator: Matheus do Nascimento <leistermat@hotmail.com>\n" +"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/" +"ncmpc/translations/pt_BR/>\n" +"Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.2.1-dev\n" "X-Launchpad-Export-Date: 2011-01-05 20:00+0000\n" -"X-Generator: Launchpad (build 12138)\n" "X-Poedit-Country: BRAZIL\n" "X-Poedit-Language: Portuguese\n" "X-Poedit-SourceCharset: utf-8\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "Tecla %s definida para %s e %s" #: src/ChatPage.cxx:64 src/ChatPage.cxx:182 msgid "Chat" -msgstr "" +msgstr "Xat" #: src/ChatPage.cxx:163 msgid "Your message" -msgstr "" +msgstr "Sua mensagem" #: src/ChatPage.cxx:172 msgid "Message could not be sent" -msgstr "" +msgstr "Mensagem não pode ser enviada" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "Tela de configuração de teclas" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Sair" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "Mover cursor para cima" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "Mover cursor para baixo" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "Mover cursor para o topo da tela" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "Mover cursor para o meio da tela" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "Mover cursor para o final da tela" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "Mover cursor para o topo da lista" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "Mover cursor para o final da lista" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "Sobe uma página" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "Desce uma página" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "Seleção de Intervalo" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "Descer uma linha" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "Subir uma linha" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "Subir meia tela" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "Descer meia tela" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "Selecionar faixa atualmente em reprodução" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "Tela de Ajuda" -#: src/Command.cxx:71 src/HelpPage.cxx:140 -#, fuzzy +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" -msgstr "Tela de definição de teclas" +msgstr "Tela de fila" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "Tela de Navegação" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "Reproduzir/Adentrar diretório" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Pause" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "Parar" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "Cortar" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "Próxima faixa" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Faixa anterior" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "Correr para frente" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "Correr para trás" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "Aumentar volume" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "Abaixar volume" -#: src/Command.cxx:98 -#, fuzzy +#: src/Command.cxx:99 msgid "Select/deselect song in queue" -msgstr "Selecionar/De-selecionar trilha na Lista de Reprodução" +msgstr "Selecionar/De-selecionar musica na Lista de Reprodução" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Selecionar todos os itens listados" -#: src/Command.cxx:102 -#, fuzzy +#: src/Command.cxx:103 msgid "Delete song from queue" -msgstr "Deletar faixa da lista de reprodução" +msgstr "Deletar musica na faixa da lista" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" -msgstr "" +msgstr "Aleatório na fila" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" -msgstr "" +msgstr "Limpar fila" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "Liga/Desliga modo de repetição" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "Liga/Desliga modo aleatório" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "Liga/Desliga modo de única reprodução" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "Liga/Desliga modo de deleção de faixa reproduzida" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "Liga/Desliga inter-mixagem" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "Iniciar a atualização do banco de dados de faixas" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" -msgstr "" +msgstr "Salvar fila" -#: src/Command.cxx:122 src/HelpPage.cxx:174 -#, fuzzy +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" -msgstr "Adicionar trilha à Lista de Reprodução" +msgstr "Adicionar trilha à lista de reprodução" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "Ir para raiz" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "Ir para diretório pai" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "Localizar musica no navegador" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "Mover item para cima" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "Mover item para baixo" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "Redesenhar tela" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "Liga/Desliga modo de procura" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "Liga/Desliga modo de centralização automática" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "Próxima tela" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "Tela anterior" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "Troca para a tela mais recente" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "Pesquisa para frente" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "Pesquisa para a frente - próximo" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "Pesquisa para trás" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "Pesquisa para trás - anterior" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "Pular para" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" -msgstr "" +msgstr "Página da biblioteca" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Tela de pesquisa" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "Mudar modo de pesquisa" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "Ver a trilha selecionada e a em atual reprodução" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "Tela de Letra de Música" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "Interromper ação" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "Atualizar letra de música" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" -msgstr "" +msgstr "Editar o item atual" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "Tela de Saídas" -#: src/Command.cxx:214 src/HelpPage.cxx:203 -#, fuzzy +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" -msgstr "Próxima tela" +msgstr "Tela de bate-papo" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" -msgstr "" +msgstr "Palavra esperada" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "Definição de tecla de atalho malformada" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "Configuração de teclas de atalho incompleta" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "Comando desconhecido" @@ -352,29 +349,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "Tipo de visualização de tempo ruim" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "Falta '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "Nome de cor ruim" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "Definição de cor incompleta" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "Número inválido" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "Definição de cor malformada" @@ -383,24 +380,23 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "Nome de tela desconhecido" -#: src/ConfigParser.cxx:403 -#, fuzzy +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" -msgstr "Comando desconhecido" +msgstr "Etiqueta MPD desconhecida" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "Modo de pesquisa inválido" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "Modo de pesquisa desconhecido" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "Parâmetro de configuração desconhecido" @@ -411,141 +407,139 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "Deletar este item não é possível" -#: src/FileBrowserPage.cxx:256 -#, fuzzy, c-format +#: src/FileBrowserPage.cxx:254 +#, c-format msgid "Delete playlist %s?" -msgstr "Deletar Lista de Reprodução" +msgstr "Deletar lista de reprodução %s?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Abortado" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "Lista de Reprodução deletada" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Navegar" -#: src/FileListPage.cxx:119 -#, fuzzy, c-format +#: src/FileListPage.cxx:125 +#, c-format msgid "Loading playlist '%s'" -msgstr "Carregando Lista de Reprodução %s..." +msgstr "Carregando lista de reprodução '%s'" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 -#, fuzzy, c-format +#, c-format msgid "Adding '%s' to queue" -msgstr "Adicionando '%s' á Lista de Reprodução" +msgstr "Adicionando '%s' para a fila" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Movimento" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Global" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Reproduzir" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "Centralizar" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Adentrar diretório/Selecionar e reproduzir trilha" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Deletar Lista de Reprodução" -#: src/HelpPage.cxx:171 -#, fuzzy +#: src/HelpPage.cxx:172 msgid "New search" -msgstr "Pesquisa" +msgstr "Nova pesquisa" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Selecionar e reproduzir" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "Ver Letra de Música" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "(Re)Carregar letra de música" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Interromper busca" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "Baixar letra de música da faixa em reprodução" -#: src/HelpPage.cxx:189 -#, fuzzy +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" -msgstr "Sem letras salvas" +msgstr "Adicionar ou editar letras" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" -msgstr "Salvar letra de música." +msgstr "Salvar letra" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" msgstr "Apagar letras salvas" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Habilitar/desabilitar saída" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" -msgstr "" +msgstr "Escrever uma mensagem" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Tela de definição de teclas" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Editar a definição de teclas para o comando selecionado" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "Remover keydef selecionado" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 #, fuzzy msgid "Add a keydef" msgstr "Adicionar nova tecla" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Subir um nível" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Aplicar mudanças e salvar" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Ajuda" @@ -557,179 +551,178 @@ msgid "n" msgstr "n (não)" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Deletada" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "Entre nova tecla para %s: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" -msgstr "" +msgstr "Ctrl-Espaço não pode ser usado" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Erro: tecla %s já está sendo usada para %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "Tecla %s definida para %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Adicionar nova tecla" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "Editar teclas para %s" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "Você tem novas teclas de atalho" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "Teclas de atalho inalteradas." -#: src/KeyDefPage.cxx:406 -#, fuzzy +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" -msgstr "Configuração de teclas de atalho incompleta" +msgstr "Incapaz de escrever a configuração" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "Erro" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "Gravei %s" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "===> Aplicar teclas de atalho " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "===> Aplicar e salvar teclas de atalho " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "Editar teclas de atalho" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "Nota: Você esqueceu de 'Aplicar' suas mudanças?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" -msgstr "" +msgstr "Chaves" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "Não-definido" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Espaço" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Enter" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "Backspace" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Delete" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Cima" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Baixo" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "Esquerda" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "Direita" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Home" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "End" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "PageDown" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "PageUp" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Shift+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Insert" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" -msgstr "" +msgstr "Ctrl-%c" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" -msgstr "" +msgstr "Alt-%c" #: src/LibraryPage.cxx:45 -#, fuzzy msgid "Artists" -msgstr "Artista" +msgstr "Artistas" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 -#, fuzzy +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 msgid "Albums" -msgstr "Álbum" +msgstr "Álbuns" #: src/LibraryPage.cxx:123 msgid "All" -msgstr "" +msgstr "Todos" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" -msgstr "" +msgstr "Canções" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" -msgstr "" +msgstr "Biblioteca" #: src/ListWindow.cxx:213 msgid "Range selection disabled" @@ -747,7 +740,7 @@ #: src/LyricsPage.cxx:270 #, c-format msgid "Lyrics timeout occurred after %d seconds" -msgstr "" +msgstr "Timeout das letras aconteceu após %d segundos" #: src/LyricsPage.cxx:353 src/LyricsPage.cxx:361 src/LyricsPage.cxx:371 #: src/LyricsPage.cxx:507 @@ -762,19 +755,19 @@ #: src/LyricsPage.cxx:378 msgid "Editor not configured" -msgstr "" +msgstr "Editor não configurado" #: src/LyricsPage.cxx:385 msgid "Do you really want to start an editor and edit these lyrics?" -msgstr "" +msgstr "Quer realmente abrir o editor e editar essa letra?" #: src/LyricsPage.cxx:403 src/LyricsPage.cxx:427 msgid "Can't start editor" -msgstr "" +msgstr "Não foi possível abrir o editor" #: src/LyricsPage.cxx:430 src/LyricsPage.cxx:434 msgid "Editor exited unexpectedly" -msgstr "" +msgstr "Editor foi fechado inesperadamente" #. lyrics for the song were saved on hard disk #: src/LyricsPage.cxx:456 @@ -789,12 +782,12 @@ msgid "No saved lyrics" msgstr "Sem letras salvas" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, fuzzy, c-format msgid "Connecting to %s" msgstr "Conectado à %s" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, fuzzy, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "Erro: Versão do MPD %d.%d.%d é muito antiga (necessária %s)" @@ -813,27 +806,45 @@ " Max Kellermann https://launchpad.net/~max-duempel\n" " Osni Leandro https://launchpad.net/~osni" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Nome" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "Saída '%s' habilitada" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "Saída '%s' desabilitada" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Saídas" +#: src/OutputsPage.cxx:383 +#, fuzzy +msgid "Partition" +msgstr "Posição" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" -msgstr "" +msgstr "Fila embaralhada" #: src/player_command.cxx:100 msgid "Cleared queue" -msgstr "" +msgstr "Fila limpa" #. get path #: src/QueuePage.cxx:314 @@ -842,22 +853,22 @@ #: src/QueuePage.cxx:379 src/QueuePage.cxx:697 msgid "Queue" -msgstr "" +msgstr "Fila" #: src/QueuePage.cxx:381 #, c-format msgid "Queue on %s" -msgstr "" +msgstr "Fila em %s" #. query the user for a filename #: src/save_playlist.cxx:86 msgid "Save queue as" -msgstr "" +msgstr "Salvar fila como" #: src/save_playlist.cxx:108 -#, fuzzy, c-format +#, c-format msgid "Replace %s?" -msgstr "Substituir %s %s/%s ? " +msgstr "Substituir %s?" #. success #: src/save_playlist.cxx:129 @@ -866,9 +877,8 @@ msgstr "%s salvo" #: src/screen_client.cxx:41 -#, fuzzy msgid "Database update running" -msgstr "Atualização de Banco de Dados em progresso..." +msgstr "Atualização de Banco de Dados em progresso" #: src/screen_client.cxx:48 #, c-format @@ -966,86 +976,90 @@ msgid "Password" msgstr "Senha" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "artista" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "álbum" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "título" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "faixa" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "nome" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "estilo" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "data" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "compositor" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "intérprete" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "comentário" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "arquivo" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Título" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Artista" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Álbum" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Nome de Arquivo" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Artista + Título" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Tag de pesquisa ruim %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "Sem argumento para tag de pesquisa %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Pesquisa" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Modo de Pesquisa: %s" @@ -1056,118 +1070,117 @@ #: src/SongPage.cxx:66 msgid "Position" -msgstr "" +msgstr "Posição" #: src/SongPage.cxx:67 msgid "Composer" msgstr "Compositor" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Nome" +#, fuzzy +msgid "Performer" +msgstr "intérprete" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Disco" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Faixa" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Data" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Estilo" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Comentário" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Caminho" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Taxa de Amostragem" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" -msgstr "" +msgstr "Formato" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Número de artistas" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Número de álbuns" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Número de faixas" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "Tempo rodando" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "Atualização do BD mais recente" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "Tempo de reprodução" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "Tempo de reprodução do BD" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "Visualizador de Trilha" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "Estatísticas do MPD" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "Faixa selecionada" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "Faixa atualmente em reprodução" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d kbps" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" -msgstr "" +msgstr "Música" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Reproduzindo:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "Pausado" #: src/Styles.cxx:252 src/Styles.cxx:313 -#, fuzzy msgid "Unknown color" -msgstr "Comando desconhecido" +msgstr "Cor desconhecida" #: src/Styles.cxx:323 -#, fuzzy msgid "Unknown color field" -msgstr "Aviso: Campo de cor desconhecido - %s\n" +msgstr "Campo de cor desconhecido" #: src/Styles.cxx:356 msgid "Terminal lacks color capabilities" @@ -1179,27 +1192,27 @@ #: src/time_format.cxx:44 msgid "year" -msgstr "" +msgstr "ano" #: src/time_format.cxx:46 msgid "years" -msgstr "" +msgstr "anos" #: src/time_format.cxx:54 msgid "week" -msgstr "" +msgstr "semana" #: src/time_format.cxx:57 msgid "weeks" -msgstr "" +msgstr "semanas" #: src/time_format.cxx:65 msgid "day" -msgstr "" +msgstr "dia" #: src/time_format.cxx:68 msgid "days" -msgstr "" +msgstr "dias" #: src/TitleBar.cxx:101 msgid "Volume n/a"
View file
ncmpc-0.36.tar.xz/po/ru.po -> ncmpc-0.47.tar.xz/po/ru.po
Changed
@@ -1,5 +1,5 @@ # Russian -# Copyright (C) 2004 Kalle Wallin +# Copyright (C) 2004 Kalle Wallin # This file is distributed under the same license as the ncmpc package. # Original translation by Nikolay Pavlov <quetzal@roks.biz>, 2004. # Currently maintained by Max Arnold <lwarxx@gmail.com>, 2009. @@ -7,9 +7,9 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2019-05-19 12:49+0000\n" -"Last-Translator: OIS <mistresssilvara@hotmail.com>\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2021-04-11 19:43+0700\n" +"Last-Translator: Artem <KovalevArtem.ru@gmail.com>\n" "Language-Team: Russian <https://hosted.weblate.org/projects/ncmpc/" "translations/ru/>\n" "Language: ru\n" @@ -18,9 +18,9 @@ "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 3.7-dev\n" +"X-Generator: Weblate 4.4-dev\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "Клавиша %s назначена для %s и %s" @@ -37,309 +37,309 @@ msgid "Message could not be sent" msgstr "Сообщение не может быть отправлено" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "Экран клавиатурных комбинаций" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Выход" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "Курсор вверх" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "Курсор вниз" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "Переместить курсор в верх экрана" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "Переместить курсор в середину экрана" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "Переместить курсор в низ экрана" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "Переместить курсор в начало списка" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "Переместить курсор в конец списка" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "На страницу вверх" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "На страницу вниз" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "Выбор диапазона" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "Прокрутка на одну строку вниз" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "Прокрутка на одну строку вверх" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "Прокрутка на половину экрана вверх" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "Прокрутка на половину экрана вниз" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "Выбрать текущую композицию" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "Экран помощи" -#: src/Command.cxx:71 src/HelpPage.cxx:140 +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" msgstr "Экран очереди" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "Экран навигации" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "Воспроизвести/Перейти в директорию" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Пауза" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "Останов" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "Удалить из плейлиста все композиции кроме текущей" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "Следующая композиция" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Предыдущая композиция" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "Перемотка вперёд" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "Перемотка назад" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "Увеличить громкость" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "Уменьшить громкость" -#: src/Command.cxx:98 +#: src/Command.cxx:99 msgid "Select/deselect song in queue" msgstr "Выбрать или отменить выбор композиции в очереди" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Добавить все композиции в плейлист" -#: src/Command.cxx:102 +#: src/Command.cxx:103 msgid "Delete song from queue" msgstr "Удалить композицию из очереди" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" msgstr "Перемешать очередь" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" msgstr "Очистить очередь" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "Вкл/выкл режим повтора" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "Вкл/выкл случайный режим" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "Вкл/выкл одиночный режим" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "Вкл/выкл режим удаления после проигрывания" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "Вкл/выкл режим плавного перехода" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "Обновить музыкальную базу" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" msgstr "Сохранить очередь" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" msgstr "Добавить композицию в очередь" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "Перейти к корневой директории" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "Перейти к родительской директории" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "Перейти к файлу композиции" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "Переместить вверх" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "Переместить вниз" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "Обновить экран" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "Переключить режим поиска" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "Вкл/выкл режим автоцентрирования" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "Следующий экран" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "Предыдущий экран" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "Последний посещённый экран" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "Поиск вперёд" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "Продолжить поиск вперёд" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "Поиск назад" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "Продолжить поиск назад" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "Перейти к" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" -msgstr "" +msgstr "Библиотека" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Экран поиска" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "Изменить поле для поиска" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "Просмотр выбранной и проигрываемой композиций" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "Экран текста песни" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "Прервать операцию" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "Обновить текст" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "Редактировать текущий элемент" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "Экран аудиовыходов" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" msgstr "Экран чата" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "Ожидалось слово" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "Неправильное значение клавиатурной комбинации" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "Неопределённое значение клавиатурной комбинации" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "Неизвестная команда" @@ -351,29 +351,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "Неверный тип отображения времени" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "Пропущен символ '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "Неверное название цвета" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "Неопределённое значение цвета" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "Неверное число" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "Неправильное значение цвета" @@ -382,24 +382,23 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "Неизвестное название экрана" -#: src/ConfigParser.cxx:403 -#, fuzzy +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" -msgstr "Неизвестная команда" +msgstr "Неизвестный тег MPD" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "Неверный режим поиска" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "Неизвестный режим поиска" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "Неизвестный параметр конфигурации" @@ -410,138 +409,138 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "Удаление этого элемента невозможно" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, c-format msgid "Delete playlist %s?" msgstr "Удалить плейлист %s?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Прервано" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "Плейлист удалён" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Навигация" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, c-format msgid "Loading playlist '%s'" msgstr "Загружается плейлист '%s'" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 #, c-format msgid "Adding '%s' to queue" msgstr "В очередь добавляется '%s'" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Перемещение" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Глобальные" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Воспроизведение" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "Центрировать" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Перейти в директорию/Выбрать и проиграть композицию" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Удалить плейлист" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 msgid "New search" msgstr "Новый поиск" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Выбрать и проиграть" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "Показать текст" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "(Пере)загрузить текст" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Прервать загрузку" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "Загрузить текст проигрываемой композиции" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" msgstr "Добавить или редактировать текст" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "Сохранить текст" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" msgstr "Удалить сохранённый текст" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Вкл/выкл аудиовыход" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" msgstr "Напишите сообщение" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Экран клавиатурных комбинаций" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Изменить комбинации для выбранной команды" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "Удалить выбранную комбинацию" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 msgid "Add a keydef" msgstr "Добавить новую клавишу" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Перейти на уровень выше" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Применить и сохранить изменения" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Помощь" @@ -553,153 +552,155 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Удалено" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "Нажмите новую клавишу для %s: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" msgstr "Ctrl+Space не может использоваться" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Ошибка: клавиша %s уже используется для %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "Назначено %s для %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Добавить новую клавишу" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "Изменение клавиатурных комбинаций для %s" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "Новые клавиатурные комбинации задействованы" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "Клавиатурные комбинации не изменились." -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" msgstr "Не удалось сохранить конфигурацию" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "Ошибка" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "Записано %s" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "===> Применить клавиатурные комбинации " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "===> Применить и сохранить клавиатурные комбинации " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "Изменение клавиатурных комбинаций" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "Внимание: вы не забыли применить сделанные изменения?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "Клавиши" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "Не задано" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Пробел" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Ввод" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "Backspace" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Delete" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Вверх" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Вниз" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "Влево" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "Вправо" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "В начало" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "В конец" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "Page Down" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "Page Up" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Shift+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Insert" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "Ctrl-%c" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "Alt-%c" @@ -708,22 +709,21 @@ msgid "Artists" msgstr "Исполнители" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 msgid "Albums" msgstr "Альбомы" #: src/LibraryPage.cxx:123 msgid "All" -msgstr "" +msgstr "Всё" -#: src/LibraryPage.cxx:199 -#, fuzzy +#: src/LibraryPage.cxx:197 msgid "Songs" -msgstr "Композиция" +msgstr "Композиции" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" -msgstr "" +msgstr "Библиотека" #: src/ListWindow.cxx:213 msgid "Range selection disabled" @@ -783,12 +783,12 @@ msgid "No saved lyrics" msgstr "Сохранённый текст отсутствует" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, c-format msgid "Connecting to %s" msgstr "Подключено к %s" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "Ошибка: MPD версии %d.%d.%d устарел (необходим %s)" @@ -799,20 +799,37 @@ msgid "translator-credits" msgstr "Перевод: Max Arnold <lwarxx@gmail.com>" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "Переключено на раздел '%s'" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Название" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "Аудиовыход '%s' включен" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "Аудиовыход '%s' выключен" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Аудиовыходы" +#: src/OutputsPage.cxx:383 +msgid "Partition" +msgstr "Раздел" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "Создать новый раздел" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" msgstr "Очередь перемешана" @@ -951,86 +968,90 @@ msgid "Password" msgstr "Пароль" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "artist" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "album" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "title" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "track" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "name" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "genre" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "date" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "composer" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" -msgstr "performer" +msgstr "исполнитель" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" -msgstr "comment" +msgstr "комментарий" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" -msgstr "file" +msgstr "файл" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Композиция" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Исполнитель" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Альбом" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Имя файла" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Исполнитель + Композиция" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "Неизвестный суффикс" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Неверный тег поиска %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "Не задан критерий поиска по тегу %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Поиск" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Поле для поиска: %s" @@ -1048,100 +1069,100 @@ msgstr "Композитор" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Название" +msgid "Performer" +msgstr "Исполнитель" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Диск" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Дорожка" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Дата" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Жанр" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Комментарий" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Путь" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Битрейт" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" msgstr "Формат" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Количество исполнителей" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Количество альбомов" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Количество композиций" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "Время работы" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "Последнее обновление базы" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "Время воспроизведения" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "Время воспроизведения базы" # Several translations for Song Viewer: -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "Информация о композиции" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "Статистика MPD" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "Выбранная композиция" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "Проигрываемая композиция" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d кбит/с" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" msgstr "Композиция" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Проигрывается:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "Пауза"
View file
ncmpc-0.36.tar.xz/po/sk.po -> ncmpc-0.47.tar.xz/po/sk.po
Changed
@@ -1,347 +1,342 @@ # Slovak # Copyright (C) 2004 Kalle Wallin # This file is distributed under the same license as the ncmpc package. -# Jozef Riha <jose1711@gmail.com>, 2006, 2008. +# Jozef Riha <jose1711@gmail.com>, 2006, 2008, 2022. msgid "" msgstr "" "Project-Id-Version: ncmpc 0.11.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2010-04-07 01:36+0000\n" -"Last-Translator: Roman Horník <Unknown>\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2022-05-04 15:09+0200\n" +"Last-Translator: Jose Riha <jose1711@gmail.com>\n" "Language-Team: sk <sk@li.org>\n" -"Language: \n" +"Language: sk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2010-06-19 15:12+0000\n" -"X-Generator: Launchpad (build Unknown)\n" +"X-Generator: Poedit 3.0.1\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" -msgstr "Kláves %s priradený k %s a %s" +msgstr "Kláves %s priradený pre %s a %s" #: src/ChatPage.cxx:64 src/ChatPage.cxx:182 msgid "Chat" -msgstr "" +msgstr "Chat" #: src/ChatPage.cxx:163 msgid "Your message" -msgstr "" +msgstr "Vaša správa" #: src/ChatPage.cxx:172 msgid "Message could not be sent" -msgstr "" +msgstr "Správu sa nepodarilo odoslať" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "Okno nastavenia klávesov" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Ukončiť" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" -msgstr "Presunúť kurzor nahor" +msgstr "Presunúť kurzor vyššie" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" -msgstr "Presunúť kurzor nadol" +msgstr "Presunúť kurzor nižšie" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" -msgstr "Presunúť na vrch obrazovky" +msgstr "Presunúť kurzor na vrch okna" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" -msgstr "Presunúť kurzor do stredu obrazovky" +msgstr "Presunúť kurzor do stredu okna" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" -msgstr "Presunúť kurzor na spodok obrazovky" +msgstr "Presunúť kurzor na spodok okna" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "Presunúť kurzor na začiatok zoznamu" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "Presunúť kurzor na koniec zoznamu" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" -msgstr "Page up" +msgstr "O stranu vyššie" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" -msgstr "Page down" +msgstr "O stranu nižšie" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "Výber rozsahu" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" -msgstr "Posun o jeden riadok nadol" +msgstr "Posunúť o jeden riadok nadol" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" -msgstr "Posun o jeden riadok nahor" +msgstr "Posunúť o jeden riadok nahor" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" -msgstr "Posun o polovicu obrazovky nahor" +msgstr "Posunúť o polovicu okna nahor" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" -msgstr "Posun o polovicu obrazovky nadol" +msgstr "Posunúť o polovicu okna nadol" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" -msgstr "Zvoľiť práve prehrávanú skladbu" +msgstr "Vybrať práve prehrávanú skladbu" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" -msgstr "Okno s pomocou" +msgstr "Okno pomocníka" -#: src/Command.cxx:71 src/HelpPage.cxx:140 -#, fuzzy +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" -msgstr "Obrazovka s nastavením kláves" +msgstr "Okno s poradím" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" -msgstr "Okno listovania" +msgstr "Okno s prehliadaním" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "Prehrať/Vstúpiť do adresára" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Pauza" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" -msgstr "Stop" +msgstr "Zastaviť" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "Orezať" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "Ďalšia stopa" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Predchádzajúca stopa" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" -msgstr "Posunúť vpred" +msgstr "Posunúť dopredu" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" -msgstr "Posunúť vzad" +msgstr "Posunúť dozadu" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" -msgstr "Pridať hlasitosť" +msgstr "Zvýšiť hlasitosť" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" -msgstr "Stíšiť" +msgstr "Znížiť hlasitosť" -#: src/Command.cxx:98 -#, fuzzy +#: src/Command.cxx:99 msgid "Select/deselect song in queue" -msgstr "Vybrať/odvybrať skladbu v playliste" +msgstr "Vybrať/zrušiť výber skladby v poradí" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Vybrať všetky položky v zozname" -#: src/Command.cxx:102 -#, fuzzy +#: src/Command.cxx:103 msgid "Delete song from queue" -msgstr "Vymazať skladbu z playlistu" +msgstr "Odstrániť skladbu z poradia" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" -msgstr "" +msgstr "Zamiešať poradie" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" -msgstr "" +msgstr "Vyčistiť zoznam" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" -msgstr "Prepnúť režim opakovania" +msgstr "Zapnúť/vypnúť režim opakovania" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" -msgstr "Prepnúť náhodný režim" +msgstr "Zapnúť/vypnúť náhodný režim" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" -msgstr "Prepnúť jednotlivý režim" +msgstr "Zapnúť/vypnúť jednotlivý režim" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" -msgstr "Prepnúť spotrebný režim" +msgstr "Zapnúť/vypnúť spotrebný režim" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" -msgstr "Prepnúť režím prelínania skladieb" +msgstr "Zapnúť/vypnúť režim prelínania skladieb" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" -msgstr "Spustiť aktualizáciu hudobnej databáze" +msgstr "Spustiť aktualizáciu hudobnej databázy" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" -msgstr "" +msgstr "Uložiť poradie" -#: src/Command.cxx:122 src/HelpPage.cxx:174 -#, fuzzy +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" -msgstr "Pridať skladbu do playlistu" +msgstr "Pridať skladbu do poradia" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "Prejsť do koreňového adresára" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "Prejsť do nadradeného adresára" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "Nájsť skladbu v prehliadači" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" -msgstr "Presunúť položku nahor" +msgstr "Presunúť položku vyššie" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" -msgstr "Presunúť položku nadol" +msgstr "Presunúť položku nižšie" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" -msgstr "Obnoviť obrazovku" +msgstr "Obnoviť okno" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" -msgstr "Prepnúť režim vyhľadávania" +msgstr "Zapnúť/vypnúť režim vyhľadávania" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" -msgstr "Prepnúť automatický režim centrovania" +msgstr "Zapnúť/vypnúť automatický režim centrovania" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" -msgstr "Ďalšia obrazovka" +msgstr "Ďalšie okno" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" -msgstr "Predchádzajúca obrazovka" +msgstr "Predchádzajúce okno" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" -msgstr "Prepnúť na predchádzajúcu obrazovku" +msgstr "Prepnúť na predchádzajúce okno" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" -msgstr "Hľadať vpred" +msgstr "Hľadať smerom dopredu" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" -msgstr "Pokračovať v hľadaní vpred" +msgstr "Pokračovať v hľadaní smerom dopredu" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" -msgstr "Hľadať vzad" +msgstr "Hľadať dozadu" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" -msgstr "Pokračovať v hľadaní vzad" +msgstr "Pokračovať v hľadaní smerom dozadu" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" -msgstr "Skok na" +msgstr "Prejsť na" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" -msgstr "" +msgstr "Okno knižnice" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Okno vyhľadávania" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "Zmeniť režim vyhľadávania" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "Zobraziť vybranú a momentálne prehrávanú pieseň" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "Okno textu piesne" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "Akcia prerušenia" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "Obnoviť text" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" -msgstr "" +msgstr "Upraviť aktuálnu položku" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" -msgstr "Obrazovka výstupov" +msgstr "Obrazovka s výstupmi" -#: src/Command.cxx:214 src/HelpPage.cxx:203 -#, fuzzy +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" -msgstr "Ďalšia obrazovka" +msgstr "Obrazovka s chatom" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" -msgstr "" +msgstr "Očakávané slovo" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "Chybne zadaná definícia klávesovej skratky" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" -msgstr "Neúplná konfigurácie klavesových skratiek" +msgstr "Neúplná konfigurácia klavesových skratiek" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "Neznámy príkaz" @@ -353,29 +348,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "Nesprávny typ zobrazovania času" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "Chýba '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "Nesprávny názov farby" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "Neúplná definícia farby" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "Neplatné číslo" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "Zle zadaná definícia farby" @@ -384,24 +379,23 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" -msgstr "Neznámy názov obrazovky" +msgstr "Neznámy názov okna" -#: src/ConfigParser.cxx:403 -#, fuzzy +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" -msgstr "Neznámy príkaz" +msgstr "Neznáma značka MPD" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "Neplatný režim vyhľadávania" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "Neznámy režim vyhľadávania" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "Neznámy parameter konfigurácie" @@ -412,144 +406,140 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" -msgstr "Zmazanie tejto položky nie je možné" +msgstr "Túto položku nie je možné odstrániť" -#: src/FileBrowserPage.cxx:256 -#, fuzzy, c-format +#: src/FileBrowserPage.cxx:254 +#, c-format msgid "Delete playlist %s?" -msgstr "Vymazať playlist" +msgstr "Odstrániť playlist %s?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Zrušené" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" -msgstr "Playlist vymazaný" +msgstr "Playlist bol odstránený" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" -msgstr "Listovať" +msgstr "Prehliadať" -#: src/FileListPage.cxx:119 -#, fuzzy, c-format +#: src/FileListPage.cxx:125 +#, c-format msgid "Loading playlist '%s'" -msgstr "Nahrávam playlist %s..." +msgstr "Nahrávam playlist '%s'" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 -#, fuzzy, c-format +#, c-format msgid "Adding '%s' to queue" -msgstr "Pridávam '%s' do playlistu" +msgstr "Pridávam '%s' do poradia" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Pohyb" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Globálne" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Prehrávať" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "Do stredu" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Vstúpiť do adresára/Vybrať a prehrať skladbu" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" -msgstr "Vymazať playlist" +msgstr "Odstrániť playlist" -#: src/HelpPage.cxx:171 -#, fuzzy +#: src/HelpPage.cxx:172 msgid "New search" -msgstr "Hľadanie" +msgstr "Nové hľadanie" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Vybrať a prehrať" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "Zobraziť text piesne" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "(Znovu)načítať text" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Zachytené prerušenie" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "Stiahnuť text pre momentálne prehrávanú pieseň" -#: src/HelpPage.cxx:189 -#, fuzzy +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" -msgstr "Uložiť text piesne" +msgstr "Pridať alebo upraviť text piesne" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "Uložiť text piesne" -#: src/HelpPage.cxx:191 -#, fuzzy +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" -msgstr "Uložiť text piesne" +msgstr "Odstrániť uložený text piesne" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Povoliť/vypnúť výstup" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" -msgstr "" +msgstr "Napísať správu" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Obrazovka s nastavením kláves" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Upraviť kláves pre vybraný príkaz" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "Odstrániť vybrané nastavenie kláves" -#: src/HelpPage.cxx:214 -#, fuzzy +#: src/HelpPage.cxx:215 msgid "Add a keydef" -msgstr "Pridať nový kláves" +msgstr "Pridať def. klávesu" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Prejsť o úroveň vyššie" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Použiť a uložiť zmeny" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" -msgstr "Pomoc" +msgstr "Pomocník" #: src/i18n.h:43 msgid "y" @@ -559,179 +549,178 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" -msgstr "Vymazané" +msgstr "Odstránené" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "Zadajte nový kláves pre %s: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" -msgstr "" +msgstr "Ctrl-medzerník sa nedá použiť" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Chyba: kláves %s je už použitý pre %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" -msgstr "%s priradené k %s" +msgstr "%s priradené pre %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Pridať nový kláves" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "Upraviť klávesy pre %s" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "Nastavili ste nové priradenie klávesov" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "Priradenie klávesov sa nezmenilo." -#: src/KeyDefPage.cxx:406 -#, fuzzy +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" -msgstr "Neúplná konfigurácie klavesových skratiek" +msgstr "Nepodarilo sa zapísať nastavenie" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "Chyba" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "Zapísané %s" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "===> Použiť nastavenie klávesov " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "===> Použiť & Uložiť nastavenie klávesov " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "Upraviť priradenie klávesov" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" -msgstr "Poznámka: Zabudli ste 'Použiť' vaše zmeny?" +msgstr "Poznámka: Nezabudli ste 'Použiť' vaše zmeny?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" -msgstr "" +msgstr "Klávesy" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "Neurčené" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Medzera" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Enter" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "Backspace" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Delete" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Hore" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Dole" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" -msgstr "Vľavo" +msgstr "Doľava" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" -msgstr "Vpravo" +msgstr "Doprava" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Home" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "End" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "PageDown" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "PageUp" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Shift+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Insert" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" -msgstr "" +msgstr "Ctrl-%c" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" -msgstr "" +msgstr "Alt-%c" #: src/LibraryPage.cxx:45 -#, fuzzy msgid "Artists" -msgstr "Interpret" +msgstr "Interpreti" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 -#, fuzzy +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 msgid "Albums" -msgstr "Album" +msgstr "Albumy" #: src/LibraryPage.cxx:123 msgid "All" -msgstr "" +msgstr "Všetky" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" -msgstr "" +msgstr "Skladby" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" -msgstr "" +msgstr "Knižnica" #: src/ListWindow.cxx:213 msgid "Range selection disabled" @@ -749,7 +738,7 @@ #: src/LyricsPage.cxx:270 #, c-format msgid "Lyrics timeout occurred after %d seconds" -msgstr "" +msgstr "Po %d sekundách vypršal čas na získanie textu piesne" #: src/LyricsPage.cxx:353 src/LyricsPage.cxx:361 src/LyricsPage.cxx:371 #: src/LyricsPage.cxx:507 @@ -764,19 +753,19 @@ #: src/LyricsPage.cxx:378 msgid "Editor not configured" -msgstr "" +msgstr "Editor nie je nastavený" #: src/LyricsPage.cxx:385 msgid "Do you really want to start an editor and edit these lyrics?" -msgstr "" +msgstr "Naozaj chcete spustiť editor a upraviť tento text piesne?" #: src/LyricsPage.cxx:403 src/LyricsPage.cxx:427 msgid "Can't start editor" -msgstr "" +msgstr "Nepodarilo sa spustiť editor" #: src/LyricsPage.cxx:430 src/LyricsPage.cxx:434 msgid "Editor exited unexpectedly" -msgstr "" +msgstr "Editor neočakávane skončil" #. lyrics for the song were saved on hard disk #: src/LyricsPage.cxx:456 @@ -784,24 +773,22 @@ msgstr "Text piesne uložený" #: src/LyricsPage.cxx:462 -#, fuzzy msgid "Lyrics deleted" -msgstr "Playlist vymazaný" +msgstr "Text skladby bol odstránený" #: src/LyricsPage.cxx:463 -#, fuzzy msgid "No saved lyrics" -msgstr "Uložiť text piesne" +msgstr "Žiaden uložený text piesne" -#: src/Main.cxx:132 -#, fuzzy, c-format +#: src/Main.cxx:133 +#, c-format msgid "Connecting to %s" -msgstr "Pripojený k %s" +msgstr "Pripájam sa k %s" -#: src/Main.cxx:148 -#, fuzzy, c-format +#: src/Main.cxx:149 +#, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" -msgstr "Chyba: MPD verzie %d.%d.%d je príliš staré (%s je potrebná)" +msgstr "Chyba: Verzia MPD %d.%d.%d je príliš stará (potrebná je %s)" #. To translators: these credits are shown #. when ncmpc is started with "--version" @@ -814,27 +801,44 @@ " Jose Riha https://launchpad.net/~jose1711\n" " Roman Horník https://launchpad.net/~roman.hornik" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "Prepnuté na partíciu '%s'" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Názov" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" -msgstr "Výstup '%s' povolený" +msgstr "Výstup '%s' zapnutý" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "Výstup '%s' vypnutý" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Výstupy" +#: src/OutputsPage.cxx:383 +msgid "Partition" +msgstr "Partícia" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "Vytvoriť novú partíciu" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" -msgstr "" +msgstr "Poradie bolo zamiešané" #: src/player_command.cxx:100 msgid "Cleared queue" -msgstr "" +msgstr "Vyčistené poradie" #. get path #: src/QueuePage.cxx:314 @@ -843,22 +847,22 @@ #: src/QueuePage.cxx:379 src/QueuePage.cxx:697 msgid "Queue" -msgstr "" +msgstr "Poradie" #: src/QueuePage.cxx:381 #, c-format msgid "Queue on %s" -msgstr "" +msgstr "Poradie na %s" #. query the user for a filename #: src/save_playlist.cxx:86 msgid "Save queue as" -msgstr "" +msgstr "Uložiť poradie skladieb ako" #: src/save_playlist.cxx:108 -#, fuzzy, c-format +#, c-format msgid "Replace %s?" -msgstr "Nahradiť %s %s/%s ? " +msgstr "Nahradiť %s?" #. success #: src/save_playlist.cxx:129 @@ -867,9 +871,8 @@ msgstr "Uložený %s" #: src/screen_client.cxx:41 -#, fuzzy msgid "Database update running" -msgstr "Prebieha aktualizácia databáze..." +msgstr "Spúšťam aktualizáciu databáze" #: src/screen_client.cxx:48 #, c-format @@ -932,11 +935,11 @@ #: src/screen.cxx:248 msgid "Find mode: Wrapped" -msgstr "Režim vyhľadávania: Zabalený" +msgstr "Režim vyhľadávania: Dookola" #: src/screen.cxx:249 msgid "Find mode: Normal" -msgstr "Režim vyhľadávanie: Normálny" +msgstr "Režim vyhľadávania: Normálny" #: src/screen.cxx:254 msgid "Auto center mode: On" @@ -967,86 +970,90 @@ msgid "Password" msgstr "Heslo" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "interpret" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "album" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "názov" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "stopa" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "názov" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "žáner" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "dátum" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "skladateľ" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "umelec" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "komentár" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "súbor" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Názov" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Interpret" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Album" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Názov súboru" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Interpret + Názov" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "Nerozpoznaná prípona" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Zlá značka vyhľadávania %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "Chýba argument pre značku vyhľadávania %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Hľadanie" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Režim vyhľadávania: %s" @@ -1057,118 +1064,116 @@ #: src/SongPage.cxx:66 msgid "Position" -msgstr "" +msgstr "Pozícia" #: src/SongPage.cxx:67 msgid "Composer" msgstr "Skladateľ" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Názov" +msgid "Performer" +msgstr "Umelec" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Disk" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Stopa" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Dátum" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Žáner" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Komentár" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Cesta" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Bitový tok" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" -msgstr "" +msgstr "Formát" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Počet interpretov" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Počet albumov" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Počet piesní" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" -msgstr "Uptime" +msgstr "Doba spustenia" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" -msgstr "Najčerstvejší update databáze" +msgstr "Najnovšia aktualizácia databáze" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" -msgstr "Čas hrania" +msgstr "Doba hrania" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" -msgstr "Čas hrania databáze" +msgstr "Doba hrania databáze" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "Prehliadač piesní" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "Štatistiky MPD" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "Vybraná pieseň" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "Momentálne prehrávaná pieseň" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d kbps" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" -msgstr "" +msgstr "Skladba" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Prehrávam:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "Pozastavené" #: src/Styles.cxx:252 src/Styles.cxx:313 -#, fuzzy msgid "Unknown color" -msgstr "Neznámy príkaz" +msgstr "Neznáma farba" #: src/Styles.cxx:323 -#, fuzzy msgid "Unknown color field" -msgstr "Varovanie: Neznáme farebné pole - %s\n" +msgstr "Neznáme pole farby" #: src/Styles.cxx:356 msgid "Terminal lacks color capabilities" @@ -1180,27 +1185,27 @@ #: src/time_format.cxx:44 msgid "year" -msgstr "" +msgstr "rok" #: src/time_format.cxx:46 msgid "years" -msgstr "" +msgstr "roky" #: src/time_format.cxx:54 msgid "week" -msgstr "" +msgstr "týždeň" #: src/time_format.cxx:57 msgid "weeks" -msgstr "" +msgstr "týždne" #: src/time_format.cxx:65 msgid "day" -msgstr "" +msgstr "deň" #: src/time_format.cxx:68 msgid "days" -msgstr "" +msgstr "dni" #: src/TitleBar.cxx:101 msgid "Volume n/a"
View file
ncmpc-0.36.tar.xz/po/sv.po -> ncmpc-0.47.tar.xz/po/sv.po
Changed
@@ -7,342 +7,339 @@ msgstr "" "Project-Id-Version: ncmpc 0.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2010-04-14 05:21+0000\n" -"Last-Translator: Rickard Närström <rickard.narstrom@gmail.com>\n" -"Language-Team: sv <sv@li.org>\n" -"Language: \n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2021-08-18 10:35+0000\n" +"Last-Translator: Luna Jernberg <droidbittin@gmail.com>\n" +"Language-Team: Swedish <https://hosted.weblate.org/projects/ncmpc/" +"translations/sv/>\n" +"Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.8-dev\n" "X-Launchpad-Export-Date: 2010-06-19 15:12+0000\n" -"X-Generator: Launchpad (build Unknown)\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "Tangent %s tilldelad %s och %s" #: src/ChatPage.cxx:64 src/ChatPage.cxx:182 msgid "Chat" -msgstr "" +msgstr "Chatt" #: src/ChatPage.cxx:163 msgid "Your message" -msgstr "" +msgstr "Ditt meddelande" #: src/ChatPage.cxx:172 msgid "Message could not be sent" -msgstr "" +msgstr "Meddelande kunde inte skickas" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "Tangentdefinitioner" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Avsluta" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "Markör uppåt" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "Markör nedåt" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "Flytta markören längst upp" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "Flytta markören till mitten" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "Flytta markören längst ner" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "Flytta markören längst upp i listan" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "Flytta markören längst ner i listan" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "Markören en skärm uppåt" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "Markören en skärm nedåt" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "Gå ner en rad" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "Gå upp en rad" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "Gå upp en halv skärm" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "Gå ner en halv skärm" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" -msgstr "" +msgstr "Välj låten som spelas" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "Hjälp" -#: src/Command.cxx:71 src/HelpPage.cxx:140 -#, fuzzy +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" -msgstr "Hjälp" +msgstr "Kö skärm" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "Filer" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "Spela upp/Välj" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Pausa" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "Stoppa" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "Beskär" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "Nästa spår" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Föregående spår" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "Sök framåt" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "Sök bakåt" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "Höj volymen" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "Sänk volymen" -#: src/Command.cxx:98 -#, fuzzy +#: src/Command.cxx:99 msgid "Select/deselect song in queue" -msgstr "Markera/avmarkera spår till spellistan" +msgstr "Markera/avmarkera spår i kön" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Markera alla listade föremål" -#: src/Command.cxx:102 -#, fuzzy +#: src/Command.cxx:103 msgid "Delete song from queue" -msgstr "Ta bort låt från spellista" +msgstr "Ta bort låt från kö" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" -msgstr "" +msgstr "Blanda kö" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" -msgstr "" +msgstr "Töm kön" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "Repeat på/av" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "Slumpning på/av" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "Mjuk övergång på/av" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "Updatera musikdatabasen" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" -msgstr "" +msgstr "Spara kö" -#: src/Command.cxx:122 src/HelpPage.cxx:174 -#, fuzzy +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" -msgstr "Lägg till i spellista" +msgstr "Lägg till låt till kö" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "Gå till rotkatalogen" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "Gå upp en nivå" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "Hitta spår i Filer" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "Flytta upp" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "Flytta ner" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "Uppdatera fönster" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "Ändra sökinställningar" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "Automatisk centrering på/av" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "Nästa skärm" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "Tidigare skärm" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" -msgstr "" +msgstr "Byt till förra skärmen" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "Sök" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "Nästa träff" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "Föregående träff" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "Upprepa sökning bakåt" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "Hoppa till" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" -msgstr "" +msgstr "Bibliotekssida" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Databassökning" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "Ändra måltyp för databassökning" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" -msgstr "" +msgstr "Visa den valda och den låt som spelas just nu" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "Texter" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "Avbryt handling" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "Uppdatera texter" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" -msgstr "" +msgstr "Redigera det aktuella objektet" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "Utgångar" -#: src/Command.cxx:214 src/HelpPage.cxx:203 -#, fuzzy +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" -msgstr "Nästa skärm" +msgstr "Chatt skärm" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "Dålig tangentdefinition" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "Inkomplett tangentdefinition" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "Okänt kommando" @@ -354,29 +351,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "Felaktigt tidsformat" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "Saknar '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "Felaktigt färgnamn" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "Inkomplett färgdefinition" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "Ogiltigt nummer" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "Felaktig färgdefinition" @@ -385,170 +382,166 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "Skärmnamn okänt" -#: src/ConfigParser.cxx:403 -#, fuzzy +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" -msgstr "Okänt kommando" +msgstr "Okänd MPD tagg" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" -msgstr "" +msgstr "Ogiltigt sökläge" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" -msgstr "" +msgstr "Okänt sökläge" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "Okänd konfigurationsinställning" #: src/CustomColors.cxx:57 msgid "Terminal lacks support for changing colors" -msgstr "Terminalen saknar stöd för växling av färger" +msgstr "Terminalen saknar stöd för att ändra färger" #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "Du kan inte ta bort det här föremålet" -#: src/FileBrowserPage.cxx:256 -#, fuzzy, c-format +#: src/FileBrowserPage.cxx:254 +#, c-format msgid "Delete playlist %s?" -msgstr "Ta bort spellista" +msgstr "Ta bort spellista %s?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Avbrutet" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "Spellista borttagen" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Filer" -#: src/FileListPage.cxx:119 -#, fuzzy, c-format +#: src/FileListPage.cxx:125 +#, c-format msgid "Loading playlist '%s'" -msgstr "Laddar spellista %s..." +msgstr "Laddar spellista '%s'" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 -#, fuzzy, c-format +#, c-format msgid "Adding '%s' to queue" -msgstr "Lägger till '%s' till spellista" +msgstr "Lägger till '%s' till kö" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Navigation" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Globala" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Starta/Spela markerad" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "Centrera" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Välj katalog/Markera och spela upp" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Ta bort spellista" -#: src/HelpPage.cxx:171 -#, fuzzy +#: src/HelpPage.cxx:172 msgid "New search" -msgstr "Sök" +msgstr "Ny sökning" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Lägg till spellistan och spela" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "Visa texter" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "Ladda (om) texter" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Avbryt hämtning" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "Ladda ner texter till låten som spelas just nu" -#: src/HelpPage.cxx:189 -#, fuzzy +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" -msgstr "Spara texter" +msgstr "Lägg till eller redigera texter" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "Spara texter" -#: src/HelpPage.cxx:191 -#, fuzzy +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" -msgstr "Spara texter" +msgstr "Ta bort sparade texter" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Slå på/av utgång" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" -msgstr "" +msgstr "Skriv ett meddelande" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 #, fuzzy msgid "Add a keydef" msgstr "Lägg till ny tangent" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "Gå upp en nivå" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Verkställ och spara förändringar" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Hjälp" @@ -560,179 +553,180 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Borttagen" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "Ny tangent för %s: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" -msgstr "" +msgstr "Ctrl-Space kan inte användas" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Fel: Tangenten %s används redan för %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "%s tilldelad %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Lägg till ny tangent" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "Ändra tangenter för kommandot %s" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "Tangentdefinitioner uppdaterade" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "Tangentdefinitioner oförändrade." -#: src/KeyDefPage.cxx:406 -#, fuzzy +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" -msgstr "Inkomplett tangentdefinition" +msgstr "Kunde inte skriva konfiguration" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "Fel" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "Sparade %s" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "===> Verkställ " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "===> Verkställ och spara " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "Ändra tangentdefinitioner" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "OBS! Glömde du att 'Verkställa' dina ändringar?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" -msgstr "" +msgstr "Tangenter" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "Ej definierad" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Mellanslag" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Enter" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "Bakstegstangent" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Ta bort" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Uppåtpil" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Nedåtpil" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "Vänsterpil" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "Högerpil" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Home" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "End" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "PageDown" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "PageUp" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Shift+tabb" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Insert" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" -msgstr "" +msgstr "Ctrl-%c" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" -msgstr "" +msgstr "Alt-%c" #: src/LibraryPage.cxx:45 #, fuzzy msgid "Artists" msgstr "Artist" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 #, fuzzy msgid "Albums" msgstr "Album" #: src/LibraryPage.cxx:123 msgid "All" -msgstr "" +msgstr "Alla" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" -msgstr "" +msgstr "Låtar" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" -msgstr "" +msgstr "Bibliotek" #: src/ListWindow.cxx:213 msgid "Range selection disabled" @@ -765,7 +759,7 @@ #: src/LyricsPage.cxx:378 msgid "Editor not configured" -msgstr "" +msgstr "Redigeraren inte konfiguerad" #: src/LyricsPage.cxx:385 msgid "Do you really want to start an editor and edit these lyrics?" @@ -773,7 +767,7 @@ #: src/LyricsPage.cxx:403 src/LyricsPage.cxx:427 msgid "Can't start editor" -msgstr "" +msgstr "Kan inte starta redigeraren" #: src/LyricsPage.cxx:430 src/LyricsPage.cxx:434 msgid "Editor exited unexpectedly" @@ -790,17 +784,16 @@ msgstr "Spellista borttagen" #: src/LyricsPage.cxx:463 -#, fuzzy msgid "No saved lyrics" -msgstr "Spara texter" +msgstr "Inga sparade texter" -#: src/Main.cxx:132 -#, fuzzy, c-format +#: src/Main.cxx:133 +#, c-format msgid "Connecting to %s" -msgstr "Ansluten till %s" +msgstr "Ansluter till %s" -#: src/Main.cxx:148 -#, fuzzy, c-format +#: src/Main.cxx:149 +#, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "Fel: MPD version %d.%d.%d är för gammal (%s krävs)" @@ -815,27 +808,44 @@ " Rickard Närström https://launchpad.net/~riccetn\n" " nanker https://launchpad.net/~nanker" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "Ändrade till partition '%s'" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Namn" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "Utgång '%s' påslagen" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "Utgång '%s' avslagen" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Utgångar" +#: src/OutputsPage.cxx:383 +msgid "Partition" +msgstr "Partition" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "Skapa ny partition" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" -msgstr "" +msgstr "Blandad kö" #: src/player_command.cxx:100 msgid "Cleared queue" -msgstr "" +msgstr "Kön tömd" #. get path #: src/QueuePage.cxx:314 @@ -844,22 +854,22 @@ #: src/QueuePage.cxx:379 src/QueuePage.cxx:697 msgid "Queue" -msgstr "" +msgstr "Kö" #: src/QueuePage.cxx:381 #, c-format msgid "Queue on %s" -msgstr "" +msgstr "Kö på %s" #. query the user for a filename #: src/save_playlist.cxx:86 msgid "Save queue as" -msgstr "" +msgstr "Spara kö som" #: src/save_playlist.cxx:108 -#, fuzzy, c-format +#, c-format msgid "Replace %s?" -msgstr "Ersätt %s %s/%s ? " +msgstr "Ersätt %s?" #. success #: src/save_playlist.cxx:129 @@ -868,9 +878,8 @@ msgstr "%s sparad" #: src/screen_client.cxx:41 -#, fuzzy msgid "Database update running" -msgstr "Databasen uppdateras..." +msgstr "Databasuppdatering körs" #: src/screen_client.cxx:48 #, c-format @@ -968,86 +977,90 @@ msgid "Password" msgstr "Lösenord" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "artist" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "album" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "titel" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "spår" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "namn" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "genre" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "datum" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "kompositör" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "uppträdare" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "kommentar" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "fil" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Titel" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Artist" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Album" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Filnamn" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Artist + titel" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "Okänt suffix" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Felaktig söktyp %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "Argumentet för söktyp %s saknas" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Sök" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Sök efter: %s" @@ -1058,118 +1071,117 @@ #: src/SongPage.cxx:66 msgid "Position" -msgstr "" +msgstr "Position" #: src/SongPage.cxx:67 msgid "Composer" msgstr "Kompositör" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Namn" +#, fuzzy +msgid "Performer" +msgstr "uppträdare" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Skiva" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Spår" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Datum" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Genre" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Kommentar" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Sökväg" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Bithastighet" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" -msgstr "" +msgstr "Format" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Antal artister" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Antal album" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Antal låtar" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "Upptid" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "Senaste databasuppdateringen" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "Speltid" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" -msgstr "" +msgstr "DB speltid" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "Spår" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "MPD-statistik" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "Markerad låt" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d kb/s" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" -msgstr "" +msgstr "Låt" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Spelar:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "Pausad" #: src/Styles.cxx:252 src/Styles.cxx:313 -#, fuzzy msgid "Unknown color" -msgstr "Okänt kommando" +msgstr "Okänd färg" #: src/Styles.cxx:323 -#, fuzzy msgid "Unknown color field" -msgstr "Varning: %s ej definierad.\n" +msgstr "Okänt färg fält" #: src/Styles.cxx:356 msgid "Terminal lacks color capabilities" @@ -1181,27 +1193,27 @@ #: src/time_format.cxx:44 msgid "year" -msgstr "" +msgstr "år" #: src/time_format.cxx:46 msgid "years" -msgstr "" +msgstr "år" #: src/time_format.cxx:54 msgid "week" -msgstr "" +msgstr "vecka" #: src/time_format.cxx:57 msgid "weeks" -msgstr "" +msgstr "veckor" #: src/time_format.cxx:65 msgid "day" -msgstr "" +msgstr "dag" #: src/time_format.cxx:68 msgid "days" -msgstr "" +msgstr "dagar" #: src/TitleBar.cxx:101 msgid "Volume n/a"
View file
ncmpc-0.36.tar.xz/po/uk.po -> ncmpc-0.47.tar.xz/po/uk.po
Changed
@@ -6,7 +6,7 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" "PO-Revision-Date: 2011-08-11 10:30+0300\n" "Last-Translator: Oleksandr Kovalenko <alx.kovalenko@gmail.com>\n" "Language-Team: Ukrainian <uk@li.org>\n" @@ -19,7 +19,7 @@ "X-Poedit-Language: Ukrainian\n" "X-Poedit-Country: UKRAINE\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "Клавіша %s призначена до %s та %s" @@ -36,314 +36,314 @@ msgid "Message could not be sent" msgstr "" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "Екран конфігурації клавіш" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "Вийти" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "Перемістити курсор доверху" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "Перемістити курсор донизу" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" msgstr "Перемістити курсор на початок екрану" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" msgstr "Перемістити курсор до середини екрану" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" msgstr "Перемістити курсор в кінець екрану" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "Перемістити курсор на початок переліку" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "Перемістити курсор в кінець переліку" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "Сторінка догори" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "Сторінка донизу" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" msgstr "Вибір обсягу" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "Прогорнути один рядок донизу" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "Прогорнути один рядок догори" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "Прогорнути півекрану догори" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "Прогорнути півекрану донизу" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "Вибрати пісню, що зараз програється" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "Екран допомоги" -#: src/Command.cxx:71 src/HelpPage.cxx:140 +#: src/Command.cxx:72 src/HelpPage.cxx:141 #, fuzzy msgid "Queue screen" msgstr "Екран призначення клавіш" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "Екран перегляду" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "Програти чи увійти до каталогу" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "Призупинити" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "Зупинити" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "Обрізати" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "Наступна доріжка" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "Попередня доріжка" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "Шукати попереду" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "Шукати позаду" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "Збільшити гучність" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "Зменшити гучність" -#: src/Command.cxx:98 +#: src/Command.cxx:99 #, fuzzy msgid "Select/deselect song in queue" msgstr "Вибрати чи зняти виділення пісні в переліку програвання" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "Вибрати всі перелічені елементи" -#: src/Command.cxx:102 +#: src/Command.cxx:103 #, fuzzy msgid "Delete song from queue" msgstr "Видалити пісню з переліку програвання" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" msgstr "" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" msgstr "" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "Перемкнути режим повторення" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "Перемкнути випадковий режим" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "Перемкнути режим повторення однієї пісні" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "Перемкнути режим вичерпання" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "Перемкнути режим плавного переходу" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "Розпочати оновлення бази даних музики" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" msgstr "" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 #, fuzzy msgid "Append song to queue" msgstr "Долучити пісню до переліку програвання" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "Перейти до кореневої теки" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "Перейти до батьківської теки" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "Визначити розміщення пісні в оглядачі" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "Перемістити елемент догори" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "Перемістити елемент донизу" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "Оновити екран" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "Перемкнути режим пошуку" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "Перемкнути режим автоматичного центрування" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "Наступний екран" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "Попередній екран" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "Поміняти останні екрани" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "Знайти попереду" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "Знайти попереду наступне" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "Знайти позаду" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "Знайти позаду попереднє" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "Перейти до" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" msgstr "" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "Екран пошуку" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "Змінити режим пошуку" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" msgstr "Переглянути вибрану та пісню, що зараз програється" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "Екран текстів пісень" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "Припинити дію" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "Оновити текст пісні" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "Екран виходів" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 #, fuzzy msgid "Chat screen" msgstr "Наступний екран" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "Неправильне визначення гарячої клавіші" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "Незавершена конфігурація гарячих клавіш" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "Невідома команда" @@ -355,29 +355,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" msgstr "Неправильний тип показу часу" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "Відсутній \"=\"" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "Неправильна назва кольору" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "Незавершене визначення кольору" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "Неправильне число" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "Неправильне визначення кольору" @@ -386,24 +386,24 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "Невідома назва екрану" -#: src/ConfigParser.cxx:403 +#: src/ConfigParser.cxx:388 #, fuzzy msgid "Unknown MPD tag" msgstr "Невідома команда" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "Помилковий режим пошуку" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "Невідомий режим пошуку" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "Невідомий конфігураційний параметр" @@ -414,141 +414,141 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "Видалити цей елемент неможливо" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, fuzzy, c-format msgid "Delete playlist %s?" msgstr "Видалити перелік програвання" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "Перервано" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "Перелік програвання видалений" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "Огляд" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, fuzzy, c-format msgid "Loading playlist '%s'" msgstr "Завантажується перелік програвання %s..." -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 #, fuzzy, c-format msgid "Adding '%s' to queue" msgstr "Додається '%s' до переліку програвання" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "Переміщення" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "Загальні" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "Програти" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "По центру" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "Ввести теку чи вибрати та програти пісню" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "Видалити перелік програвання" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 #, fuzzy msgid "New search" msgstr "Пошук" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "Вибрати та програти" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "Переглянути текст пісні" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "(Пере)завантажити текст пісні" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "Припинити отримання" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "Завантажити текст для пісні, що зараз програється" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 #, fuzzy msgid "Add or edit lyrics" msgstr "Немає збереженого тексту пісні" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "Зберегти текст пісні" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" msgstr "Видалити збережений текст пісні" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "Увімкнути/вимкнути вихід" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" msgstr "" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "Екран призначення клавіш" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "Редагувати призначену клавішу для вибраної команди" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "Вилучити вибране призначення клавіші" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 #, fuzzy msgid "Add a keydef" msgstr "Додати нову клавішу" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "На рівень вище" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" msgstr "Застосувати та зберегти зміни" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "Допомога" @@ -560,154 +560,156 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "Видалена" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "Введіть нову клавішу для %s: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" msgstr "" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" msgstr "Помилка: клавіша %s вже використовується для %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "Призначення %s до %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "Додати нову клавішу" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "Редагувати клавішу для %s" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "Ви маєте нову прив'язку клавіші" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "Прив'язки клавіш не змінені." -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 #, fuzzy msgid "Unable to write configuration" msgstr "Незавершена конфігурація гарячих клавіш" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "Помилка" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "Записаний %s" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " msgstr "===> Застосування прив'язки клавіші " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " msgstr "===> Застосування та збереження прив'язки клавіші " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "Редагувати прив'язки клавіш" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "Примітка: ви забули \"Застосувати\" зроблені зміни?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" msgstr "Не визначений" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" msgstr "Space" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" msgstr "Enter" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" msgstr "Backspace" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Delete" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" msgstr "Up" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" msgstr "Down" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" msgstr "Left" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" msgstr "Right" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Home" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "End" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" msgstr "PageDown" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" msgstr "PageUp" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Shift+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Insert" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "" @@ -717,7 +719,7 @@ msgid "Artists" msgstr "Виконавець" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 #, fuzzy msgid "Albums" msgstr "Альбом" @@ -726,11 +728,11 @@ msgid "All" msgstr "" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" msgstr "" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" msgstr "" @@ -792,12 +794,12 @@ msgid "No saved lyrics" msgstr "Немає збереженого тексту пісні" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, fuzzy, c-format msgid "Connecting to %s" msgstr "Встановлене з'єднання з %s" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, fuzzy, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "Помилка: MPD версії %d.%d.%d застаріла (необхідна %s)" @@ -808,20 +810,38 @@ msgid "translator-credits" msgstr "Oleksandr Kovalenko <alx.kovalenko@gmail.com>" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "Назва" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "Вихід '%s' увімкнений" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "Вихід '%s' вимкнений" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "Виходи" +#: src/OutputsPage.cxx:383 +#, fuzzy +msgid "Partition" +msgstr "artist" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" msgstr "" @@ -961,86 +981,90 @@ msgid "Password" msgstr "Пароль" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "artist" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "album" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "title" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "track" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "name" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "genre" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "date" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "composer" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "performer" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "comment" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "file" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "Назва" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "Виконавець" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "Альбом" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "Назва файлу" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "Виконавець + Назва" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "Неправильна мітка %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "Немає аргументу для пошуку за міткою %s" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" msgstr "Пошук" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "Режим пошуку: %s" @@ -1058,99 +1082,100 @@ msgstr "Композитор" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "Назва" +#, fuzzy +msgid "Performer" +msgstr "performer" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "Диск" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "Доріжка" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "Дата" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "Жанр" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "Примітка" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "Шлях" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "Бітрейт" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" msgstr "" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "Кількість виконавців" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "Кількість альбомів" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "Кількість пісень" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "Час роботи" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" msgstr "Останнє оновлення бази даних" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "Час програвання" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" msgstr "Час програвання всієї БД" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "Переглядач пісень" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" msgstr "Статистика MPD" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "Вибрана пісня" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "Пісня, що зараз програється" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "%d кбіт/с" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" msgstr "" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "Програється:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" msgstr "Призупинено"
View file
ncmpc-0.36.tar.xz/po/zh_CN.po -> ncmpc-0.47.tar.xz/po/zh_CN.po
Changed
@@ -7,9 +7,9 @@ msgstr "" "Project-Id-Version: ncmpc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-08 17:59+0200\n" -"PO-Revision-Date: 2019-09-16 09:02+0000\n" -"Last-Translator: 谭志新 <tanzhxin@hotmail.com>\n" +"POT-Creation-Date: 2020-08-24 15:23+0200\n" +"PO-Revision-Date: 2021-01-19 16:32+0000\n" +"Last-Translator: Lilian Wang <li330wang@gmail.com>\n" "Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/" "ncmpc/translations/zh_Hans/>\n" "Language: zh_CN\n" @@ -17,10 +17,10 @@ "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 3.9-dev\n" +"X-Generator: Weblate 4.5-dev\n" "X-Launchpad-Export-Date: 2011-06-23 08:56+0000\n" -#: src/Bindings.cxx:81 src/Bindings.cxx:87 +#: src/Bindings.cxx:80 src/Bindings.cxx:86 #, c-format msgid "Key %s assigned to %s and %s" msgstr "按键 %s 分配给 %s 和 %s" @@ -31,315 +31,315 @@ #: src/ChatPage.cxx:163 msgid "Your message" -msgstr "你的讯息" +msgstr "你的消息" #: src/ChatPage.cxx:172 msgid "Message could not be sent" -msgstr "讯息无法送出" +msgstr "消息无法发出" -#: src/Command.cxx:29 +#: src/Command.cxx:30 msgid "Key configuration screen" msgstr "快捷键设置页面" -#: src/Command.cxx:32 +#: src/Command.cxx:33 msgid "Quit" msgstr "退出" -#: src/Command.cxx:36 +#: src/Command.cxx:37 msgid "Move cursor up" msgstr "向上移动光标" -#: src/Command.cxx:38 +#: src/Command.cxx:39 msgid "Move cursor down" msgstr "向下移动光标" -#: src/Command.cxx:40 +#: src/Command.cxx:41 msgid "Move cursor to the top of screen" -msgstr "光标移到顶部" +msgstr "光标移到屏幕顶部" -#: src/Command.cxx:42 +#: src/Command.cxx:43 msgid "Move cursor to the middle of screen" -msgstr "光标移到中部" +msgstr "光标移到屏幕中部" -#: src/Command.cxx:44 +#: src/Command.cxx:45 msgid "Move cursor to the bottom of screen" -msgstr "光标移到底部" +msgstr "光标移到屏幕底部" -#: src/Command.cxx:46 +#: src/Command.cxx:47 msgid "Move cursor to the top of the list" msgstr "光标移到列表顶部" -#: src/Command.cxx:48 +#: src/Command.cxx:49 msgid "Move cursor to the bottom of the list" msgstr "光标移到列表底部" -#: src/Command.cxx:50 +#: src/Command.cxx:51 msgid "Page up" msgstr "上一页" -#: src/Command.cxx:52 +#: src/Command.cxx:53 msgid "Page down" msgstr "下一页" -#: src/Command.cxx:54 +#: src/Command.cxx:55 msgid "Range selection" -msgstr "区段选择" +msgstr "范围选择" -#: src/Command.cxx:56 +#: src/Command.cxx:57 msgid "Scroll down one line" msgstr "向下滚动一行" -#: src/Command.cxx:58 +#: src/Command.cxx:59 msgid "Scroll up one line" msgstr "向上滚动一行" -#: src/Command.cxx:60 +#: src/Command.cxx:61 msgid "Scroll up half a screen" msgstr "向上滚动半屏" -#: src/Command.cxx:62 +#: src/Command.cxx:63 msgid "Scroll down half a screen" msgstr "向下滚动半屏" -#: src/Command.cxx:64 +#: src/Command.cxx:65 msgid "Select currently playing song" msgstr "选择当前播放曲目" -#: src/Command.cxx:69 +#: src/Command.cxx:70 msgid "Help screen" msgstr "帮助页面" -#: src/Command.cxx:71 src/HelpPage.cxx:140 +#: src/Command.cxx:72 src/HelpPage.cxx:141 msgid "Queue screen" msgstr "列表页面" -#: src/Command.cxx:73 src/HelpPage.cxx:155 +#: src/Command.cxx:74 src/HelpPage.cxx:156 msgid "Browse screen" msgstr "目录页面" -#: src/Command.cxx:78 +#: src/Command.cxx:79 msgid "Play/Enter directory" msgstr "播放/进入 目录" -#: src/Command.cxx:80 +#: src/Command.cxx:81 msgid "Pause" msgstr "暂停" -#: src/Command.cxx:82 +#: src/Command.cxx:83 msgid "Stop" msgstr "停止" -#: src/Command.cxx:84 +#: src/Command.cxx:85 msgid "Crop" msgstr "剪切" -#: src/Command.cxx:86 +#: src/Command.cxx:87 msgid "Next track" msgstr "下一曲" -#: src/Command.cxx:88 +#: src/Command.cxx:89 msgid "Previous track" msgstr "上一曲" -#: src/Command.cxx:90 +#: src/Command.cxx:91 msgid "Seek forward" msgstr "快进" -#: src/Command.cxx:92 +#: src/Command.cxx:93 msgid "Seek backward" msgstr "快退" -#: src/Command.cxx:94 +#: src/Command.cxx:95 msgid "Increase volume" msgstr "增加音量" -#: src/Command.cxx:96 +#: src/Command.cxx:97 msgid "Decrease volume" msgstr "降低音量" -#: src/Command.cxx:98 +#: src/Command.cxx:99 msgid "Select/deselect song in queue" -msgstr "选中/不选当前列表的歌曲" +msgstr "选择/取消当前列表的歌曲" -#: src/Command.cxx:100 +#: src/Command.cxx:101 msgid "Select all listed items" msgstr "选中所有列出的项" -#: src/Command.cxx:102 +#: src/Command.cxx:103 msgid "Delete song from queue" msgstr "从播放列表中移除歌曲" -#: src/Command.cxx:104 +#: src/Command.cxx:105 msgid "Shuffle queue" msgstr "随机播放列表" -#: src/Command.cxx:106 +#: src/Command.cxx:107 msgid "Clear queue" msgstr "清空播放列表" -#: src/Command.cxx:108 +#: src/Command.cxx:109 msgid "Toggle repeat mode" msgstr "切换重复模式" -#: src/Command.cxx:110 +#: src/Command.cxx:111 msgid "Toggle random mode" msgstr "切换随机模式" -#: src/Command.cxx:112 +#: src/Command.cxx:113 msgid "Toggle single mode" msgstr "切换单曲模式" -#: src/Command.cxx:114 +#: src/Command.cxx:115 msgid "Toggle consume mode" msgstr "切换消除模式" -#: src/Command.cxx:116 +#: src/Command.cxx:117 msgid "Toggle crossfade mode" msgstr "切换淡入淡出模式" -#: src/Command.cxx:118 +#: src/Command.cxx:119 msgid "Start a music database update" msgstr "更新此数据库" -#: src/Command.cxx:120 +#: src/Command.cxx:121 msgid "Save queue" msgstr "保存播放列表" -#: src/Command.cxx:122 src/HelpPage.cxx:174 +#: src/Command.cxx:123 src/HelpPage.cxx:175 msgid "Append song to queue" msgstr "添加到播放列表" -#: src/Command.cxx:125 +#: src/Command.cxx:126 msgid "Go to root directory" msgstr "进入根目录" -#: src/Command.cxx:127 +#: src/Command.cxx:128 msgid "Go to parent directory" msgstr "进入父目录" -#: src/Command.cxx:130 +#: src/Command.cxx:131 msgid "Locate song in browser" msgstr "定位到音乐所在目录" -#: src/Command.cxx:134 +#: src/Command.cxx:135 msgid "Move item up" msgstr "上移" -#: src/Command.cxx:136 +#: src/Command.cxx:137 msgid "Move item down" msgstr "下移" -#: src/Command.cxx:138 +#: src/Command.cxx:139 msgid "Refresh screen" msgstr "刷新页面" #. translators: toggle between wrapping and non-wrapping #. search -#: src/Command.cxx:145 +#: src/Command.cxx:146 msgid "Toggle find mode" msgstr "切换查找模式" #. translators: the auto center mode always centers the song #. currently being played -#: src/Command.cxx:149 +#: src/Command.cxx:150 msgid "Toggle auto center mode" msgstr "切换自动居中模式" -#: src/Command.cxx:154 +#: src/Command.cxx:155 msgid "Next screen" msgstr "下一页面" -#: src/Command.cxx:156 +#: src/Command.cxx:157 msgid "Previous screen" msgstr "上一页面" -#: src/Command.cxx:158 +#: src/Command.cxx:159 msgid "Swap to most recent screen" msgstr "切换到最近一个页面" -#: src/Command.cxx:163 +#: src/Command.cxx:164 msgid "Forward find" msgstr "前向查找" -#: src/Command.cxx:165 +#: src/Command.cxx:166 msgid "Forward find next" msgstr "查找下一个" -#: src/Command.cxx:167 +#: src/Command.cxx:168 msgid "Backward find" msgstr "后向查找" -#: src/Command.cxx:169 +#: src/Command.cxx:170 msgid "Backward find previous" msgstr "查找前一个" #. translators: this queries the user for a string #. * and jumps directly (while the user is typing) #. * to the entry which begins with this string -#: src/Command.cxx:174 +#: src/Command.cxx:175 msgid "Jump to" msgstr "跳转到" -#: src/Command.cxx:180 +#: src/Command.cxx:181 msgid "Library page" msgstr "曲库页面" -#: src/Command.cxx:184 src/HelpPage.cxx:169 +#: src/Command.cxx:185 src/HelpPage.cxx:170 msgid "Search screen" msgstr "查找页面" -#: src/Command.cxx:186 +#: src/Command.cxx:187 msgid "Change search mode" msgstr "更改搜索模式" -#: src/Command.cxx:190 +#: src/Command.cxx:191 msgid "View the selected and the currently playing song" -msgstr "参看选择当前播放的曲目" +msgstr "查看所选和当前播放的歌曲" -#: src/Command.cxx:194 src/HelpPage.cxx:181 +#: src/Command.cxx:195 src/HelpPage.cxx:182 msgid "Lyrics screen" msgstr "歌词页面" #. translators: interrupt the current background action, #. e.g. stop loading lyrics from the internet -#: src/Command.cxx:198 +#: src/Command.cxx:199 msgid "Interrupt action" msgstr "中断后台操作" -#: src/Command.cxx:200 +#: src/Command.cxx:201 msgid "Update Lyrics" msgstr "更新歌词" -#: src/Command.cxx:204 +#: src/Command.cxx:205 msgid "Edit the current item" msgstr "编辑当前条目" -#: src/Command.cxx:209 src/HelpPage.cxx:196 +#: src/Command.cxx:210 src/HelpPage.cxx:197 msgid "Outputs screen" msgstr "输出页面" -#: src/Command.cxx:214 src/HelpPage.cxx:203 +#: src/Command.cxx:215 src/HelpPage.cxx:204 msgid "Chat screen" msgstr "对话页面" -#: src/ConfigParser.cxx:119 +#: src/ConfigParser.cxx:120 msgid "Word expected" msgstr "建议字符" -#: src/ConfigParser.cxx:145 src/ConfigParser.cxx:154 +#: src/ConfigParser.cxx:139 msgid "Malformed hotkey definition" msgstr "不正确的快捷键定义" #. the hotkey configuration #. line is incomplete -#: src/ConfigParser.cxx:173 +#: src/ConfigParser.cxx:158 msgid "Incomplete hotkey configuration" msgstr "不完整的快捷键配置" #. the hotkey configuration #. contains an unknown #. command -#: src/ConfigParser.cxx:187 +#: src/ConfigParser.cxx:172 msgid "Unknown command" msgstr "未知命令" @@ -351,29 +351,29 @@ #. configuration file #. contained an invalid #. setting -#: src/ConfigParser.cxx:223 +#: src/ConfigParser.cxx:210 msgid "Bad time display type" -msgstr "错误的时间显示格式" +msgstr "错误的时间显示类型" #. an equals sign '=' was expected while parsing a #. configuration file line -#: src/ConfigParser.cxx:239 src/ConfigParser.cxx:469 +#: src/ConfigParser.cxx:224 src/ConfigParser.cxx:454 msgid "Missing '='" msgstr "缺少 '='" -#: src/ConfigParser.cxx:288 +#: src/ConfigParser.cxx:273 msgid "Bad color name" msgstr "错误的颜色名" -#: src/ConfigParser.cxx:297 +#: src/ConfigParser.cxx:282 msgid "Incomplete color definition" msgstr "不完整的颜色定义" -#: src/ConfigParser.cxx:303 +#: src/ConfigParser.cxx:288 src/SearchPage.cxx:244 msgid "Invalid number" msgstr "无效的数字" -#: src/ConfigParser.cxx:310 +#: src/ConfigParser.cxx:295 msgid "Malformed color definition" msgstr "不正确的颜色定义" @@ -382,23 +382,23 @@ #. in the #. configuration #. file -#: src/ConfigParser.cxx:374 +#: src/ConfigParser.cxx:359 msgid "Unknown screen name" msgstr "未知的页面名" -#: src/ConfigParser.cxx:403 +#: src/ConfigParser.cxx:388 msgid "Unknown MPD tag" -msgstr "未知mpd标记" +msgstr "未知的MPD标签" -#: src/ConfigParser.cxx:430 +#: src/ConfigParser.cxx:415 msgid "Invalid search mode" msgstr "无效的搜索模式" -#: src/ConfigParser.cxx:448 +#: src/ConfigParser.cxx:433 msgid "Unknown search mode" msgstr "未知的搜索模式" -#: src/ConfigParser.cxx:636 +#: src/ConfigParser.cxx:621 msgid "Unknown configuration parameter" msgstr "未知的配置参数" @@ -409,138 +409,138 @@ #. translators: the "delete" command is only possible #. for playlists; the user attempted to delete a song #. or a directory or something else -#: src/FileBrowserPage.cxx:248 +#: src/FileBrowserPage.cxx:246 msgid "Deleting this item is not possible" msgstr "此项目不能被删除" -#: src/FileBrowserPage.cxx:256 +#: src/FileBrowserPage.cxx:254 #, c-format msgid "Delete playlist %s?" msgstr "删除播放列表 %s?" #. translators: a dialog was aborted by the user -#: src/FileBrowserPage.cxx:261 src/KeyDefPage.cxx:181 src/LyricsPage.cxx:388 +#: src/FileBrowserPage.cxx:259 src/KeyDefPage.cxx:182 src/LyricsPage.cxx:388 #: src/save_playlist.cxx:111 msgid "Aborted" msgstr "已放弃" #. translators: MPD deleted the playlist, as requested by the #. user -#: src/FileBrowserPage.cxx:274 +#: src/FileBrowserPage.cxx:272 msgid "Playlist deleted" msgstr "播放列表已删除" #. translators: caption of the browser screen -#: src/FileBrowserPage.cxx:301 src/FileBrowserPage.cxx:383 +#: src/FileBrowserPage.cxx:299 src/FileBrowserPage.cxx:381 msgid "Browse" msgstr "目录" -#: src/FileListPage.cxx:119 +#: src/FileListPage.cxx:125 #, c-format msgid "Loading playlist '%s'" msgstr "加载播放列表 %s" -#: src/FileListPage.cxx:159 src/FileListPage.cxx:246 src/FileListPage.cxx:271 +#: src/FileListPage.cxx:165 src/FileListPage.cxx:254 src/FileListPage.cxx:277 #: src/TagListPage.cxx:184 #, c-format msgid "Adding '%s' to queue" -msgstr "添加 %s 到播放列表" +msgstr "添加 '%s' 到播放列表" -#: src/HelpPage.cxx:60 +#: src/HelpPage.cxx:61 msgid "Movement" msgstr "移动" -#: src/HelpPage.cxx:105 +#: src/HelpPage.cxx:106 msgid "Global" msgstr "全局设定" -#: src/HelpPage.cxx:142 +#: src/HelpPage.cxx:143 msgid "Play" msgstr "播放" -#: src/HelpPage.cxx:149 +#: src/HelpPage.cxx:150 msgid "Center" msgstr "当前播放项居中显示" -#: src/HelpPage.cxx:157 +#: src/HelpPage.cxx:158 msgid "Enter directory/Select and play song" msgstr "进入选中目录/播放选中歌曲" -#: src/HelpPage.cxx:161 +#: src/HelpPage.cxx:162 msgid "Delete playlist" msgstr "删除播放列表" -#: src/HelpPage.cxx:171 +#: src/HelpPage.cxx:172 msgid "New search" msgstr "新的查找" -#: src/HelpPage.cxx:172 +#: src/HelpPage.cxx:173 msgid "Select and play" msgstr "选中并播放" -#: src/HelpPage.cxx:183 +#: src/HelpPage.cxx:184 msgid "View Lyrics" msgstr "查看歌词" -#: src/HelpPage.cxx:184 +#: src/HelpPage.cxx:185 msgid "(Re)load lyrics" msgstr "(重新)加载歌词" #. to translators: this hotkey aborts the retrieval of lyrics #. from the server -#: src/HelpPage.cxx:187 +#: src/HelpPage.cxx:188 msgid "Interrupt retrieval" msgstr "中断歌词下载" -#: src/HelpPage.cxx:188 +#: src/HelpPage.cxx:189 msgid "Download lyrics for currently playing song" msgstr "为当前曲目下载歌词" -#: src/HelpPage.cxx:189 +#: src/HelpPage.cxx:190 msgid "Add or edit lyrics" msgstr "添加或编辑歌词" -#: src/HelpPage.cxx:190 +#: src/HelpPage.cxx:191 msgid "Save lyrics" msgstr "保存歌词" -#: src/HelpPage.cxx:191 +#: src/HelpPage.cxx:192 msgid "Delete saved lyrics" msgstr "删除已保存歌词" -#: src/HelpPage.cxx:198 +#: src/HelpPage.cxx:199 msgid "Enable/disable output" msgstr "启用/禁用音频输出" -#: src/HelpPage.cxx:205 +#: src/HelpPage.cxx:206 msgid "Write a message" -msgstr "写讯息" +msgstr "写消息" -#: src/HelpPage.cxx:210 +#: src/HelpPage.cxx:211 msgid "Keydef screen" msgstr "键定义页面" -#: src/HelpPage.cxx:212 +#: src/HelpPage.cxx:213 msgid "Edit keydefs for selected command" msgstr "为选择的命令定义快捷键" -#: src/HelpPage.cxx:213 +#: src/HelpPage.cxx:214 msgid "Remove selected keydef" msgstr "去除选择的快捷键设定" -#: src/HelpPage.cxx:214 +#: src/HelpPage.cxx:215 msgid "Add a keydef" msgstr "添加新的快捷键" -#: src/HelpPage.cxx:215 +#: src/HelpPage.cxx:216 msgid "Go up a level" msgstr "上一级" -#: src/HelpPage.cxx:216 +#: src/HelpPage.cxx:217 msgid "Apply and save changes" -msgstr "保存设置" +msgstr "应用并保存更改" -#: src/HelpPage.cxx:245 src/HelpPage.cxx:329 +#: src/HelpPage.cxx:246 src/HelpPage.cxx:330 msgid "Help" msgstr "帮助" @@ -552,153 +552,155 @@ msgid "n" msgstr "n" -#: src/KeyDefPage.cxx:160 +#: src/KeyDefPage.cxx:161 msgid "Deleted" msgstr "已删除" -#: src/KeyDefPage.cxx:176 +#: src/KeyDefPage.cxx:177 #, c-format msgid "Enter new key for %s: " msgstr "为 %s 输入新的按键: " -#: src/KeyDefPage.cxx:186 +#: src/KeyDefPage.cxx:187 msgid "Ctrl-Space can't be used" -msgstr "ctl-Space键无法使用" +msgstr "Ctrl-空格键无法使用" -#: src/KeyDefPage.cxx:192 +#: src/KeyDefPage.cxx:193 #, c-format msgid "Error: key %s is already used for %s" -msgstr "键 %s 已经绑定到 %s" +msgstr "错误:%s 键已经绑定到 %s" -#: src/KeyDefPage.cxx:202 +#: src/KeyDefPage.cxx:203 #, c-format msgid "Assigned %s to %s" msgstr "分配 %s 到 %s" -#: src/KeyDefPage.cxx:229 +#: src/KeyDefPage.cxx:230 msgid "Add new key" msgstr "添加新的键" -#: src/KeyDefPage.cxx:251 +#: src/KeyDefPage.cxx:252 #, c-format msgid "Edit keys for %s" msgstr "为 %s 编辑快捷键" -#: src/KeyDefPage.cxx:394 +#: src/KeyDefPage.cxx:395 msgid "You have new key bindings" msgstr "你有新绑定的快捷键" -#: src/KeyDefPage.cxx:396 +#: src/KeyDefPage.cxx:397 msgid "Keybindings unchanged." msgstr "取消快捷键变更." -#: src/KeyDefPage.cxx:406 +#: src/KeyDefPage.cxx:407 msgid "Unable to write configuration" msgstr "无法保存配置" -#: src/KeyDefPage.cxx:415 src/KeyDefPage.cxx:424 +#: src/KeyDefPage.cxx:416 src/KeyDefPage.cxx:425 msgid "Error" msgstr "错误" -#: src/KeyDefPage.cxx:422 +#: src/KeyDefPage.cxx:423 #, c-format msgid "Wrote %s" msgstr "写入 %s" -#: src/KeyDefPage.cxx:435 +#: src/KeyDefPage.cxx:436 msgid "===> Apply key bindings " -msgstr "应用快捷键设置 " +msgstr "===> 应用快捷键设置 " -#: src/KeyDefPage.cxx:437 +#: src/KeyDefPage.cxx:438 msgid "===> Apply & Save key bindings " -msgstr "应用 & 保存快捷键设置 " +msgstr "===> 应用并保存快捷键设置 " -#: src/KeyDefPage.cxx:474 +#: src/KeyDefPage.cxx:475 msgid "Edit key bindings" msgstr "编辑快捷键设置" -#: src/KeyDefPage.cxx:556 +#: src/KeyDefPage.cxx:557 msgid "Note: Did you forget to 'Apply' your changes?" msgstr "提示: 你忘记了保存你的设置?" -#: src/KeyDefPage.cxx:606 +#: src/KeyDefPage.cxx:607 msgid "Keys" msgstr "快捷键" -#: src/KeyName.cxx:34 +#: src/KeyName.cxx:115 msgid "Undefined" -msgstr "未定义的" +msgstr "未定义" -#: src/KeyName.cxx:36 +#: src/KeyName.cxx:117 msgid "Space" -msgstr "空格键" +msgstr "空格" -#: src/KeyName.cxx:38 +#: src/KeyName.cxx:119 msgid "Enter" -msgstr "Enter" +msgstr "回车" -#: src/KeyName.cxx:40 +#: src/KeyName.cxx:121 msgid "Backspace" -msgstr "Backspace" +msgstr "退格" -#: src/KeyName.cxx:42 +#: src/KeyName.cxx:123 msgid "Delete" msgstr "Delete" -#: src/KeyName.cxx:44 +#: src/KeyName.cxx:125 msgid "Up" -msgstr "Up" +msgstr "方向键上" -#: src/KeyName.cxx:46 +#: src/KeyName.cxx:127 msgid "Down" -msgstr "Down" +msgstr "方向键下" -#: src/KeyName.cxx:48 +#: src/KeyName.cxx:129 msgid "Left" -msgstr "向左" +msgstr "方向键左" -#: src/KeyName.cxx:50 +#: src/KeyName.cxx:131 msgid "Right" -msgstr "向右" +msgstr "方向键右" -#: src/KeyName.cxx:52 +#: src/KeyName.cxx:133 msgid "Home" msgstr "Home" -#: src/KeyName.cxx:54 +#: src/KeyName.cxx:135 msgid "End" msgstr "End" -#: src/KeyName.cxx:56 +#: src/KeyName.cxx:137 msgid "PageDown" -msgstr "向下翻页" +msgstr "PageDown" -#: src/KeyName.cxx:58 +#: src/KeyName.cxx:139 msgid "PageUp" -msgstr "向上翻页" +msgstr "PageUp" -#: src/KeyName.cxx:60 +#: src/KeyName.cxx:141 msgid "Tab" msgstr "Tab" -#: src/KeyName.cxx:62 +#: src/KeyName.cxx:143 msgid "Shift+Tab" msgstr "Shift+Tab" -#: src/KeyName.cxx:64 +#: src/KeyName.cxx:145 msgid "Esc" -msgstr "取消" +msgstr "Esc" -#: src/KeyName.cxx:66 +#: src/KeyName.cxx:147 msgid "Insert" msgstr "Insert" -#: src/KeyName.cxx:75 +#. translate "^X" to "Ctrl-X" +#: src/KeyName.cxx:167 #, c-format msgid "Ctrl-%c" msgstr "Ctrl-%c" -#: src/KeyName.cxx:78 +#. translate "M-X" to "Alt-X" +#: src/KeyName.cxx:173 #, c-format msgid "Alt-%c" msgstr "Alt-%c" @@ -707,7 +709,7 @@ msgid "Artists" msgstr "艺术家" -#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:177 +#: src/LibraryPage.cxx:48 src/LibraryPage.cxx:175 msgid "Albums" msgstr "专辑" @@ -715,21 +717,21 @@ msgid "All" msgstr "全部" -#: src/LibraryPage.cxx:199 +#: src/LibraryPage.cxx:197 msgid "Songs" msgstr "歌曲" -#: src/LibraryPage.cxx:300 +#: src/LibraryPage.cxx:314 msgid "Library" -msgstr "库" +msgstr "曲库" #: src/ListWindow.cxx:213 msgid "Range selection disabled" -msgstr "禁用区段选取" +msgstr "范围选择取消" #: src/ListWindow.cxx:216 msgid "Range selection enabled" -msgstr "开启区段选取" +msgstr "范围选择开启" #. translators: no lyrics were found for the song #: src/LyricsPage.cxx:253 @@ -754,11 +756,11 @@ #: src/LyricsPage.cxx:378 msgid "Editor not configured" -msgstr "没有定义编辑器" +msgstr "未配置编辑器" #: src/LyricsPage.cxx:385 msgid "Do you really want to start an editor and edit these lyrics?" -msgstr "你确认要使用editor来编辑歌词吗?" +msgstr "你确认要启动文本编辑器来编辑歌词吗?" #: src/LyricsPage.cxx:403 src/LyricsPage.cxx:427 msgid "Can't start editor" @@ -781,12 +783,12 @@ msgid "No saved lyrics" msgstr "没有歌词" -#: src/Main.cxx:132 +#: src/Main.cxx:133 #, c-format msgid "Connecting to %s" -msgstr "连接到服务器 %s" +msgstr "连接到服务器 %s" -#: src/Main.cxx:148 +#: src/Main.cxx:149 #, c-format msgid "Error: MPD version %d.%d.%d is too old (%s needed)" msgstr "错误: MPD版本%d.%d.%d过低 (需要 %s)" @@ -802,20 +804,37 @@ "deactivatedaccount\n" " snowdream https://launchpad.net/~yanghui" -#: src/OutputsPage.cxx:87 +#: src/OutputsPage.cxx:168 +#, c-format +msgid "Switched to partition '%s'" +msgstr "切换至“%s”分区" + +#: src/OutputsPage.cxx:180 src/SongPage.cxx:69 +msgid "Name" +msgstr "名字" + +#: src/OutputsPage.cxx:230 #, c-format msgid "Output '%s' enabled" msgstr "启用 '%s' 输出" -#: src/OutputsPage.cxx:98 +#: src/OutputsPage.cxx:241 #, c-format msgid "Output '%s' disabled" msgstr "禁用 '%s' 输出" -#: src/OutputsPage.cxx:145 src/OutputsPage.cxx:206 +#: src/OutputsPage.cxx:371 src/OutputsPage.cxx:480 msgid "Outputs" msgstr "输出" +#: src/OutputsPage.cxx:383 +msgid "Partition" +msgstr "分区" + +#: src/OutputsPage.cxx:407 +msgid "Create new partition" +msgstr "创建新分区" + #: src/player_command.cxx:94 src/QueuePage.cxx:651 msgid "Shuffled queue" msgstr "随机播放列表" @@ -954,86 +973,90 @@ msgid "Password" msgstr "密码" -#: src/SearchPage.cxx:47 +#: src/SearchPage.cxx:51 msgid "artist" msgstr "艺术家" -#: src/SearchPage.cxx:48 +#: src/SearchPage.cxx:52 msgid "album" msgstr "专辑" -#: src/SearchPage.cxx:49 +#: src/SearchPage.cxx:53 msgid "title" msgstr "标题" -#: src/SearchPage.cxx:50 +#: src/SearchPage.cxx:54 msgid "track" msgstr "曲目" -#: src/SearchPage.cxx:51 +#: src/SearchPage.cxx:55 msgid "name" msgstr "名称" -#: src/SearchPage.cxx:52 +#: src/SearchPage.cxx:56 msgid "genre" msgstr "流派" -#: src/SearchPage.cxx:53 +#: src/SearchPage.cxx:57 msgid "date" msgstr "日期" -#: src/SearchPage.cxx:54 +#: src/SearchPage.cxx:58 msgid "composer" msgstr "作曲" -#: src/SearchPage.cxx:55 +#: src/SearchPage.cxx:59 msgid "performer" msgstr "歌手" -#: src/SearchPage.cxx:56 +#: src/SearchPage.cxx:60 msgid "comment" msgstr "注释" -#: src/SearchPage.cxx:64 +#: src/SearchPage.cxx:68 msgid "file" msgstr "文件" -#: src/SearchPage.cxx:81 src/SongPage.cxx:63 +#: src/SearchPage.cxx:90 src/SongPage.cxx:63 msgid "Title" msgstr "标题" -#: src/SearchPage.cxx:82 src/SongPage.cxx:62 +#: src/SearchPage.cxx:91 src/SongPage.cxx:62 msgid "Artist" msgstr "艺术家" -#: src/SearchPage.cxx:83 src/SongPage.cxx:64 +#: src/SearchPage.cxx:92 src/SongPage.cxx:64 msgid "Album" msgstr "专辑" -#: src/SearchPage.cxx:84 +#: src/SearchPage.cxx:93 msgid "Filename" msgstr "文件名" -#: src/SearchPage.cxx:85 +#: src/SearchPage.cxx:94 msgid "Artist + Title" msgstr "艺术家 + 标题" -#: src/SearchPage.cxx:263 +#: src/SearchPage.cxx:285 src/SearchPage.cxx:289 +msgid "Unrecognized suffix" +msgstr "未识别后缀" + +#: src/SearchPage.cxx:337 #, c-format msgid "Bad search tag %s" msgstr "不正确的搜索条目 %s" -#: src/SearchPage.cxx:277 +#: src/SearchPage.cxx:351 #, c-format msgid "No argument for search tag %s" msgstr "搜索条目 %s 没有参数" -#: src/SearchPage.cxx:366 src/SearchPage.cxx:399 src/SearchPage.cxx:403 -#: src/SearchPage.cxx:407 src/SearchPage.cxx:466 +#: src/SearchPage.cxx:446 src/SearchPage.cxx:479 src/SearchPage.cxx:483 +#: src/SearchPage.cxx:487 src/SearchPage.cxx:546 msgid "Search" -msgstr "查找" +msgstr "搜索" -#: src/SearchPage.cxx:429 +#: src/SearchPage.cxx:509 #, c-format msgid "Search mode: %s" msgstr "搜索模式: %s" @@ -1051,101 +1074,101 @@ msgstr "作曲" #: src/SongPage.cxx:68 -msgid "Name" -msgstr "名字" +msgid "Performer" +msgstr "表演者" -#: src/SongPage.cxx:69 +#: src/SongPage.cxx:70 msgid "Disc" msgstr "碟片" -#: src/SongPage.cxx:70 +#: src/SongPage.cxx:71 msgid "Track" msgstr "音轨" -#: src/SongPage.cxx:71 +#: src/SongPage.cxx:72 msgid "Date" msgstr "日期" -#: src/SongPage.cxx:72 +#: src/SongPage.cxx:73 msgid "Genre" msgstr "流派" -#: src/SongPage.cxx:73 +#: src/SongPage.cxx:74 msgid "Comment" msgstr "注释" -#: src/SongPage.cxx:74 +#: src/SongPage.cxx:75 msgid "Path" msgstr "路径" -#: src/SongPage.cxx:75 +#: src/SongPage.cxx:76 msgid "Bitrate" msgstr "比特率" -#: src/SongPage.cxx:76 +#: src/SongPage.cxx:77 msgid "Format" msgstr "格式" -#: src/SongPage.cxx:93 +#: src/SongPage.cxx:94 msgid "Number of artists" msgstr "艺术家总数" -#: src/SongPage.cxx:94 +#: src/SongPage.cxx:95 msgid "Number of albums" msgstr "专辑总数" -#: src/SongPage.cxx:95 +#: src/SongPage.cxx:96 msgid "Number of songs" msgstr "歌曲总数" -#: src/SongPage.cxx:96 +#: src/SongPage.cxx:97 msgid "Uptime" msgstr "启动时间" -#: src/SongPage.cxx:97 +#: src/SongPage.cxx:98 msgid "Most recent db update" -msgstr "最新DB更新" +msgstr "最近数据库更新" -#: src/SongPage.cxx:98 +#: src/SongPage.cxx:99 msgid "Playtime" msgstr "播放时间" -#: src/SongPage.cxx:99 +#: src/SongPage.cxx:100 msgid "DB playtime" -msgstr "DB 播放时间" +msgstr "数据库播放时间" -#: src/SongPage.cxx:204 +#: src/SongPage.cxx:205 msgid "Song viewer" msgstr "歌曲查看器" -#: src/SongPage.cxx:370 +#: src/SongPage.cxx:371 msgid "MPD statistics" -msgstr "MPD统计" +msgstr "MPD统计信息" -#: src/SongPage.cxx:456 +#: src/SongPage.cxx:457 msgid "Selected song" msgstr "选中曲目" -#: src/SongPage.cxx:466 +#: src/SongPage.cxx:467 msgid "Currently playing song" msgstr "当前播放曲目" -#: src/SongPage.cxx:471 +#: src/SongPage.cxx:472 #, c-format msgid "%d kbps" msgstr "码率 %d kbps" -#: src/SongPage.cxx:555 +#: src/SongPage.cxx:556 msgid "Song" -msgstr "歌" +msgstr "歌曲" -#: src/StatusBar.cxx:100 +#: src/StatusBar.cxx:165 msgid "Playing:" msgstr "播放中:" -#: src/StatusBar.cxx:104 +#: src/StatusBar.cxx:169 msgid "Paused" -msgstr "暂停" +msgstr "暂停" #: src/Styles.cxx:252 src/Styles.cxx:313 msgid "Unknown color"
View file
ncmpc-0.36.tar.xz/src/AsyncUserInput.cxx -> ncmpc-0.47.tar.xz/src/AsyncUserInput.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -24,7 +23,6 @@ #include "GlobalBindings.hxx" #include "ncmpc.hxx" #include "Point.hxx" -#include "util/Compiler.h" static bool ignore_key(int key) @@ -32,7 +30,7 @@ return key == ERR || key == '\0'; } -gcc_pure +gnu::pure static Command translate_key(int key) { @@ -40,18 +38,11 @@ } void -AsyncUserInput::OnReadable(const boost::system::error_code &error) +AsyncUserInput::OnSocketReady(unsigned) noexcept { - if (error) { - get_io_context().stop(); - return; - } - int key = wgetch(&w); - if (ignore_key(key)) { - AsyncWait(); + if (ignore_key(key)) return; - } #ifdef HAVE_GETMOUSE if (key == KEY_MOUSE) { @@ -68,39 +59,38 @@ do_mouse_event({event.x, event.y}, event.bstate); end_input_event(); - AsyncWait(); return; } #endif Command cmd = translate_key(key); - if (cmd == Command::NONE) { - AsyncWait(); + if (cmd == Command::NONE) return; - } begin_input_event(); - if (!do_input_event(get_io_context(), cmd)) + if (!do_input_event(socket_event.GetEventLoop(), cmd)) return; end_input_event(); - AsyncWait(); + return; } -AsyncUserInput::AsyncUserInput(boost::asio::io_service &io_service, WINDOW &_w) - :UserInput(io_service), w(_w) +AsyncUserInput::AsyncUserInput(EventLoop &event_loop, WINDOW &_w) noexcept + :socket_event(event_loop, BIND_THIS_METHOD(OnSocketReady), + FileDescriptor{STDIN_FILENO}), + w(_w) { - AsyncWait(); + socket_event.ScheduleRead(); } void -keyboard_unread(boost::asio::io_service &io_service, int key) +keyboard_unread(EventLoop &event_loop, int key) { if (ignore_key(key)) return; Command cmd = translate_key(key); if (cmd != Command::NONE) - do_input_event(io_service, cmd); + do_input_event(event_loop, cmd); }
View file
ncmpc-0.36.tar.xz/src/AsyncUserInput.hxx -> ncmpc-0.47.tar.xz/src/AsyncUserInput.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,26 +19,23 @@ #ifndef ASYNC_USER_INPUT_HXX #define ASYNC_USER_INPUT_HXX -#include "UserInput.hxx" +#include "event/PipeEvent.hxx" #include <curses.h> -class AsyncUserInput : public UserInput { +class AsyncUserInput { + PipeEvent socket_event; + WINDOW &w; public: - AsyncUserInput(boost::asio::io_service &io_service, WINDOW &_w); + AsyncUserInput(EventLoop &event_loop, WINDOW &_w) noexcept; private: - void AsyncWait() { - UserInput::AsyncWait(std::bind(&AsyncUserInput::OnReadable, this, - std::placeholders::_1)); - } - - void OnReadable(const boost::system::error_code &error); + void OnSocketReady(unsigned flags) noexcept; }; void -keyboard_unread(boost::asio::io_service &io_service, int key); +keyboard_unread(EventLoop &event_loop, int key); #endif
View file
ncmpc-0.36.tar.xz/src/BasicColors.cxx -> ncmpc-0.47.tar.xz/src/BasicColors.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/BasicColors.hxx -> ncmpc-0.47.tar.xz/src/BasicColors.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,14 +19,12 @@ #ifndef BASIC_COLORS_HXX #define BASIC_COLORS_HXX -#include "util/Compiler.h" - /** * Parse an ncurses color name. * * @return the COLOR_* integer value or -1 on error */ -gcc_pure +gnu::pure short ParseBasicColorName(const char *name) noexcept; @@ -36,7 +33,7 @@ * * @return the color integer value or -1 on error */ -gcc_pure +gnu::pure short ParseColorNameOrNumber(const char *s) noexcept;
View file
ncmpc-0.36.tar.xz/src/BasicMarquee.cxx -> ncmpc-0.47.tar.xz/src/BasicMarquee.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/BasicMarquee.hxx -> ncmpc-0.47.tar.xz/src/BasicMarquee.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,16 +19,12 @@ #ifndef BASIC_MARQUEE_HXX #define BASIC_MARQUEE_HXX -#include "util/Compiler.h" - #include <string> #include <utility> /** * This class is used to auto-scroll text which does not fit on the - * screen. Call hscroll_init() to initialize the object, - * hscroll_clear() to free resources, and hscroll_set() to begin - * scrolling. + * screen. Call Set() to begin scrolling. */ class BasicMarquee { const char *const separator; @@ -92,7 +87,7 @@ offset = 0; } - gcc_pure + gnu::pure std::pair<const char *, size_t> ScrollString() const noexcept; };
View file
ncmpc-0.36.tar.xz/src/Bindings.cxx -> ncmpc-0.47.tar.xz/src/Bindings.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/Bindings.hxx -> ncmpc-0.47.tar.xz/src/Bindings.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -22,7 +21,6 @@ #include "config.h" // IWYU pragma: keep #include "Command.hxx" -#include "util/Compiler.h" #include <array> #include <algorithm> @@ -46,12 +44,12 @@ constexpr KeyBinding(int a, int b=0, int c=0) noexcept :keys{{a, b, c}} {} - gcc_pure + gnu::pure bool HasKey(int key) const noexcept { return std::find(keys.begin(), keys.end(), key) != keys.end(); } - gcc_pure + gnu::pure size_t GetKeyCount() const noexcept { return std::distance(keys.begin(), std::find(keys.begin(), keys.end(), 0)); @@ -73,17 +71,17 @@ struct KeyBindings { std::array<KeyBinding, size_t(Command::NONE)> key_bindings; - gcc_pure + gnu::pure Command FindKey(int key) const noexcept; /** * Returns the name of the first key bound to the given * command, or nullptr if there is no key binding. */ - gcc_pure + gnu::pure const char *GetFirstKeyName(Command command) const noexcept; - gcc_pure + gnu::pure std::string GetKeyNames(Command command) const noexcept; void SetKey(Command command,
View file
ncmpc-0.36.tar.xz/src/ChatPage.cxx -> ncmpc-0.47.tar.xz/src/ChatPage.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -50,7 +49,7 @@ void ProcessMessage(const struct mpd_message &message); - gcc_pure + gnu::pure const std::string &GetPrefix() noexcept; void SendMessage(struct mpdclient &c, const char *msg) noexcept;
View file
ncmpc-0.36.tar.xz/src/ChatPage.hxx -> ncmpc-0.47.tar.xz/src/ChatPage.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/Command.cxx -> ncmpc-0.47.tar.xz/src/Command.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -19,7 +18,8 @@ #include "Command.hxx" #include "i18n.h" -#include "util/Macros.hxx" + +#include <iterator> #include <string.h> @@ -185,6 +185,10 @@ { "search-mode", N_("Change search mode") }, #endif +#ifdef ENABLE_PLAYLIST_EDITOR + { "playlist-editor-page", + N_("Playlist editor") }, +#endif #ifdef ENABLE_SONG_SCREEN { "view", N_("View the selected and the currently playing song") }, @@ -198,8 +202,8 @@ N_("Interrupt action") }, { "lyrics-update", N_("Update Lyrics") }, - /* this command may move out of #ifdef ENABLE_LYRICS_SCREEN - at some point */ +#endif +#if defined(ENABLE_LYRICS_SCREEN) || defined(ENABLE_PLAYLIST_EDITOR) { "edit", N_("Edit the current item") }, #endif @@ -215,7 +219,7 @@ #endif }; -static_assert(ARRAY_SIZE(cmds) == size_t(Command::NONE), +static_assert(std::size(cmds) == size_t(Command::NONE), "Wrong command table size"); const command_definition_t *
View file
ncmpc-0.36.tar.xz/src/Command.hxx -> ncmpc-0.47.tar.xz/src/Command.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -21,7 +20,6 @@ #define COMMAND_H #include "config.h" -#include "util/Compiler.h" #include <stddef.h> @@ -111,6 +109,9 @@ SCREEN_SEARCH, SEARCH_MODE, #endif +#ifdef ENABLE_PLAYLIST_EDITOR + PLAYLIST_EDITOR_PAGE, +#endif #ifdef ENABLE_SONG_SCREEN SCREEN_SONG, #endif @@ -118,6 +119,8 @@ SCREEN_LYRICS, INTERRUPT, LYRICS_UPDATE, +#endif +#if defined(ENABLE_LYRICS_SCREEN) || defined(ENABLE_PLAYLIST_EDITOR) EDIT, #endif #ifdef ENABLE_OUTPUTS_SCREEN @@ -138,17 +141,17 @@ const command_definition_t * get_command_definitions(); -gcc_const +gnu::const size_t get_cmds_max_name_width(); -gcc_pure +gnu::pure const char *get_key_description(Command command); -gcc_pure +gnu::pure const char *get_key_command_name(Command command); -gcc_pure +gnu::pure Command get_key_command_from_name(const char *name);
View file
ncmpc-0.36.tar.xz/src/Completion.cxx -> ncmpc-0.47.tar.xz/src/Completion.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/Completion.hxx -> ncmpc-0.47.tar.xz/src/Completion.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/ConfigFile.cxx -> ncmpc-0.47.tar.xz/src/ConfigFile.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -22,7 +21,6 @@ #include "config.h" #include "Options.hxx" #include "io/Path.hxx" -#include "util/Compiler.h" #include <sys/stat.h> @@ -40,7 +38,7 @@ #define KEYS_FILENAME "keys" #endif -gcc_pure +gnu::pure static bool IsFile(const char *path) noexcept { @@ -98,7 +96,7 @@ #ifndef _WIN32 -gcc_pure +gnu::pure static std::string GetHomeKeysPath() noexcept { @@ -111,7 +109,7 @@ #endif -gcc_pure +gnu::pure static std::string GetUserKeysPath() noexcept { @@ -122,7 +120,7 @@ return BuildPath(dir, PACKAGE, KEYS_FILENAME); } -gcc_pure +gnu::pure static std::string GetSystemKeysPath() noexcept {
View file
ncmpc-0.36.tar.xz/src/ConfigFile.hxx -> ncmpc-0.47.tar.xz/src/ConfigFile.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/ConfigParser.cxx -> ncmpc-0.47.tar.xz/src/ConfigParser.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -32,7 +31,6 @@ #include "PageMeta.hxx" #include "Options.hxx" #include "util/CharUtil.hxx" -#include "util/Compiler.h" #include "util/PrintException.hxx" #include "util/RuntimeError.hxx" #include "util/ScopeExit.hxx" @@ -98,7 +96,7 @@ #define CONF_CHAT_PREFIX "chat-prefix" #define CONF_SECOND_COLUMN "second-column" -gcc_pure +gnu::pure static bool str2bool(char *str) noexcept { @@ -175,7 +173,7 @@ size_t i = 0; const char *p = str; - std::array<int, MAX_COMMAND_KEYS> keys{0}; + std::array<int, MAX_COMMAND_KEYS> keys{}; while (i < MAX_COMMAND_KEYS && *p != 0) { keysi++ = parse_key_value(p, &p); while (*p==',' || *p==' ' || *p=='\t') @@ -188,14 +186,16 @@ /** * Throws on error. */ -static bool -parse_timedisplay_type(const char *str) +static CurrentTimeDisplay +ParseCurrentTimeDisplay(const char *str) { if (strcmp(str, "elapsed") == 0) - return false; + return CurrentTimeDisplay::ELAPSED; else if (strcmp(str, "remaining") == 0) - return true; - else { + return CurrentTimeDisplay::REMAINING; + else if (strcmp(str, "none") == 0) + return CurrentTimeDisplay::NONE; + else throw FormatRuntimeError("%s: %s", /* translators: ncmpc supports displaying the @@ -206,8 +206,6 @@ contained an invalid setting */ _("Bad time display type"), str); - return false; - } } #ifdef ENABLE_COLORS @@ -494,7 +492,7 @@ options.visible_bitrate = str2bool(value); /* timer display type */ else if (!strcasecmp(CONF_TIMEDISPLAY_TYPE, name)) - options.display_remaining_time = parse_timedisplay_type(value); + options.current_time_display = ParseCurrentTimeDisplay(value); /* color definition */ else if (!strcasecmp(CONF_COLOR_DEFINITION, name)) #ifdef ENABLE_COLORS
View file
ncmpc-0.36.tar.xz/src/ConfigParser.hxx -> ncmpc-0.47.tar.xz/src/ConfigParser.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/CustomColors.cxx -> ncmpc-0.47.tar.xz/src/CustomColors.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/CustomColors.hxx -> ncmpc-0.47.tar.xz/src/CustomColors.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/DelayedSeek.cxx -> ncmpc-0.47.tar.xz/src/DelayedSeek.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -42,25 +41,19 @@ void DelayedSeek::Cancel() noexcept { - commit_timer.cancel(); + commit_timer.Cancel(); } void -DelayedSeek::OnTimer(const boost::system::error_code &error) noexcept +DelayedSeek::OnTimer() noexcept { - if (error) - return; - Commit(); } void DelayedSeek::ScheduleTimer() noexcept { - boost::system::error_code error; - commit_timer.expires_from_now(std::chrono::milliseconds(500), error); - commit_timer.async_wait(std::bind(&DelayedSeek::OnTimer, - this, std::placeholders::_1)); + commit_timer.Schedule(std::chrono::milliseconds(500)); } bool
View file
ncmpc-0.36.tar.xz/src/DelayedSeek.hxx -> ncmpc-0.47.tar.xz/src/DelayedSeek.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,9 +19,7 @@ #ifndef NCMPC_DELAYED_SEEK_HXX #define NCMPC_DELAYED_SEEK_HXX -#include "AsioServiceFwd.hxx" - -#include <boost/asio/steady_timer.hpp> +#include "event/CoarseTimerEvent.hxx" struct mpdclient; @@ -36,12 +33,12 @@ int id = -1; unsigned time; - boost::asio::steady_timer commit_timer; + CoarseTimerEvent commit_timer; public: - DelayedSeek(boost::asio::io_service &io_service, + DelayedSeek(EventLoop &event_loop, struct mpdclient &_c) noexcept - :c(_c), commit_timer(io_service) {} + :c(_c), commit_timer(event_loop, BIND_THIS_METHOD(OnTimer)) {} ~DelayedSeek() noexcept { Cancel(); @@ -61,7 +58,7 @@ void Cancel() noexcept; private: - void OnTimer(const boost::system::error_code &error) noexcept; + void OnTimer() noexcept; void ScheduleTimer() noexcept; };
View file
ncmpc-0.47.tar.xz/src/Deleter.hxx
Added
@@ -0,0 +1,40 @@ +/* ncmpc (Ncurses MPD Client) + * Copyright 2004-2021 The Music Player Daemon Project + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef DELETER_HXX +#define DELETER_HXX + +#include <mpd/client.h> + +struct LibmpdclientDeleter { + void operator()(struct mpd_song *song) const noexcept { + mpd_song_free(song); + } + + void operator()(struct mpd_output *o) const noexcept { + mpd_output_free(o); + } + +#if LIBMPDCLIENT_CHECK_VERSION(2,17,0) + void operator()(struct mpd_partition *o) const noexcept { + mpd_partition_free(o); + } +#endif +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/EditPlaylistPage.cxx
Added
@@ -0,0 +1,325 @@ +/* ncmpc (Ncurses MPD Client) + * Copyright 2004-2021 The Music Player Daemon Project + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "EditPlaylistPage.hxx" +#include "PageMeta.hxx" +#include "FileListPage.hxx" +#include "filelist.hxx" +#include "SongPtr.hxx" +#include "config.h" +#include "i18n.h" +#include "Command.hxx" +#include "Options.hxx" +#include "mpdclient.hxx" +#include "screen.hxx" + +#include <mpd/client.h> + +#include <string> + +static std::string next_playlist_name; + +class EditPlaylistPage final : public FileListPage { + std::string name; + + SongPtr selected_song; + +public: + EditPlaylistPage(ScreenManager &_screen, WINDOW *w, Size size) noexcept + :FileListPage(_screen, w, size, + options.list_format.c_str()) + { + } + +private: + void Reload(struct mpdclient &c); + + void SaveSelection() noexcept; + void RestoreSelection() noexcept; + + bool HandleDelete(struct mpdclient &c); + bool HandleMoveUp(struct mpdclient &c); + bool HandleMoveDown(struct mpdclient &c); + +public: + /* virtual methods from class Page */ + void Update(struct mpdclient &c, unsigned events) noexcept override; + bool OnCommand(struct mpdclient &c, Command cmd) override; + +#ifdef HAVE_GETMOUSE + bool OnMouse(struct mpdclient &c, Point p, mmask_t bstate) override; +#endif + + const char *GetTitle(char *s, size_t size) const noexcept override; +}; + +static bool +LoadPlaylist(struct mpdclient &c, const char *name, FileList &l) +{ + auto *connection = c.GetConnection(); + if (connection == nullptr) + return false; + + mpd_send_list_playlist_meta(connection, name); + l.Receive(*connection); + return c.FinishCommand(); +} + +static struct std::unique_ptr<FileList> +LoadPlaylist(struct mpdclient &c, const std::string &name) +{ + auto l = std::make_unique<FileList>(); + if (!name.empty()) + LoadPlaylist(c, name.c_str(), *l); + + return l; +} + +void +EditPlaylistPage::Reload(struct mpdclient &c) +{ + filelist = LoadPlaylist(c, name.c_str()); + lw.SetLength(filelist->size()); + SetDirty(); +} + +void +EditPlaylistPage::SaveSelection() noexcept +{ + const auto *song = GetSelectedSong(); + selected_song.reset(song != nullptr + ? mpd_song_dup(song) + : nullptr); +} + +void +EditPlaylistPage::RestoreSelection() noexcept +{ + if (!filelist || !selected_song) + /* there was no selection */ + return; + + int i = filelist->FindSong(*selected_song); + if (i >= 0) + lw.SetCursor(i); + + SaveSelection(); +} + +static std::unique_ptr<Page> +edit_playlist_page_init(ScreenManager &_screen, WINDOW *w, Size size) +{ + return std::make_unique<EditPlaylistPage>(_screen, w, size); +} + +const char * +EditPlaylistPage::GetTitle(char *str, size_t size) const noexcept +{ + if (name.empty()) + return _("Playlist"); + + snprintf(str, size, "%s: %s", _("Playlist"), name.c_str()); + return str; +} + +void +EditPlaylistPage::Update(struct mpdclient &c, unsigned events) noexcept +{ + bool need_reload = events & MPD_IDLE_STORED_PLAYLIST; + + if (!next_playlist_name.empty()) { + if (next_playlist_name != name) { + lw.SetCursor(0); + selected_song.reset(); + name = std::move(next_playlist_name); + need_reload = true; + } + + next_playlist_name.clear(); + } + + if (need_reload) { + Reload(c); + RestoreSelection(); + } +} + +#ifdef HAVE_GETMOUSE +bool +EditPlaylistPage::OnMouse(struct mpdclient &c, Point p, mmask_t bstate) +{ + if (FileListPage::OnMouse(c, p, bstate)) + return true; + + if (bstate & BUTTON1_DOUBLE_CLICKED) { + /* stop */ + + auto *connection = c.GetConnection(); + if (connection != nullptr && + !mpd_run_stop(connection)) + c.HandleError(); + return true; + } + + const unsigned old_selected = lw.GetCursorIndex(); + lw.SetCursorFromOrigin(p.y); + + if (bstate & BUTTON3_CLICKED) { + /* delete */ + if (lw.GetCursorIndex() == old_selected) { + auto *connection = c.GetConnection(); + if (connection != nullptr && + !mpd_run_playlist_delete(connection, name.c_str(), + lw.GetCursorIndex())) + c.HandleError(); + } + } + + SaveSelection(); + SetDirty(); + + return true; +} +#endif + +inline bool +EditPlaylistPage::HandleDelete(struct mpdclient &c) +{ + const auto range = lw.GetRange(); + if (range.empty()) + return true; + + auto *connection = c.GetConnection(); + if (connection == nullptr) + return true; + + mpd_command_list_begin(connection, false); + + for (unsigned i = range.end_index; i > range.start_index; --i) + mpd_send_playlist_delete(connection, name.c_str(), i - 1); + + if (!mpd_command_list_end(connection) || + !mpd_response_finish(connection)) + c.HandleError(); + + lw.SetCursor(range.start_index); + + return true; +} + +#if LIBMPDCLIENT_CHECK_VERSION(2,19,0) + +inline bool +EditPlaylistPage::HandleMoveUp(struct mpdclient &c) +{ + const auto range = lw.GetRange(); + if (range.start_index == 0 || range.empty()) + return false; + + auto *connection = c.GetConnection(); + if (connection == nullptr) + return true; + + SaveSelection(); + + if (mpd_run_playlist_move(connection, name.c_str(), + range.start_index - 1, range.end_index - 1)) + lw.SelectionMovedUp(); + else + c.HandleError(); + + return true; +} + +inline bool +EditPlaylistPage::HandleMoveDown(struct mpdclient &c) +{ + const auto range = lw.GetRange(); + if (range.end_index >= lw.GetLength()) + return false; + + auto *connection = c.GetConnection(); + if (connection == nullptr) + return true; + + SaveSelection(); + + if (mpd_run_playlist_move(connection, name.c_str(), + range.end_index, range.start_index)) + lw.SelectionMovedDown(); + else + c.HandleError(); + + return true; +} + +#endif + +bool +EditPlaylistPage::OnCommand(struct mpdclient &c, Command cmd) +{ + if (FileListPage::OnCommand(c, cmd)) { + SaveSelection(); + return true; + } + + if (!c.IsConnected()) + return false; + + switch (cmd) { + case Command::DELETE: + return HandleDelete(c); + + case Command::SAVE_PLAYLIST: + //playlist_save(&c, nullptr, nullptr); + // TODO + return true; + + case Command::SHUFFLE: + // TODO + return true; + +#if LIBMPDCLIENT_CHECK_VERSION(2,19,0) + case Command::LIST_MOVE_UP: + return HandleMoveUp(c); + + case Command::LIST_MOVE_DOWN: + return HandleMoveDown(c); +#endif + + default: + break; + } + + return false; +} + +const PageMeta edit_playlist_page = { + "playlist_editor", + N_("Playlist Editor"), + Command::PLAYLIST_EDITOR_PAGE, + edit_playlist_page_init, +}; + +void +EditPlaylist(ScreenManager &_screen, struct mpdclient &c, + const char *name) noexcept +{ + next_playlist_name = name; + _screen.Switch(edit_playlist_page, c); +}
View file
ncmpc-0.47.tar.xz/src/EditPlaylistPage.hxx
Added
@@ -0,0 +1,31 @@ +/* ncmpc (Ncurses MPD Client) + * Copyright 2004-2021 The Music Player Daemon Project + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef NCMPC_EDIT_PLAYLIST_PAGE_HXX +#define NCMPC_EDIT_PLAYLIST_PAGE_HXX + +struct PageMeta; +class ScreenManager; + +extern const PageMeta edit_playlist_page; + +void +EditPlaylist(ScreenManager &_screen, struct mpdclient &c, + const char *name) noexcept; + +#endif
View file
ncmpc-0.36.tar.xz/src/FileBrowserPage.cxx -> ncmpc-0.47.tar.xz/src/FileBrowserPage.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -46,34 +45,39 @@ public: FileBrowserPage(ScreenManager &_screen, WINDOW *_w, - Size size) + Size size) noexcept :FileListPage(_screen, _w, size, options.list_format.c_str()) {} - bool GotoSong(struct mpdclient &c, const struct mpd_song &song); + bool GotoSong(struct mpdclient &c, const struct mpd_song &song) noexcept; private: - void Reload(struct mpdclient &c); + void Reload(struct mpdclient &c) noexcept; /** * Change to the specified absolute directory. */ - bool ChangeDirectory(struct mpdclient &c, std::string &&new_path); + bool ChangeDirectory(struct mpdclient &c, + std::string_view new_path) noexcept; /** * Change to the parent directory of the current directory. */ - bool ChangeToParent(struct mpdclient &c); + bool ChangeToParent(struct mpdclient &c) noexcept; /** * Change to the directory referred by the specified * #FileListEntry object. */ - bool ChangeToEntry(struct mpdclient &c, const FileListEntry &entry); + bool ChangeToEntry(struct mpdclient &c, + const FileListEntry &entry) noexcept; - bool HandleEnter(struct mpdclient &c); - void HandleSave(struct mpdclient &c); - void HandleDelete(struct mpdclient &c); +protected: + bool HandleEnter(struct mpdclient &c) override; + +private: + void HandleSave(struct mpdclient &c) noexcept; + void HandleDelete(struct mpdclient &c) noexcept; public: /* virtual methods from class Page */ @@ -84,30 +88,28 @@ static void screen_file_load_list(struct mpdclient *c, const char *current_path, - FileList *filelist) + FileList &filelist) noexcept { auto *connection = c->GetConnection(); if (connection == nullptr) return; mpd_send_list_meta(connection, current_path); - filelist->Receive(*connection); + filelist.Receive(*connection); if (c->FinishCommand()) - filelist->Sort(); + filelist.Sort(); } void -FileBrowserPage::Reload(struct mpdclient &c) +FileBrowserPage::Reload(struct mpdclient &c) noexcept { - delete filelist; - - filelist = new FileList(); + filelist = std::make_unique<FileList>(); if (!current_path.empty()) /* add a dummy entry for ./.. */ filelist->emplace_back(nullptr); - screen_file_load_list(&c, current_path.c_str(), filelist); + screen_file_load_list(&c, current_path.c_str(), *filelist); lw.SetLength(filelist->size()); @@ -115,13 +117,14 @@ } bool -FileBrowserPage::ChangeDirectory(struct mpdclient &c, std::string &&new_path) +FileBrowserPage::ChangeDirectory(struct mpdclient &c, + std::string_view new_path) noexcept { - current_path = std::move(new_path); + current_path = new_path; Reload(c); - screen_browser_sync_highlights(filelist, &c.playlist); + screen_browser_sync_highlights(*filelist, c.playlist); lw.Reset(); @@ -129,12 +132,11 @@ } bool -FileBrowserPage::ChangeToParent(struct mpdclient &c) +FileBrowserPage::ChangeToParent(struct mpdclient &c) noexcept { - auto parent = GetParentUri(current_path.c_str()); const auto old_path = std::move(current_path); - bool success = ChangeDirectory(c, std::move(parent)); + bool success = ChangeDirectory(c, GetParentUri(old_path)); int idx = success ? filelist->FindDirectory(old_path.c_str()) @@ -154,7 +156,8 @@ * object. */ bool -FileBrowserPage::ChangeToEntry(struct mpdclient &c, const FileListEntry &entry) +FileBrowserPage::ChangeToEntry(struct mpdclient &c, + const FileListEntry &entry) noexcept { if (entry.entity == nullptr) return ChangeToParent(c); @@ -165,7 +168,7 @@ } bool -FileBrowserPage::GotoSong(struct mpdclient &c, const struct mpd_song &song) +FileBrowserPage::GotoSong(struct mpdclient &c, const struct mpd_song &song) noexcept { const char *uri = mpd_song_get_uri(&song); if (strstr(uri, "//") != nullptr) @@ -192,14 +195,14 @@ FileBrowserPage::HandleEnter(struct mpdclient &c) { const auto *entry = GetSelectedEntry(); - if (entry == nullptr) - return false; + if (entry != nullptr && ChangeToEntry(c, *entry)) + return true; - return ChangeToEntry(c, *entry); + return FileListPage::HandleEnter(c); } void -FileBrowserPage::HandleSave(struct mpdclient &c) +FileBrowserPage::HandleSave(struct mpdclient &c) noexcept { const char *defaultname = nullptr; @@ -226,7 +229,7 @@ } void -FileBrowserPage::HandleDelete(struct mpdclient &c) +FileBrowserPage::HandleDelete(struct mpdclient &c) noexcept { auto *connection = c.GetConnection(); @@ -276,7 +279,7 @@ } static std::unique_ptr<Page> -screen_file_init(ScreenManager &_screen, WINDOW *w, Size size) +screen_file_init(ScreenManager &_screen, WINDOW *w, Size size) noexcept { return std::make_unique<FileBrowserPage>(_screen, w, size); } @@ -315,7 +318,7 @@ | MPD_IDLE_QUEUE #endif )) { - screen_browser_sync_highlights(filelist, &c.playlist); + screen_browser_sync_highlights(*filelist, c.playlist); SetDirty(); } } @@ -324,12 +327,6 @@ FileBrowserPage::OnCommand(struct mpdclient &c, Command cmd) { switch(cmd) { - case Command::PLAY: - if (HandleEnter(c)) - return true; - - break; - case Command::GO_ROOT_DIRECTORY: ChangeDirectory(c, {}); return true; @@ -345,7 +342,7 @@ case Command::SCREEN_UPDATE: Reload(c); - screen_browser_sync_highlights(filelist, &c.playlist); + screen_browser_sync_highlights(*filelist, c.playlist); return false; default: @@ -387,7 +384,7 @@ bool screen_file_goto_song(ScreenManager &_screen, struct mpdclient &c, - const struct mpd_song &song) + const struct mpd_song &song) noexcept { auto pi = _screen.MakePage(screen_browse); auto &page = (FileBrowserPage &)*pi->second;
View file
ncmpc-0.36.tar.xz/src/FileBrowserPage.hxx -> ncmpc-0.47.tar.xz/src/FileBrowserPage.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -29,6 +28,6 @@ bool screen_file_goto_song(ScreenManager &_screen, struct mpdclient &c, - const struct mpd_song &song); + const struct mpd_song &song) noexcept; #endif
View file
ncmpc-0.36.tar.xz/src/FileListPage.cxx -> ncmpc-0.47.tar.xz/src/FileListPage.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -21,6 +20,7 @@ #include "FileListPage.hxx" #include "FileBrowserPage.hxx" #include "SongPage.hxx" +#include "EditPlaylistPage.hxx" #include "LyricsPage.hxx" #include "Command.hxx" #include "screen_status.hxx" @@ -45,28 +45,34 @@ #define BUFSIZE 1024 #ifndef NCMPC_MINI -#define HIGHLIGHT (0x01) +static constexpr unsigned HIGHLIGHT = 0x01; #endif -FileListPage::~FileListPage() noexcept +FileListPage::FileListPage(ScreenManager &_screen, WINDOW *_w, + Size size, + const char *_song_format) noexcept + :ListPage(_w, size), + screen(_screen), + song_format(_song_format) { - delete filelist; } +FileListPage::~FileListPage() noexcept = default; + #ifndef NCMPC_MINI /* sync highlight flags with playlist */ void -screen_browser_sync_highlights(FileList *fl, const MpdQueue *playlist) +screen_browser_sync_highlights(FileList &fl, const MpdQueue &playlist) noexcept { - for (unsigned i = 0; i < fl->size(); ++i) { - auto &entry = (*fl)i; + for (unsigned i = 0; i < fl.size(); ++i) { + auto &entry = fli; const auto *entity = entry.entity; if (entity != nullptr && mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) { const auto *song = mpd_entity_get_song(entity); - if (playlist->ContainsUri(mpd_song_get_uri(song))) + if (playlist.ContainsUri(mpd_song_get_uri(song))) entry.flags |= HIGHLIGHT; else entry.flags &= ~HIGHLIGHT; @@ -168,7 +174,7 @@ } FileListEntry * -FileListPage::GetSelectedEntry() const +FileListPage::GetSelectedEntry() const noexcept { const auto range = lw.GetRange(); @@ -182,7 +188,7 @@ } const struct mpd_entity * -FileListPage::GetSelectedEntity() const +FileListPage::GetSelectedEntity() const noexcept { const auto *entry = GetSelectedEntry(); @@ -192,7 +198,7 @@ } const struct mpd_song * -FileListPage::GetSelectedSong() const +FileListPage::GetSelectedSong() const noexcept { const auto *entity = GetSelectedEntity(); @@ -203,7 +209,7 @@ } FileListEntry * -FileListPage::GetIndex(unsigned i) const +FileListPage::GetIndex(unsigned i) const noexcept { if (filelist == nullptr || i >= filelist->size()) return nullptr; @@ -230,40 +236,39 @@ } static bool -browser_select_entry(struct mpdclient *c, FileListEntry *entry, - gcc_unused bool toggle) +browser_select_entry(struct mpdclient &c, FileListEntry &entry, + maybe_unused bool toggle) noexcept { - assert(entry != nullptr); - assert(entry->entity != nullptr); + assert(entry.entity != nullptr); - if (mpd_entity_get_type(entry->entity) == MPD_ENTITY_TYPE_PLAYLIST) - return load_playlist(c, mpd_entity_get_playlist(entry->entity)); + if (mpd_entity_get_type(entry.entity) == MPD_ENTITY_TYPE_PLAYLIST) + return load_playlist(&c, mpd_entity_get_playlist(entry.entity)); - if (mpd_entity_get_type(entry->entity) == MPD_ENTITY_TYPE_DIRECTORY) { - const auto *dir = mpd_entity_get_directory(entry->entity); + if (mpd_entity_get_type(entry.entity) == MPD_ENTITY_TYPE_DIRECTORY) { + const auto *dir = mpd_entity_get_directory(entry.entity); - if (mpdclient_cmd_add_path(c, mpd_directory_get_path(dir))) { - screen_status_printf(_("Adding \'%s\' to queue"), - Utf8ToLocale(mpd_directory_get_path(dir)).c_str()); - } + if (!mpdclient_cmd_add_path(&c, mpd_directory_get_path(dir))) + return false; + screen_status_printf(_("Adding \'%s\' to queue"), + Utf8ToLocale(mpd_directory_get_path(dir)).c_str()); return true; } - if (mpd_entity_get_type(entry->entity) != MPD_ENTITY_TYPE_SONG) + if (mpd_entity_get_type(entry.entity) != MPD_ENTITY_TYPE_SONG) return false; #ifndef NCMPC_MINI - if (!toggle || (entry->flags & HIGHLIGHT) == 0) + if (!toggle || (entry.flags & HIGHLIGHT) == 0) #endif { - const auto *song = mpd_entity_get_song(entry->entity); + const auto *song = mpd_entity_get_song(entry.entity); #ifndef NCMPC_MINI - entry->flags |= HIGHLIGHT; + entry.flags |= HIGHLIGHT; #endif - if (c->RunAdd(*song)) { + if (c.RunAdd(*song)) { char bufBUFSIZE; strfsong(buf, BUFSIZE, @@ -273,21 +278,21 @@ #ifndef NCMPC_MINI } else { /* remove song from playlist */ - const auto *song = mpd_entity_get_song(entry->entity); + const auto *song = mpd_entity_get_song(entry.entity); int idx; - entry->flags &= ~HIGHLIGHT; + entry.flags &= ~HIGHLIGHT; - while ((idx = c->playlist.FindByUri(mpd_song_get_uri(song))) >= 0) - c->RunDelete(idx); + while ((idx = c.playlist.FindByUri(mpd_song_get_uri(song))) >= 0) + c.RunDelete(idx); #endif } return true; } -bool -FileListPage::HandleSelect(struct mpdclient &c) +inline bool +FileListPage::HandleSelect(struct mpdclient &c) noexcept { bool success = false; @@ -295,7 +300,7 @@ for (const unsigned i : range) { auto *entry = GetIndex(i); if (entry != nullptr && entry->entity != nullptr) - success = browser_select_entry(&c, entry, true); + success = browser_select_entry(c, *entry, true); } SetDirty(); @@ -303,8 +308,8 @@ return range.end_index == range.start_index + 1 && success; } -bool -FileListPage::HandleAdd(struct mpdclient &c) +inline bool +FileListPage::HandleAdd(struct mpdclient &c) noexcept { bool success = false; @@ -312,15 +317,34 @@ for (const unsigned i : range) { auto *entry = GetIndex(i); if (entry != nullptr && entry->entity != nullptr) - success = browser_select_entry(&c, entry, false) || + success = browser_select_entry(c, *entry, false) || success; } return range.end_index == range.start_index + 1 && success; } -void -FileListPage::HandleSelectAll(struct mpdclient &c) +#ifdef ENABLE_PLAYLIST_EDITOR + +inline bool +FileListPage::HandleEdit(struct mpdclient &c) noexcept +{ + const auto *entity = GetSelectedEntity(); + if (entity == nullptr || + mpd_entity_get_type(entity) != MPD_ENTITY_TYPE_PLAYLIST) + return false; + + const auto *playlist = mpd_entity_get_playlist(entity); + assert(playlist != nullptr); + + EditPlaylist(screen, c, mpd_playlist_get_path(playlist)); + return true; +} + +#endif + +inline void +FileListPage::HandleSelectAll(struct mpdclient &c) noexcept { if (filelist == nullptr) return; @@ -329,7 +353,7 @@ auto &entry = (*filelist)i; if (entry.entity != nullptr) - browser_select_entry(&c, &entry, false); + browser_select_entry(c, entry, false); } SetDirty(); @@ -348,14 +372,18 @@ lw.SetCursorFromOrigin(p.y); - if( bstate & BUTTON1_CLICKED ) { - if (prev_selected == lw.GetCursorIndex()) + if (bstate & (BUTTON1_CLICKED|BUTTON1_DOUBLE_CLICKED)) { + if ((bstate & BUTTON1_DOUBLE_CLICKED) || + prev_selected == lw.GetCursorIndex()) HandleEnter(c); - } else if (bstate & BUTTON3_CLICKED) { - if (prev_selected == lw.GetCursorIndex()) + } else if (bstate & (BUTTON3_CLICKED|BUTTON3_DOUBLE_CLICKED)) { + if ((bstate & BUTTON3_DOUBLE_CLICKED) || + prev_selected == lw.GetCursorIndex()) HandleSelect(c); } + SetDirty(); + return true; } @@ -371,10 +399,6 @@ return true; switch (cmd) { -#if defined(ENABLE_SONG_SCREEN) || defined(ENABLE_LYRICS_SCREEN) - const struct mpd_song *song; -#endif - case Command::LIST_FIND: case Command::LIST_RFIND: case Command::LIST_FIND_NEXT: @@ -389,22 +413,22 @@ #ifdef ENABLE_SONG_SCREEN case Command::SCREEN_SONG: - song = GetSelectedSong(); - if (song == nullptr) + if (const auto *song = GetSelectedSong()) { + screen_song_switch(screen, c, *song); + return true; + } else return false; - screen_song_switch(screen, c, *song); - return true; #endif #ifdef ENABLE_LYRICS_SCREEN case Command::SCREEN_LYRICS: - song = GetSelectedSong(); - if (song == nullptr) + if (const auto *song = GetSelectedSong()) { + screen_lyrics_switch(screen, c, *song, false); + return true; + } else return false; - screen_lyrics_switch(screen, c, *song, false); - return true; #endif case Command::SCREEN_SWAP: screen.Swap(c, GetSelectedSong()); @@ -418,8 +442,6 @@ return false; switch (cmd) { - const struct mpd_song *song; - case Command::PLAY: HandleEnter(c); return true; @@ -436,17 +458,24 @@ SetDirty(); return true; +#ifdef ENABLE_PLAYLIST_EDITOR + case Command::EDIT: + if (HandleEdit(c)) + return true; + break; +#endif + case Command::SELECT_ALL: HandleSelectAll(c); return true; case Command::LOCATE: - song = GetSelectedSong(); - if (song == nullptr) + if (const auto *song = GetSelectedSong()) { + screen_file_goto_song(screen, c, *song); + return true; + } else return false; - screen_file_goto_song(screen, c, *song); - return true; default: break; @@ -457,7 +486,7 @@ void screen_browser_paint_directory(WINDOW *w, unsigned width, - bool selected, const char *name) + bool selected, const char *name) noexcept { row_color(w, Style::DIRECTORY, selected); @@ -471,7 +500,7 @@ static void screen_browser_paint_playlist(WINDOW *w, unsigned width, - bool selected, const char *name) + bool selected, const char *name) noexcept { row_paint_text(w, width, Style::PLAYLIST, selected, name); } @@ -494,20 +523,17 @@ #ifndef NCMPC_MINI const bool highlight = (entry.flags & HIGHLIGHT) != 0; #else - const bool highlight = false; + constexpr bool highlight = false; #endif switch (mpd_entity_get_type(entity)) { - const struct mpd_directory *directory; - const struct mpd_playlist *playlist; - const char *name; - - case MPD_ENTITY_TYPE_DIRECTORY: - directory = mpd_entity_get_directory(entity); - name = GetUriFilename(mpd_directory_get_path(directory)); + case MPD_ENTITY_TYPE_DIRECTORY: { + const auto *directory = mpd_entity_get_directory(entity); + const char *name = GetUriFilename(mpd_directory_get_path(directory)); screen_browser_paint_directory(w, width, selected, Utf8ToLocale(name).c_str()); break; + } case MPD_ENTITY_TYPE_SONG: paint_song_row(w, y, width, selected, highlight, @@ -515,12 +541,13 @@ song_format); break; - case MPD_ENTITY_TYPE_PLAYLIST: - playlist = mpd_entity_get_playlist(entity); - name = GetUriFilename(mpd_playlist_get_path(playlist)); + case MPD_ENTITY_TYPE_PLAYLIST: { + const auto *playlist = mpd_entity_get_playlist(entity); + const char *name = GetUriFilename(mpd_playlist_get_path(playlist)); screen_browser_paint_playlist(w, width, selected, Utf8ToLocale(name).c_str()); break; + } default: row_paint_text(w, width, @@ -552,9 +579,11 @@ for (const unsigned i : lw.GetRange()) { assert(i < filelist->size()); const auto &entry = (*filelist)i; + const auto *entity = entry.entity; - if (mpd_entity_get_type(entry.entity) == MPD_ENTITY_TYPE_SONG) - duration += mpd_song_get_duration(mpd_entity_get_song(entry.entity)); + if (entity != nullptr && + mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) + duration += mpd_song_get_duration(mpd_entity_get_song(entity)); } char duration_string32;
View file
ncmpc-0.36.tar.xz/src/FileListPage.hxx -> ncmpc-0.47.tar.xz/src/FileListPage.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -27,6 +26,8 @@ #include <curses.h> +#include <memory> + struct mpdclient; struct MpdQueue; class ScreenManager; @@ -37,41 +38,42 @@ protected: ScreenManager &screen; - FileList *filelist = nullptr; + std::unique_ptr<FileList> filelist; const char *const song_format; public: FileListPage(ScreenManager &_screen, WINDOW *_w, Size size, - const char *_song_format) - :ListPage(_w, size), - screen(_screen), - song_format(_song_format) {} + const char *_song_format) noexcept; ~FileListPage() noexcept override; protected: - gcc_pure - FileListEntry *GetSelectedEntry() const; + gnu::pure + FileListEntry *GetSelectedEntry() const noexcept; + + gnu::pure + const struct mpd_entity *GetSelectedEntity() const noexcept; - gcc_pure - const struct mpd_entity *GetSelectedEntity() const; + gnu::pure + const struct mpd_song *GetSelectedSong() const noexcept; - gcc_pure - const struct mpd_song *GetSelectedSong() const; + gnu::pure + FileListEntry *GetIndex(unsigned i) const noexcept; - FileListEntry *GetIndex(unsigned i) const; +protected: + virtual bool HandleEnter(struct mpdclient &c); private: - bool HandleEnter(struct mpdclient &c); - bool HandleSelect(struct mpdclient &c); - bool HandleAdd(struct mpdclient &c); + bool HandleSelect(struct mpdclient &c) noexcept; + bool HandleAdd(struct mpdclient &c) noexcept; + bool HandleEdit(struct mpdclient &c) noexcept; - void HandleSelectAll(struct mpdclient &c); + void HandleSelectAll(struct mpdclient &c) noexcept; static void PaintRow(WINDOW *w, unsigned i, unsigned y, unsigned width, - bool selected, const void *data); + bool selected, const void *data) noexcept; /* virtual methods from class ListRenderer */ void PaintListItem(WINDOW *w, unsigned i, @@ -97,14 +99,13 @@ #ifndef NCMPC_MINI void -screen_browser_sync_highlights(FileList *fl, - const MpdQueue *playlist); +screen_browser_sync_highlights(FileList &fl, + const MpdQueue &playlist) noexcept; #else static inline void -screen_browser_sync_highlights(gcc_unused FileList *fl, - gcc_unused const MpdQueue *playlist) +screen_browser_sync_highlights(FileList &, const MpdQueue &) noexcept { } @@ -112,6 +113,6 @@ void screen_browser_paint_directory(WINDOW *w, unsigned width, - bool selected, const char *name); + bool selected, const char *name) noexcept; #endif
View file
ncmpc-0.36.tar.xz/src/GlobalBindings.cxx -> ncmpc-0.47.tar.xz/src/GlobalBindings.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -140,6 +139,9 @@ {'5', F5}, {'m'}, #endif +#ifdef ENABLE_PLAYLIST_EDITOR + {C('P')}, +#endif #ifdef ENABLE_SONG_SCREEN {'i'}, #endif @@ -147,6 +149,8 @@ {'7', F7}, {ESC}, {'u'}, +#endif +#if defined(ENABLE_LYRICS_SCREEN) || defined(ENABLE_PLAYLIST_EDITOR) {'e'}, #endif
View file
ncmpc-0.36.tar.xz/src/GlobalBindings.hxx -> ncmpc-0.47.tar.xz/src/GlobalBindings.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,11 +19,9 @@ #ifndef GLOBAL_BINDINGS_HXX #define GLOBAL_BINDINGS_HXX -#include "util/Compiler.h" - struct KeyBindings; -gcc_const +gnu::const KeyBindings & GetGlobalKeyBindings() noexcept;
View file
ncmpc-0.36.tar.xz/src/HelpPage.cxx -> ncmpc-0.47.tar.xz/src/HelpPage.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -28,9 +27,10 @@ #include "GlobalBindings.hxx" #include "config.h" #include "i18n.h" -#include "util/Macros.hxx" #include "util/LocaleString.hxx" +#include <iterator> + #include <assert.h> struct HelpRow { @@ -157,6 +157,9 @@ { Command::PLAY, N_("Enter directory/Select and play song") }, Command::SELECT, Command::ADD, +#ifdef ENABLE_PLAYLIST_EDITOR + Command::EDIT, +#endif Command::SAVE_PLAYLIST, { Command::DELETE, N_("Delete playlist") }, Command::GO_PARENT_DIRECTORY, @@ -223,8 +226,8 @@ public: HelpPage(ScreenManager &_screen, WINDOW *w, Size size) :ListPage(w, size), screen(_screen) { - lw.DisableCursor(); - lw.SetLength(ARRAY_SIZE(help_text)); + lw.HideCursor(); + lw.SetLength(std::size(help_text)); } public: @@ -251,7 +254,7 @@ { const auto *row = &help_texti; - assert(i < ARRAY_SIZE(help_text)); + assert(i < std::size(help_text)); if (row->text != nullptr) return gettext(row->text); @@ -271,13 +274,14 @@ void HelpPage::PaintListItem(WINDOW *w, unsigned i, unsigned y, unsigned width, - gcc_unused bool selected) const noexcept + bool selected) const noexcept { const auto *row = &help_texti; - assert(i < ARRAY_SIZE(help_text)); + assert(i < std::size(help_text)); - row_color(w, row->highlight ? Style::LIST_BOLD : Style::LIST, false); + row_color(w, row->highlight ? Style::LIST_BOLD : Style::LIST, + selected); wclrtoeol(w); @@ -313,10 +317,14 @@ if (ListPage::OnCommand(c, cmd)) return true; - lw.SetCursorFromOrigin(0); + if (!lw.IsCursorVisible()) + /* start searching at the beginning of the page (not + where the invisible cursor just happens to be), + unless the cursor is still visible from the last + search */ + lw.SetCursorFromOrigin(0); + if (screen_find(screen, lw, cmd, *this)) { - /* center the row */ - lw.Center(lw.GetCursorIndex()); SetDirty(); return true; }
View file
ncmpc-0.36.tar.xz/src/HelpPage.hxx -> ncmpc-0.47.tar.xz/src/HelpPage.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/History.hxx -> ncmpc-0.47.tar.xz/src/History.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/Instance.cxx -> ncmpc-0.47.tar.xz/src/Instance.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -19,11 +18,10 @@ #include "Instance.hxx" #include "Options.hxx" +#include "event/SignalMonitor.hxx" #include <signal.h> -#ifdef HAVE_TAG_WHITELIST - #include "strfsong.hxx" #include "TagMask.hxx" @@ -33,6 +31,11 @@ MPD_TAG_TITLE, MPD_TAG_ALBUM, MPD_TAG_COMPOSER, + MPD_TAG_PERFORMER, +#if LIBMPDCLIENT_CHECK_VERSION(2,17,0) + MPD_TAG_CONDUCTOR, + MPD_TAG_WORK, +#endif MPD_TAG_NAME, MPD_TAG_DISC, MPD_TAG_TRACK, @@ -41,42 +44,35 @@ MPD_TAG_COMMENT, }; -#endif - Instance::Instance() - :io_service(), -#ifndef _WIN32 - sigterm(io_service, SIGTERM, SIGINT, SIGHUP), - sigwinch(io_service, SIGWINCH, SIGCONT), -#endif - client(io_service, + :client(event_loop, options.host.empty() ? nullptr : options.host.c_str(), options.port, options.timeout_ms, options.password.empty() ? nullptr : options.password.c_str()), - seek(io_service, client), - reconnect_timer(io_service), - update_timer(io_service), + seek(event_loop, client), + reconnect_timer(event_loop, BIND_THIS_METHOD(OnReconnectTimer)), + update_timer(event_loop, BIND_THIS_METHOD(OnUpdateTimer)), #ifndef NCMPC_MINI - check_key_bindings_timer(io_service), + check_key_bindings_timer(event_loop, BIND_THIS_METHOD(OnCheckKeyBindings)), #endif - screen_manager(io_service), + screen_manager(event_loop), #ifdef ENABLE_LIRC - lirc_input(io_service), + lirc_input(event_loop), #endif - user_input(io_service, *screen_manager.main_window.w) + user_input(event_loop, *screen_manager.main_window.w) { screen_manager.Init(&client); - sigterm.async_wait(this(const auto &, int){ - this->io_service.stop(); - }); - #ifndef _WIN32 - AsyncWaitSigwinch(); + SignalMonitorInit(event_loop); + SignalMonitorRegister(SIGTERM, BIND_THIS_METHOD(Quit)); + SignalMonitorRegister(SIGINT, BIND_THIS_METHOD(Quit)); + SignalMonitorRegister(SIGHUP, BIND_THIS_METHOD(Quit)); + SignalMonitorRegister(SIGWINCH, BIND_THIS_METHOD(OnSigwinch)); + SignalMonitorRegister(SIGCONT, BIND_THIS_METHOD(OnSigwinch)); #endif -#ifdef HAVE_TAG_WHITELIST TagMask tag_mask = global_tag_whitelist; tag_mask |= SongFormatToTagMask(options.list_format.c_str()); tag_mask |= SongFormatToTagMask(options.search_format.c_str()); @@ -86,12 +82,12 @@ #endif client.WhitelistTags(tag_mask); -#endif } Instance::~Instance() { screen_manager.Exit(); + SignalMonitorFinish(); } void @@ -99,5 +95,5 @@ { screen_manager.Update(client, seek); - io_service.run(); + event_loop.Run(); }
View file
ncmpc-0.36.tar.xz/src/Instance.hxx -> ncmpc-0.47.tar.xz/src/Instance.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -25,26 +24,19 @@ #include "mpdclient.hxx" #include "DelayedSeek.hxx" #include "screen.hxx" +#include "event/Loop.hxx" +#include "event/CoarseTimerEvent.hxx" +#include "event/FineTimerEvent.hxx" #ifdef ENABLE_LIRC #include "lirc.hxx" #endif -#include <boost/asio/io_service.hpp> -#include <boost/asio/steady_timer.hpp> -#ifndef _WIN32 -#include <boost/asio/signal_set.hpp> -#endif - /** * A singleton holding global instance variables. */ class Instance { - boost::asio::io_service io_service; - -#ifndef _WIN32 - boost::asio::signal_set sigterm, sigwinch; -#endif + EventLoop event_loop; struct mpdclient client; @@ -55,13 +47,13 @@ * server is broken. It tries to recover by reconnecting * periodically. */ - boost::asio::steady_timer reconnect_timer; + CoarseTimerEvent reconnect_timer; - boost::asio::steady_timer update_timer; + FineTimerEvent update_timer; bool pending_update_timer = false; #ifndef NCMPC_MINI - boost::asio::steady_timer check_key_bindings_timer; + CoarseTimerEvent check_key_bindings_timer; #endif ScreenManager screen_manager; @@ -79,10 +71,6 @@ Instance(const Instance &) = delete; Instance &operator=(const Instance &) = delete; - auto &get_io_service() { - return io_service; - } - auto &GetClient() { return client; } @@ -95,17 +83,17 @@ return screen_manager; } + void Quit() noexcept { + event_loop.Break(); + } + void UpdateClient() noexcept; void Run(); template<typename D> void ScheduleReconnect(const D &expiry_time) { - boost::system::error_code error; - reconnect_timer.expires_from_now(expiry_time, error); - reconnect_timer.async_wait(std::bind(&Instance::OnReconnectTimer, - this, - std::placeholders::_1)); + reconnect_timer.Schedule(expiry_time); } void EnableUpdateTimer() noexcept { @@ -116,44 +104,33 @@ void DisableUpdateTimer() noexcept { if (pending_update_timer) { pending_update_timer = false; - update_timer.cancel(); + update_timer.Cancel(); } } #ifndef NCMPC_MINI void ScheduleCheckKeyBindings() noexcept { - boost::system::error_code error; - check_key_bindings_timer.expires_from_now(std::chrono::seconds(10), - error); - check_key_bindings_timer.async_wait(std::bind(&Instance::OnCheckKeyBindings, - this, - std::placeholders::_1)); + check_key_bindings_timer.Schedule(std::chrono::seconds(10)); } #endif private: #ifndef _WIN32 void InitSignals(); - void OnSigwinch(); - void AsyncWaitSigwinch(); + void OnSigwinch() noexcept; #endif - void OnReconnectTimer(const boost::system::error_code &error) noexcept; + void OnReconnectTimer() noexcept; - void OnUpdateTimer(const boost::system::error_code &error) noexcept; + void OnUpdateTimer() noexcept; void ScheduleUpdateTimer() noexcept { pending_update_timer = true; - boost::system::error_code error; - update_timer.expires_from_now(std::chrono::milliseconds(500), - error); - update_timer.async_wait(std::bind(&Instance::OnUpdateTimer, - this, - std::placeholders::_1)); + update_timer.Schedule(std::chrono::milliseconds(500)); } #ifndef NCMPC_MINI - void OnCheckKeyBindings(const boost::system::error_code &error) noexcept; + void OnCheckKeyBindings() noexcept; #endif };
View file
ncmpc-0.36.tar.xz/src/KeyDefPage.cxx -> ncmpc-0.47.tar.xz/src/KeyDefPage.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -32,7 +31,6 @@ #include "GlobalBindings.hxx" #include "screen_utils.hxx" #include "Options.hxx" -#include "util/Compiler.h" #include <assert.h> #include <errno.h> @@ -74,20 +72,20 @@ } /** The position of the "add a key" item */ - gcc_pure + gnu::pure unsigned GetAddPosition() const noexcept { return n_keys + 1; } /** The number of items in the list_window, if there's a command being edited */ - gcc_pure + gnu::pure unsigned CalculateListLength() const noexcept { /* show "add key" only if there is room for more keys */ return GetAddPosition() + (n_keys < MAX_COMMAND_KEYS); } /** Check whether a given item is a key */ - gcc_pure + gnu::pure bool IsKeyPosition(unsigned i) const noexcept { return (i > GetLeavePosition() && i < GetAddPosition()); } @@ -241,7 +239,7 @@ } void -CommandKeysPage::OnOpen(gcc_unused struct mpdclient &c) noexcept +CommandKeysPage::OnOpen(maybe_unused struct mpdclient &c) noexcept { // TODO } @@ -310,7 +308,7 @@ class CommandListPage final : public ListPage, ListText { ScreenManager &screen; - KeyBindings *bindings; + KeyBindings *bindings = nullptr; /** the number of commands */ static constexpr size_t command_n_commands = size_t(Command::NONE); @@ -348,7 +346,7 @@ } /** the number of items in the "command" view */ - gcc_pure + gnu::pure unsigned command_length() const { return command_item_save() + 1; } @@ -383,7 +381,7 @@ const auto &orginal_bindings = GetGlobalKeyBindings(); constexpr size_t size = sizeof(orginal_bindings); - return memcmp(&orginal_bindings, &bindings, size) != 0; + return memcmp(&orginal_bindings, bindings, size) != 0; } void @@ -461,7 +459,7 @@ } void -CommandListPage::OnOpen(gcc_unused struct mpdclient &c) noexcept +CommandListPage::OnOpen(maybe_unused struct mpdclient &c) noexcept { if (bindings == nullptr) bindings = new KeyBindings(GetGlobalKeyBindings());
View file
ncmpc-0.36.tar.xz/src/KeyDefPage.hxx -> ncmpc-0.47.tar.xz/src/KeyDefPage.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/KeyName.cxx -> ncmpc-0.47.tar.xz/src/KeyName.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/KeyName.hxx -> ncmpc-0.47.tar.xz/src/KeyName.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,8 +19,6 @@ #ifndef KEY_NAME_HXX #define KEY_NAME_HXX -#include "util/Compiler.h" - #include <utility> /** @@ -30,7 +27,7 @@ * @return the keycode and the first unparsed character; -1 indicates * error */ -gcc_pure +gnu::pure std::pair<int, const char *> ParseKeyName(const char *s) noexcept; @@ -40,7 +37,7 @@ * * The returned pointer is invalidated by the next call. */ -gcc_pure +gnu::pure const char * GetKeyName(int key) noexcept; @@ -49,7 +46,7 @@ * * The returned pointer is invalidated by the next call. */ -gcc_pure +gnu::pure const char * GetLocalizedKeyName(int key) noexcept;
View file
ncmpc-0.36.tar.xz/src/LibraryPage.cxx -> ncmpc-0.47.tar.xz/src/LibraryPage.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -36,7 +35,7 @@ #include <assert.h> #include <string.h> -gcc_const +gnu::const static const char * GetTagPlural(enum mpd_tag_type tag) noexcept { @@ -88,6 +87,11 @@ void LoadSongList(struct mpdclient &c); +protected: + /* virtual methods from class FileListPage */ + bool HandleEnter(struct mpdclient &c) override; + +public: /* virtual methods from class Page */ void Update(struct mpdclient &c, unsigned events) noexcept override; bool OnCommand(struct mpdclient &c, Command cmd) override; @@ -102,9 +106,28 @@ } } +class ArtistBrowserPage; + +class LibraryTagListPage final : public TagListPage { + ArtistBrowserPage &library_page; + +public: + LibraryTagListPage(ScreenManager &_screen, + ArtistBrowserPage &_library_page, + Page *_parent, + const enum mpd_tag_type _tag, + const char *_all_text, + WINDOW *_w, Size size) noexcept + :TagListPage(_screen, _parent, _tag, _all_text, _w, size), + library_page(_library_page) {} + +protected: + bool HandleEnter(struct mpdclient &c) override; +}; + class ArtistBrowserPage final : public ProxyPage { - std::list<TagListPage> tag_list_pages; - std::list<TagListPage>::iterator current_tag_list_page; + std::list<LibraryTagListPage> tag_list_pages; + std::list<LibraryTagListPage>::iterator current_tag_list_page; SongListPage song_list_page; @@ -117,7 +140,7 @@ bool first = true; for (const auto &tag : options.library_page_tags) { - tag_list_pages.emplace_back(_screen, + tag_list_pages.emplace_back(_screen, *this, first ? nullptr : this, tag, first ? nullptr : _("All"), @@ -126,6 +149,8 @@ } } + void EnterTag(struct mpdclient &c, TagFilter &&filter); + private: void OpenTagPage(struct mpdclient &c, TagFilter &&filter) noexcept; @@ -143,9 +168,7 @@ { auto *connection = c.GetConnection(); - delete filelist; - - filelist = new FileList(); + filelist = std::make_unique<FileList>(); /* add a dummy entry for ".." */ filelist->emplace_back(nullptr); @@ -160,7 +183,7 @@ } /* fix highlights */ - screen_browser_sync_highlights(filelist, &c.playlist); + screen_browser_sync_highlights(*filelist, c.playlist); lw.SetLength(filelist->size()); } @@ -200,17 +223,19 @@ } bool -SongListPage::OnCommand(struct mpdclient &c, Command cmd) +SongListPage::HandleEnter(struct mpdclient &c) { - switch(cmd) { - case Command::PLAY: - if (lw.GetCursorIndex() == 0 && parent != nullptr) - /* handle ".." */ - return parent->OnCommand(c, Command::GO_PARENT_DIRECTORY); + if (lw.GetCursorIndex() == 0 && parent != nullptr) + /* handle ".." */ + return parent->OnCommand(c, Command::GO_PARENT_DIRECTORY); - break; + return FileListPage::HandleEnter(c); +} - /* continue and update... */ +bool +SongListPage::OnCommand(struct mpdclient &c, Command cmd) +{ + switch(cmd) { case Command::SCREEN_UPDATE: LoadSongList(c); return false; @@ -246,30 +271,50 @@ ProxyPage::Update(c, events); } -bool -ArtistBrowserPage::OnCommand(struct mpdclient &c, Command cmd) +inline void +ArtistBrowserPage::EnterTag(struct mpdclient &c, TagFilter &&filter) { - if (ProxyPage::OnCommand(c, cmd)) - return true; + assert(current_tag_list_page != tag_list_pages.end()); - switch (cmd) { - case Command::PLAY: - if (current_tag_list_page != tag_list_pages.end()) { - auto filter = current_tag_list_page->MakeCursorFilter(); - if (filter.empty()) + ++current_tag_list_page; + + if (current_tag_list_page != tag_list_pages.end()) { + while (true) { + OpenTagPage(c, std::move(filter)); + if (current_tag_list_page->HasMultipleValues()) break; + /* skip tags which have just + one value */ + filter = current_tag_list_page->GetFilter(); ++current_tag_list_page; - - if (current_tag_list_page != tag_list_pages.end()) - OpenTagPage(c, std::move(filter)); - else + if (current_tag_list_page == tag_list_pages.end()) { OpenSongList(c, std::move(filter)); - return true; + break; + } } + } else + OpenSongList(c, std::move(filter)); +} - break; +bool +LibraryTagListPage::HandleEnter(struct mpdclient &c) +{ + auto new_filter = MakeCursorFilter(); + if (new_filter.empty()) + return TagListPage::HandleEnter(c); + + library_page.EnterTag(c, std::move(new_filter)); + return true; +} + +bool +ArtistBrowserPage::OnCommand(struct mpdclient &c, Command cmd) +{ + if (ProxyPage::OnCommand(c, cmd)) + return true; + switch (cmd) { case Command::GO_ROOT_DIRECTORY: if (GetCurrentPage() != &tag_list_pages.front()) { current_tag_list_page = tag_list_pages.begin(); @@ -280,10 +325,13 @@ break; case Command::GO_PARENT_DIRECTORY: - if (current_tag_list_page != tag_list_pages.begin()) { + while (current_tag_list_page != tag_list_pages.begin()) { --current_tag_list_page; SetCurrentPage(c, &*current_tag_list_page); - return true; + if (current_tag_list_page->HasMultipleValues()) + return true; + + /* skip tags which have just one value */ } break;
View file
ncmpc-0.36.tar.xz/src/LibraryPage.hxx -> ncmpc-0.47.tar.xz/src/LibraryPage.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/ListCursor.cxx -> ncmpc-0.47.tar.xz/src/ListCursor.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,11 +19,18 @@ #include "ListCursor.hxx" #include "Options.hxx" +ListCursor::ListCursor(unsigned _height) noexcept + :height(_height), + scroll_offset(ClampScrollOffset(options.scroll_offset, height)) +{ +} + void ListCursor::Reset() noexcept { selected = 0; range_selection = false; + highlight_cursor = false; range_base = 0; start = 0; } @@ -53,6 +59,8 @@ ListCursor::SetHeight(unsigned _height) noexcept { height = _height; + scroll_offset = ClampScrollOffset(options.scroll_offset, height); + CheckOrigin(); } @@ -71,6 +79,8 @@ void ListCursor::Center(unsigned n) noexcept { + highlight_cursor = false; + if (n > GetHeight() / 2) start = n - GetHeight() / 2; else @@ -87,18 +97,15 @@ void ListCursor::ScrollTo(unsigned n) noexcept { + highlight_cursor = false; + int new_start = start; - if ((unsigned) options.scroll_offset * 2 >= GetHeight()) - // Center if the offset is more than half the screen - new_start = n - GetHeight() / 2; - else { - if (n < start + options.scroll_offset) - new_start = n - options.scroll_offset; + if (n < start + scroll_offset) + new_start = n - scroll_offset; - if (n >= start + GetHeight() - options.scroll_offset) - new_start = n - GetHeight() + 1 + options.scroll_offset; - } + if (n >= start + GetHeight() - scroll_offset) + new_start = n - GetHeight() + 1 + scroll_offset; if (new_start + GetHeight() > length) new_start = length - GetHeight(); @@ -123,6 +130,7 @@ ListCursor::MoveCursor(unsigned n) noexcept { selected = n; + highlight_cursor = false; CheckSelected(); CheckOrigin(); @@ -132,11 +140,11 @@ ListCursor::FetchCursor() noexcept { if (start > 0 && - selected < start + options.scroll_offset) - MoveCursor(start + options.scroll_offset); + selected < start + scroll_offset) + MoveCursor(start + scroll_offset); else if (start + GetHeight() < length && - selected > start + GetHeight() - 1 - options.scroll_offset) - MoveCursor(start + GetHeight() - 1 - options.scroll_offset); + selected > start + GetHeight() - 1 - scroll_offset) + MoveCursor(start + GetHeight() - 1 - scroll_offset); } ListWindowRange @@ -182,10 +190,7 @@ if (start == 0) MoveCursor(start); else - if ((unsigned) options.scroll_offset * 2 >= GetHeight()) - MoveCursor(start + GetHeight() / 2); - else - MoveCursor(start + options.scroll_offset); + MoveCursor(start + scroll_offset); } void @@ -201,13 +206,10 @@ ListCursor::MoveCursorBottom() noexcept { if (length >= GetHeight()) - if ((unsigned) options.scroll_offset * 2 >= GetHeight()) - MoveCursor(start + GetHeight() / 2); + if (start + GetHeight() == length) + MoveCursor(length - 1); else - if (start + GetHeight() == length) - MoveCursor(length - 1); - else - MoveCursor(start + GetHeight() - 1 - options.scroll_offset); + MoveCursor(start + GetHeight() - 1 - scroll_offset); else MoveCursor(length - 1); } @@ -230,6 +232,8 @@ void ListCursor::MoveCursorNextPage() noexcept { + highlight_cursor = false; + if (GetHeight() < 2) return; if (selected + GetHeight() < length) @@ -241,6 +245,8 @@ void ListCursor::MoveCursorPreviousPage() noexcept { + highlight_cursor = false; + if (GetHeight() < 2) return; if (selected > GetHeight() - 1) @@ -252,6 +258,8 @@ void ListCursor::ScrollUp(unsigned n) noexcept { + highlight_cursor = false; + if (start > 0) { if (n > start) start = 0; @@ -265,6 +273,8 @@ void ListCursor::ScrollDown(unsigned n) noexcept { + highlight_cursor = false; + if (start + GetHeight() < length) { if (start + GetHeight() + n > length - 1) start = length - GetHeight(); @@ -278,6 +288,8 @@ void ListCursor::ScrollNextPage() noexcept { + highlight_cursor = false; + start += GetHeight(); if (start + GetHeight() > length) start = length > GetHeight() @@ -288,6 +300,8 @@ void ListCursor::ScrollPreviousPage() noexcept { + highlight_cursor = false; + start = start > GetHeight() ? start - GetHeight() : 0; @@ -296,6 +310,8 @@ void ListCursor::ScrollNextHalfPage() noexcept { + highlight_cursor = false; + start += (GetHeight() - 1) / 2; if (start + GetHeight() > length) { start = length > GetHeight() @@ -307,6 +323,8 @@ void ListCursor::ScrollPreviousHalfPage() noexcept { + highlight_cursor = false; + start = start > (GetHeight() - 1) / 2 ? start - (GetHeight() - 1) / 2 : 0;
View file
ncmpc-0.36.tar.xz/src/ListCursor.hxx -> ncmpc-0.47.tar.xz/src/ListCursor.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,7 +19,7 @@ #ifndef LIST_CURSOR_HXX #define LIST_CURSOR_HXX -#include "util/Compiler.h" +#include <algorithm> /** * The bounds of a range selection, see list_window_get_range(). @@ -79,6 +78,11 @@ unsigned height; /** + * A clamped copy of #Options::scroll_offset. + */ + unsigned scroll_offset = 0; + + /** * Number of items in this list. */ unsigned length = 0; @@ -96,11 +100,15 @@ */ bool range_selection = false; - bool hide_cursor = false; + bool show_cursor = true; + + /** + * @see HighlightCursor() + */ + bool highlight_cursor = false; public: - explicit constexpr ListCursor(unsigned _height) noexcept - :height(_height) {} + explicit ListCursor(unsigned _height) noexcept; constexpr unsigned GetHeight() const noexcept { return height; @@ -118,16 +126,29 @@ start = new_orign; } - void DisableCursor() { - hide_cursor = true; + void HideCursor() noexcept { + show_cursor = false; } - void EnableCursor() { - hide_cursor = false; + void ShowCursor() noexcept { + show_cursor = true; + } + + /** + * Make the cursor visible temporarily (until it is moved)? + * This is useful for highlighting a matching line after + * searching in a (cursorless) text page. + */ + void HighlightCursor() noexcept { + highlight_cursor = true; } constexpr bool HasCursor() const noexcept { - return !hide_cursor; + return show_cursor; + } + + constexpr bool IsCursorVisible() const noexcept { + return show_cursor || highlight_cursor; } constexpr bool HasRangeSelection() const noexcept { @@ -247,11 +268,51 @@ * range selection is disabled, it returns the cursor position (range * length is 1). */ - gcc_pure + gnu::pure ListWindowRange GetRange() const noexcept; + template<typename ItemList> + gnu::pure + auto GetCursorHash(const ItemList &items) const noexcept -> decltype(items.front().GetHash()) { + if (IsSingleCursor()) + return itemsGetCursorIndex().GetHash(); + else + return {}; + } + + template<typename ItemList> + bool SetCursorHash(const ItemList &items, + decltype(items.front().GetHash()) hash) noexcept { + if (hash == decltype(hash){}) + return false; + + unsigned idx = 0; + for (const auto &item : items) { + if (item.GetHash() == hash) { + SetCursor(idx); + return true; + } + + ++idx; + } + + return false; + } + private: - gcc_pure + /** + * Clamp the scroll-offset setting to slightly less than half + * of the screen height. + */ + static constexpr unsigned ClampScrollOffset(unsigned scroll_offset, + unsigned height) noexcept + { + return scroll_offset * 2 < height + ? scroll_offset + : std::max(height / 2, 1U) - 1; + } + + gnu::pure unsigned ValidateIndex(unsigned i) const noexcept; void CheckSelected() noexcept;
View file
ncmpc-0.36.tar.xz/src/ListPage.hxx -> ncmpc-0.47.tar.xz/src/ListPage.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/ListRenderer.hxx -> ncmpc-0.47.tar.xz/src/ListRenderer.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/ListText.hxx -> ncmpc-0.47.tar.xz/src/ListText.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,8 +19,6 @@ #ifndef LIST_TEXT_HXX #define LIST_TEXT_HXX -#include "util/Compiler.h" - #include <stddef.h> class ListText { @@ -29,7 +26,7 @@ /** * @return the text in the locale charset */ - gcc_pure + gnu::pure virtual const char *GetListItemText(char *buffer, size_t size, unsigned i) const noexcept = 0; };
View file
ncmpc-0.36.tar.xz/src/ListWindow.cxx -> ncmpc-0.47.tar.xz/src/ListWindow.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -34,11 +33,11 @@ void ListWindow::Paint(const ListRenderer &renderer) const noexcept { - bool show_cursor = HasCursor() && + bool cursor_visible = IsCursorVisible() && (!options.hardware_cursor || HasRangeSelection()); ListWindowRange range; - if (show_cursor) + if (cursor_visible) range = GetRange(); for (unsigned i = 0; i < GetHeight(); i++) { @@ -50,7 +49,7 @@ break; } - bool is_selected = show_cursor && + bool is_selected = cursor_visible && range.Contains(j); renderer.PaintListItem(w, j, i, width, is_selected); @@ -88,6 +87,7 @@ if (m(label)) { MoveCursor(i); + HighlightCursor(); return true; } if (wrap && i == GetCursorIndex()) @@ -134,6 +134,7 @@ if (m(label)) { MoveCursor(i); + HighlightCursor(); return true; } if (wrap && i == (int)GetCursorIndex()) @@ -169,6 +170,7 @@ if (m(label)) { MoveCursor(i); + HighlightCursor(); return true; } } @@ -285,6 +287,20 @@ bool ListWindow::HandleMouse(mmask_t bstate, int y) noexcept { +#if defined(BUTTON4_PRESSED) && defined(BUTTON5_PRESSED) + if (bstate & BUTTON4_PRESSED) { + /* mouse wheel up */ + ScrollUp(4); + return true; + } + + if (bstate & BUTTON5_PRESSED) { + /* mouse wheel down */ + ScrollDown(4); + return true; + } +#endif + /* if the even occurred above the list window move up */ if (y < 0) { if (bstate & BUTTON3_CLICKED)
View file
ncmpc-0.36.tar.xz/src/ListWindow.hxx -> ncmpc-0.47.tar.xz/src/ListWindow.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.47.tar.xz/src/LyricsCache.cxx
Added
@@ -0,0 +1,177 @@ +/* ncmpc (Ncurses MPD Client) + * Copyright 2004-2021 The Music Player Daemon Project + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "LyricsCache.hxx" +#include "XdgBaseDirectory.hxx" +#include "io/Path.hxx" +#include "config.h" + +#include <stdlib.h> +#include <sys/stat.h> +#include <unistd.h> + +static std::string +GetLyricsCacheDirectory() noexcept +{ + const auto ncmpc_cache_directory = GetHomeCacheDirectory(PACKAGE); + if (ncmpc_cache_directory.empty()) + return {}; + + mkdir(ncmpc_cache_directory.c_str(), 0777); + return BuildPath(ncmpc_cache_directory, "lyrics"); +} + +static std::string +GetLegacyLyricsCacheDirectory() noexcept +{ + const char *home = getenv("HOME"); + if (home == nullptr) + return {}; + + return BuildPath(home, ".lyrics"); +} + +LyricsCache::LyricsCache() noexcept + :directory(GetLyricsCacheDirectory()), + legacy_directory(GetLegacyLyricsCacheDirectory()) +{ +} + +/** + * Strip dangerous/illegal characters from a file name, to avoid path + * injection bugs. + */ +static void +SanitizeFilename(char *p) noexcept +{ + for (; *p; ++p) { + char ch = *p; + + if (ch == '/') + *p = '-'; + } +} + +static std::string +MakePath(const std::string &directory, + const char *artist, const char *title) noexcept +{ + if (directory.empty()) + return {}; + + char filename1024; + int length = snprintf(filename, sizeof(filename), "%s - %s.txt", + artist, title); + if (length <= 0 || size_t(length) >= sizeof(filename)) + /* too long for the buffer, bail out */ + return {}; + + SanitizeFilename(filename); + + return BuildPath(directory.c_str(), filename); +} + +std::string +LyricsCache::MakePath(const char *artist, const char *title) const noexcept +{ + auto path = ::MakePath(directory, artist, title); + if (path.empty()) + path = ::MakePath(legacy_directory, artist, title); + + return path; +} + +gnu::pure +static bool +ExistsFile(const std::string &path) noexcept +{ + if (path.empty()) + return false; + + struct stat result; + return stat(path.c_str(), &result) == 0; +} + +bool +LyricsCache::Exists(const char *artist, const char *title) const noexcept +{ + return ExistsFile(::MakePath(directory, artist, title)) || + ExistsFile(::MakePath(legacy_directory, artist, title)); +} + +gnu::pure +static std::string +LoadFile(const std::string &path) noexcept +{ + if (path.empty()) + return {}; + + FILE *file = fopen(path.c_str(), "r"); + if (file == nullptr) + return {}; + + constexpr std::size_t MAX_SIZE = 256 * 1024; + std::string value; + + do { + char buffer1024; + auto nbytes = fread(buffer, 1, sizeof(buffer), file); + if (nbytes <= 0) + break; + + value.append(buffer, nbytes); + } while (value.length() < MAX_SIZE); + + fclose(file); + return value; +} + +std::string +LyricsCache::Load(const char *artist, const char *title) const noexcept +{ + auto s = LoadFile(::MakePath(directory, artist, title)); + if (s.empty()) + s = LoadFile(::MakePath(legacy_directory, artist, title)); + return s; +} + +FILE * +LyricsCache::Save(const char *artist, const char *title) noexcept +{ + const auto &d = directory.empty() ? legacy_directory : directory; + if (d.empty()) + return nullptr; + + mkdir(d.c_str(), S_IRWXU); + + const auto path = ::MakePath(d, artist, title); + return fopen(path.c_str(), "w"); +} + +static bool +DeleteFile(const std::string &path) noexcept +{ + return !path.empty() && unlink(path.c_str()) == 0; +} + +bool +LyricsCache::Delete(const char *artist, const char *title) noexcept +{ + return DeleteFile(::MakePath(directory, artist, title)) || + DeleteFile(::MakePath(legacy_directory, artist, title)); +}
View file
ncmpc-0.47.tar.xz/src/LyricsCache.hxx
Added
@@ -0,0 +1,55 @@ +/* ncmpc (Ncurses MPD Client) + * Copyright 2004-2021 The Music Player Daemon Project + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef LYRICS_CACHE_HXX +#define LYRICS_CACHE_HXX + +#include <string> + +#include <stddef.h> +#include <stdio.h> + +class LyricsCache { + const std::string directory; + + const std::string legacy_directory; + +public: + LyricsCache() noexcept; + + bool IsAvailable() const noexcept { + return !directory.empty(); + } + + std::string MakePath(const char *artist, + const char *title) const noexcept; + + gnu::pure + bool Exists(const char *artist, const char *title) const noexcept; + + std::string Load(const char *artist, const char *title) const noexcept; + + FILE *Save(const char *artist, const char *title) noexcept; + + /** + * @return true on success + */ + bool Delete(const char *artist, const char *title) noexcept; +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/LyricsLoader.cxx
Added
@@ -0,0 +1,40 @@ +/* ncmpc (Ncurses MPD Client) + * Copyright 2004-2021 The Music Player Daemon Project + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "LyricsLoader.hxx" +#include "config.h" + +#include <assert.h> + +LyricsLoader::LyricsLoader() noexcept + :plugins(plugin_list_load_directory(LYRICS_PLUGIN_DIR)) +{ +} + +PluginCycle * +LyricsLoader::Load(EventLoop &event_loop, + const char *artist, const char *title, + PluginResponseHandler &handler) noexcept +{ + assert(artist != nullptr); + assert(title != nullptr); + + const char *args3 = { artist, title, nullptr }; + + return plugin_run(event_loop, plugins, args, handler); +}
View file
ncmpc-0.47.tar.xz/src/LyricsLoader.hxx
Added
@@ -0,0 +1,35 @@ +/* ncmpc (Ncurses MPD Client) + * Copyright 2004-2021 The Music Player Daemon Project + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef LYRICS_LOADER_HXX +#define LYRICS_LOADER_HXX + +#include "plugin.hxx" + +class LyricsLoader { + const PluginList plugins; + +public: + LyricsLoader() noexcept; + + PluginCycle *Load(EventLoop &event_loop, + const char *artist, const char *title, + PluginResponseHandler &handler) noexcept; +}; + +#endif
View file
ncmpc-0.36.tar.xz/src/LyricsPage.cxx -> ncmpc-0.47.tar.xz/src/LyricsPage.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -18,6 +17,8 @@ */ #include "LyricsPage.hxx" +#include "LyricsCache.hxx" +#include "LyricsLoader.hxx" #include "PageMeta.hxx" #include "screen_status.hxx" #include "FileBrowserPage.hxx" @@ -27,23 +28,18 @@ #include "Options.hxx" #include "mpdclient.hxx" #include "screen.hxx" -#include "lyrics.hxx" #include "plugin.hxx" #include "TextPage.hxx" #include "screen_utils.hxx" #include "ncu.hxx" -#include <boost/asio/steady_timer.hpp> - #include <string> #include <assert.h> #include <errno.h> -#include <sys/stat.h> #include <sys/wait.h> #include <stdlib.h> #include <string.h> -#include <unistd.h> #include <stdio.h> static struct mpd_song *next_song; @@ -61,26 +57,38 @@ */ const char *artist = nullptr, *title = nullptr; + LyricsCache cache; + std::string plugin_name; - PluginCycle *loader = nullptr; + LyricsLoader loader; + + PluginCycle *plugin_cycle = nullptr; - boost::asio::steady_timer loader_timeout; + CoarseTimerEvent plugin_timeout; public: LyricsPage(ScreenManager &_screen, WINDOW *w, Size size) :TextPage(_screen, w, size), - loader_timeout(_screen.get_io_service()) {} + plugin_timeout(_screen.GetEventLoop(), + BIND_THIS_METHOD(OnTimeout)) {} ~LyricsPage() override { Cancel(); } - auto &get_io_service() noexcept { - return screen.get_io_service(); + auto &GetEventLoop() noexcept { + return plugin_timeout.GetEventLoop(); } private: + void StopPluginCycle() noexcept { + assert(plugin_cycle != nullptr); + + plugin_stop(*plugin_cycle); + plugin_cycle = nullptr; + } + void Cancel(); /** @@ -95,6 +103,8 @@ void Set(const char *s); + void StartPluginCycle() noexcept; + void Load(const struct mpd_song &song) noexcept; void MaybeLoad(const struct mpd_song &new_song) noexcept; @@ -106,12 +116,11 @@ void Reload(); bool Save(); - bool Delete(); /** save current lyrics to a file and run editor on it */ void Edit(); - void OnTimeout(const boost::system::error_code &error) noexcept; + void OnTimeout() noexcept; public: /* virtual methods from class Page */ @@ -130,12 +139,10 @@ void LyricsPage::Cancel() { - if (loader != nullptr) { - plugin_stop(loader); - loader = nullptr; - } + if (plugin_cycle != nullptr) + StopPluginCycle(); - loader_timeout.cancel(); + plugin_timeout.Cancel(); plugin_name.clear(); @@ -147,41 +154,10 @@ } } -static void -path_lyr_file(char *path, size_t size, - const char *artist, const char *title) -{ - snprintf(path, size, "%s/.lyrics/%s - %s.txt", - getenv("HOME"), artist, title); -} - -static bool -exists_lyr_file(const char *artist, const char *title) -{ - char path1024; - path_lyr_file(path, 1024, artist, title); - - struct stat result; - return (stat(path, &result) == 0); -} - -static FILE * -create_lyr_file(const char *artist, const char *title) -{ - char path1024; - snprintf(path, 1024, "%s/.lyrics", - getenv("HOME")); - mkdir(path, S_IRWXU); - - path_lyr_file(path, 1024, artist, title); - - return fopen(path, "w"); -} - bool LyricsPage::Save() { - FILE *lyr_file = create_lyr_file(artist, title); + FILE *lyr_file = cache.Save(artist, title); if (lyr_file == nullptr) return false; @@ -192,17 +168,6 @@ return true; } -bool -LyricsPage::Delete() -{ - if (!exists_lyr_file(artist, title)) - return false; - - char path1024; - path_lyr_file(path, 1024, artist, title); - return unlink(path) == 0; -} - void LyricsPage::Set(const char *s) { @@ -233,13 +198,16 @@ Set(result.c_str()); - if (options.lyrics_autosave && !exists_lyr_file(artist, title)) + if (options.lyrics_autosave && cache.IsAvailable() && + !cache.Exists(artist, title)) Save(); - loader_timeout.cancel(); + plugin_timeout.Cancel(); + + StopPluginCycle(); - plugin_stop(loader); - loader = nullptr; + /* schedule a full repaint so the page title gets updated */ + screen.SchedulePaint(); } void @@ -252,23 +220,36 @@ /* translators: no lyrics were found for the song */ screen_status_message(_("No lyrics")); - loader_timeout.cancel(); + plugin_timeout.Cancel(); + StopPluginCycle(); - plugin_stop(loader); - loader = nullptr; + /* schedule a full repaint so the page title gets updated */ + screen.SchedulePaint(); } void -LyricsPage::OnTimeout(const boost::system::error_code &error) noexcept +LyricsPage::OnTimeout() noexcept { - if (error) - return; - - plugin_stop(loader); - loader = nullptr; + StopPluginCycle(); screen_status_printf(_("Lyrics timeout occurred after %d seconds"), (int)std::chrono::duration_cast<std::chrono::seconds>(options.lyrics_timeout).count()); + + /* schedule a full repaint so the page title gets updated */ + screen.SchedulePaint(); +} + +void +LyricsPage::StartPluginCycle() noexcept +{ + assert(artist != nullptr); + assert(title != nullptr); + assert(plugin_cycle == nullptr); + + plugin_cycle = loader.Load(GetEventLoop(), artist, title, *this); + + if (options.lyrics_timeout > std::chrono::steady_clock::duration::zero()) + plugin_timeout.Schedule(options.lyrics_timeout); } void @@ -286,16 +267,13 @@ return; } - loader = lyrics_load(get_io_service(), - artist, title, *this); - - if (options.lyrics_timeout > std::chrono::steady_clock::duration::zero()) { - boost::system::error_code error; - loader_timeout.expires_from_now(options.lyrics_timeout, - error); - loader_timeout.async_wait(std::bind(&LyricsPage::OnTimeout, this, - std::placeholders::_1)); - } + if (auto from_cache = cache.Load(artist, title); !from_cache.empty()) { + /* cached */ + plugin_name = "cache"; + Set(from_cache.c_str()); + } else + /* not cached - invoke plugins */ + StartPluginCycle(); } void @@ -310,10 +288,9 @@ void LyricsPage::Reload() { - if (loader == nullptr && artist != nullptr && title != nullptr) { + if (plugin_cycle == nullptr && artist != nullptr && title != nullptr) { reloading = true; - loader = lyrics_load(get_io_service(), - artist, title, *this); + StartPluginCycle(); Repaint(); } } @@ -348,7 +325,7 @@ const char * LyricsPage::GetTitle(char *str, size_t size) const noexcept { - if (loader != nullptr) { + if (plugin_cycle != nullptr) { snprintf(str, size, "%s (%s)", _("Lyrics"), /* translators: this message is displayed @@ -374,6 +351,12 @@ void LyricsPage::Edit() { + const auto path = cache.MakePath(artist, title); + if (path.empty()) { + screen_status_message(_("Lyrics cache is unavailable")); + return; + } + if (options.text_editor.empty()) { screen_status_message(_("Editor not configured")); return; @@ -404,9 +387,7 @@ ncu_init(); return; } else if (pid == 0) { - char path1024; - path_lyr_file(path, sizeof(path), artist, title); - execlp(editor, editor, path, nullptr); + execlp(editor, editor, path.c_str(), nullptr); /* exec failed, do what system does */ _exit(127); } else { @@ -444,21 +425,21 @@ switch(cmd) { case Command::INTERRUPT: - if (loader != nullptr) { + if (plugin_cycle != nullptr) { Cancel(); Clear(); } return true; case Command::SAVE_PLAYLIST: - if (loader == nullptr && artist != nullptr && + if (plugin_cycle == nullptr && artist != nullptr && title != nullptr && Save()) /* lyrics for the song were saved on hard disk */ screen_status_message (_("Lyrics saved")); return true; case Command::DELETE: - if (loader == nullptr && artist != nullptr && + if (plugin_cycle == nullptr && artist != nullptr && title != nullptr) { - screen_status_message(Delete() + screen_status_message(cache.Delete(artist, title) ? _("Lyrics deleted") : _("No saved lyrics")); }
View file
ncmpc-0.36.tar.xz/src/LyricsPage.hxx -> ncmpc-0.47.tar.xz/src/LyricsPage.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/Main.cxx -> ncmpc-0.47.tar.xz/src/Main.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -33,19 +32,15 @@ #include "xterm_title.hxx" #include "strfsong.hxx" #include "i18n.h" +#include "util/Exception.hxx" #include "util/PrintException.hxx" #include "util/ScopeExit.hxx" #include "util/StringUTF8.hxx" -#include "util/Compiler.h" #ifndef NCMPC_MINI #include "ConfigFile.hxx" #endif -#ifdef ENABLE_LYRICS_SCREEN -#include "lyrics.hxx" -#endif - #include <mpd/client.h> #include <curses.h> @@ -67,7 +62,7 @@ #ifndef NCMPC_MINI static void -update_xterm_title() +update_xterm_title() noexcept { const struct mpd_song *song = mpd->GetPlayingSong(); @@ -91,13 +86,13 @@ #endif static bool -should_enable_update_timer() +should_enable_update_timer() noexcept { return mpd->playing; } static void -auto_update_timer() +auto_update_timer() noexcept { if (should_enable_update_timer()) global_instance->EnableUpdateTimer(); @@ -122,11 +117,8 @@ } void -Instance::OnReconnectTimer(const boost::system::error_code &error) noexcept +Instance::OnReconnectTimer() noexcept { - if (error) - return; - assert(client.IsDead()); screen_status_printf(_("Connecting to %s"), @@ -137,17 +129,17 @@ } void -mpdclient_connected_callback() +mpdclient_connected_callback() noexcept { #ifndef NCMPC_MINI /* quit if mpd is pre 0.14 - song id not supported by mpd */ auto *connection = mpd->GetConnection(); - if (mpd_connection_cmp_server_version(connection, 0, 19, 0) < 0) { + if (mpd_connection_cmp_server_version(connection, 0, 21, 0) < 0) { const unsigned *version = mpd_connection_get_server_version(connection); screen_status_printf(_("Error: MPD version %d.%d.%d is too old (%s needed)"), version0, version1, version2, - "0.19.0"); + "0.21.0"); mpd->Disconnect(); doupdate(); @@ -166,14 +158,14 @@ } void -mpdclient_failed_callback() +mpdclient_failed_callback() noexcept { /* try again in 5 seconds */ global_instance->ScheduleReconnect(std::chrono::seconds(5)); } void -mpdclient_lost_callback() +mpdclient_lost_callback() noexcept { screen->Update(*mpd, global_instance->GetSeek()); @@ -185,7 +177,7 @@ * idle event (or when the connection dies). */ void -mpdclient_idle_callback(gcc_unused unsigned events) +mpdclient_idle_callback(maybe_unused unsigned events) noexcept { #ifndef NCMPC_MINI if (options.enable_xterm_title) @@ -197,11 +189,8 @@ } void -Instance::OnUpdateTimer(const boost::system::error_code &error) noexcept +Instance::OnUpdateTimer() noexcept { - if (error) - return; - assert(pending_update_timer); pending_update_timer = false; @@ -211,11 +200,12 @@ ScheduleUpdateTimer(); } -void begin_input_event() +void +begin_input_event() noexcept { } -void end_input_event() +void end_input_event() noexcept { screen->Update(*mpd, global_instance->GetSeek()); mpd->events = (enum mpd_idle)0; @@ -224,14 +214,19 @@ } bool -do_input_event(boost::asio::io_service &io_service, Command cmd) +do_input_event(EventLoop &event_loop, Command cmd) noexcept { if (cmd == Command::QUIT) { - io_service.stop(); + event_loop.Break(); return false; } - screen->OnCommand(*mpd, global_instance->GetSeek(), cmd); + try { + screen->OnCommand(*mpd, global_instance->GetSeek(), cmd); + } catch (...) { + screen_status_error(std::current_exception()); + return true; + } if (cmd == Command::VOLUME_UP || cmd == Command::VOLUME_DOWN) /* make sure we don't update the volume yet */ @@ -243,9 +238,13 @@ #ifdef HAVE_GETMOUSE void -do_mouse_event(Point p, mmask_t bstate) +do_mouse_event(Point p, mmask_t bstate) noexcept { - screen->OnMouse(*mpd, global_instance->GetSeek(), p, bstate); + try { + screen->OnMouse(*mpd, global_instance->GetSeek(), p, bstate); + } catch (...) { + screen_status_error(std::current_exception()); + } } #endif @@ -256,11 +255,8 @@ * message every 10 seconds. */ void -Instance::OnCheckKeyBindings(const boost::system::error_code &error) noexcept +Instance::OnCheckKeyBindings() noexcept { - if (error) - return; - char buf256; if (GetGlobalKeyBindings().Check(buf, sizeof(buf))) @@ -291,7 +287,7 @@ charset_init(); #endif - const ScopeInitUTF8 init_utf8; + maybe_unused const ScopeInitUTF8 init_utf8; /* initialize i18n support */ #endif @@ -318,10 +314,6 @@ const ScopeCursesInit curses_init; -#ifdef ENABLE_LYRICS_SCREEN - lyrics_init(); -#endif - /* create the global Instance */ Instance instance; global_instance = &instance;
View file
ncmpc-0.36.tar.xz/src/Match.cxx -> ncmpc-0.47.tar.xz/src/Match.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -18,6 +17,7 @@ */ #include "Match.hxx" +#include "util/ScopeExit.hxx" #include <assert.h> #include <string.h> @@ -25,7 +25,7 @@ MatchExpression::~MatchExpression() noexcept { #ifdef HAVE_PCRE - pcre_free(re); + pcre2_code_free_8(re); #endif } @@ -41,13 +41,14 @@ #else assert(re == nullptr); - int options = PCRE_CASELESS|PCRE_DOTALL|PCRE_NO_AUTO_CAPTURE; + int options = PCRE2_CASELESS|PCRE2_DOTALL|PCRE2_NO_AUTO_CAPTURE; if (anchor) - options |= PCRE_ANCHORED; + options |= PCRE2_ANCHORED; - const char *error_string; - int error_offset; - re = pcre_compile(src, options, &error_string, &error_offset, nullptr); + int error_number; + PCRE2_SIZE error_offset; + re = pcre2_compile_8(PCRE2_SPTR8(src), PCRE2_ZERO_TERMINATED, + options, &error_number, &error_offset, nullptr); return re != nullptr; #endif } @@ -64,7 +65,13 @@ #else assert(re != nullptr); - return pcre_exec(re, nullptr, line, strlen(line), - 0, 0, nullptr, 0) >= 0; + const auto match_data = + pcre2_match_data_create_from_pattern_8(re, nullptr); + AtScopeExit(match_data) { + pcre2_match_data_free_8(match_data); + }; + + return pcre2_match_8(re, (PCRE2_SPTR8)line, strlen(line), + 0, 0, match_data, nullptr) >= 0; #endif }
View file
ncmpc-0.36.tar.xz/src/Match.hxx -> ncmpc-0.47.tar.xz/src/Match.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -21,10 +20,9 @@ #define MATCH_H #include "config.h" -#include "util/Compiler.h" #ifdef HAVE_PCRE -#include <pcre.h> +#include <pcre2.h> #else #include <stddef.h> #endif @@ -35,7 +33,7 @@ size_t length; bool anchored; #else - pcre *re = nullptr; + pcre2_code_8 *re = nullptr; #endif public: @@ -47,7 +45,7 @@ bool Compile(const char *src, bool anchor) noexcept; - gcc_pure + gnu::pure bool operator()(const char *line) const noexcept; };
View file
ncmpc-0.36.tar.xz/src/Options.cxx -> ncmpc-0.47.tar.xz/src/Options.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -63,7 +62,7 @@ #endif }; -gcc_pure +gnu::pure static const OptionDefinition * FindOption(int s) noexcept { @@ -263,7 +262,6 @@ GetGlobalKeyBindings().WriteToFile(stdout, KEYDEF_WRITE_ALL | KEYDEF_COMMENT_ALL); exit(EXIT_SUCCESS); - break; #endif default: fprintf(stderr,"Unknown Option %c = %s\n", c, arg);
View file
ncmpc-0.36.tar.xz/src/Options.hxx -> ncmpc-0.47.tar.xz/src/Options.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -25,10 +24,17 @@ #include <mpd/tag.h> +#include <cstdint> #include <vector> #include <string> #include <chrono> +enum class CurrentTimeDisplay : uint8_t { + ELAPSED, + REMAINING, + NONE, +}; + struct Options { std::string host; std::string password; @@ -42,32 +48,37 @@ std::string scroll_sep = DEFAULT_SCROLL_SEP; #endif std::vector<std::string> screen_list = DEFAULT_SCREEN_LIST; - bool display_remaining_time; + +#ifdef ENABLE_LIBRARY_PAGE + std::vector<enum mpd_tag_type> library_page_tags{MPD_TAG_ARTIST, MPD_TAG_ALBUM}; +#endif + + std::chrono::steady_clock::duration hide_cursor; + std::chrono::steady_clock::duration status_message_time = std::chrono::seconds(3); + int port; int timeout_ms = 0; int crossfade_time = DEFAULT_CROSSFADE_TIME; int search_mode; - std::chrono::steady_clock::duration hide_cursor; int seek_time = 1; -#ifdef ENABLE_LIBRARY_PAGE - std::vector<enum mpd_tag_type> library_page_tags{MPD_TAG_ARTIST, MPD_TAG_ALBUM}; + unsigned scroll_offset = 0; + +#ifdef ENABLE_CHAT_SCREEN + std::string chat_prefix; #endif #ifdef ENABLE_LYRICS_SCREEN + std::string text_editor; std::chrono::steady_clock::duration lyrics_timeout = std::chrono::minutes(1); bool lyrics_autosave = false; bool lyrics_show_plugin = false; - std::string text_editor; bool text_editor_ask = false; #endif -#ifdef ENABLE_CHAT_SCREEN - std::string chat_prefix; -#endif + bool find_wrap = true; bool find_show_last_pattern; bool list_wrap; - int scroll_offset = 0; bool auto_center; bool wide_cursor = true; bool hardware_cursor; @@ -78,7 +89,6 @@ bool audible_bell = true; bool visible_bell; bool bell_on_wrap = true; - std::chrono::steady_clock::duration status_message_time = std::chrono::seconds(3); #ifndef NCMPC_MINI bool enable_xterm_title; #endif @@ -94,6 +104,8 @@ bool jump_prefix_only = true; bool second_column = true; #endif + + CurrentTimeDisplay current_time_display = CurrentTimeDisplay::ELAPSED; }; extern Options options;
View file
ncmpc-0.36.tar.xz/src/OutputsPage.cxx -> ncmpc-0.47.tar.xz/src/OutputsPage.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -18,14 +17,18 @@ */ #include "OutputsPage.hxx" +#include "Deleter.hxx" #include "PageMeta.hxx" #include "ListPage.hxx" #include "ListRenderer.hxx" #include "screen_status.hxx" #include "paint.hxx" #include "Command.hxx" +#include "screen_utils.hxx" #include "i18n.h" #include "mpdclient.hxx" +#include "util/FNVHash.hxx" +#include "util/StringAPI.hxx" #include <mpd/client.h> @@ -34,14 +37,85 @@ #include <assert.h> -struct OutputDeleter { - void operator()(struct mpd_output *o) const { - mpd_output_free(o); - } -}; +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + +gnu::pure +static uint64_t +PartitionNameHash(const char *name) noexcept +{ + return FNV1aHash64(name) ^ 0x1; +} + +gnu::pure +static uint64_t +GetActivePartitionNameHash(const struct mpd_status *status) noexcept +{ + if (status == nullptr) + return 0; + + const char *partition = mpd_status_get_partition(status); + if (partition == nullptr) + return 0; + + return PartitionNameHash(partition); +} + +#endif class OutputsPage final : public ListPage, ListRenderer { - std::vector<std::unique_ptr<struct mpd_output, OutputDeleter>> items; + static constexpr unsigned RELOAD_IDLE_FLAGS = +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + MPD_IDLE_PARTITION | +#endif + MPD_IDLE_OUTPUT; + + struct Item { + std::unique_ptr<struct mpd_output, LibmpdclientDeleter> output; +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + std::unique_ptr<struct mpd_partition, LibmpdclientDeleter> partition; + + enum class Special { + NONE, + NEW_PARTITION, + } special = Special::NONE; + + explicit Item(Special _special) noexcept + :special(_special) {} +#endif + + explicit Item(struct mpd_output *_output) noexcept + :output(_output) {} + +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + explicit Item(struct mpd_partition *_partition) noexcept + :partition(_partition) {} +#endif + + gnu::pure + uint64_t GetHash() const noexcept { +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + switch (special) { + case Special::NONE: + break; + + case Special::NEW_PARTITION: + return 0x2; + } + + if (partition) { + return PartitionNameHash(mpd_partition_get_name(partition.get())); + } +#endif + + return FNV1aHash64(mpd_output_get_name(output.get())); + } + }; + + std::vector<Item> items; + +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + uint64_t active_partition = 0; +#endif public: OutputsPage(WINDOW *w, Size size) @@ -49,9 +123,18 @@ private: void Clear(); + void Reload(struct mpdclient &c) noexcept; + +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + bool ActivatePartition(struct mpdclient &c, + const struct mpd_partition &partition) noexcept; + bool CreateNewPartition(struct mpdclient &c) noexcept; +#endif bool Toggle(struct mpdclient &c, unsigned output_index); + bool Delete(struct mpdclient &c, unsigned idx); + public: /* virtual methods from class Page */ void Paint() const noexcept override; @@ -64,17 +147,76 @@ bool selected) const noexcept override; }; +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + +inline bool +OutputsPage::ActivatePartition(struct mpdclient &c, + const struct mpd_partition &partition) noexcept +{ + auto *connection = c.GetConnection(); + if (connection == nullptr) + return false; + + const char *partition_name = mpd_partition_get_name(&partition); + + if (!mpd_run_switch_partition(connection, partition_name)) { + c.HandleError(); + return false; + } + + screen_status_printf(_("Switched to partition '%s'"), + partition_name); + return true; +} + +inline bool +OutputsPage::CreateNewPartition(struct mpdclient &c) noexcept +{ + auto *connection = c.GetConnection(); + if (connection == nullptr) + return false; + + auto name = screen_readln(_("Name"), nullptr, nullptr, nullptr); + if (name.empty()) + return false; + + if (!mpd_run_newpartition(connection, name.c_str())) { + c.HandleError(); + return false; + } + + return true; +} + +#endif + bool OutputsPage::Toggle(struct mpdclient &c, unsigned output_index) { if (output_index >= items.size()) return false; + const auto &item = itemsoutput_index; +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + switch (item.special) { + case Item::Special::NONE: + break; + + case Item::Special::NEW_PARTITION: + return CreateNewPartition(c); + } + + if (item.partition) + return ActivatePartition(c, *item.partition); +#endif + + assert(item.output); + auto *connection = c.GetConnection(); if (connection == nullptr) return false; - const auto &output = *itemsoutput_index; + const auto &output = *item.output; if (!mpd_output_get_enabled(&output)) { if (!mpd_run_enable_output(connection, mpd_output_get_id(&output))) { @@ -102,6 +244,30 @@ return true; } +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + +bool +OutputsPage::Delete(struct mpdclient &c, unsigned idx) +{ + const auto &item = itemsidx; + + if (item.partition) { + auto *connection = c.GetConnection(); + if (connection == nullptr) + return false; + + const char *name = + mpd_partition_get_name(item.partition.get()); + if (!mpd_run_delete_partition(connection, name)) + c.HandleError(); + + return true; + } else + return false; +} + +#endif + void OutputsPage::Clear() { @@ -127,12 +293,69 @@ mpd_send_outputs(connection); struct mpd_output *output; - while ((output = mpd_recv_output(connection)) != nullptr) + while ((output = mpd_recv_output(connection)) != nullptr) { + const char *plugin = mpd_output_get_plugin(output); + if (plugin != nullptr && StringIsEqual(plugin, "dummy")) { + /* hide "dummy" outputs; they are placeholders + for an output which was moved to a + different partition */ + mpd_output_free(output); + continue; + } + items.emplace_back(output); + } c->FinishCommand(); } +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + +template<typename O> +static void +FillPartitionList(struct mpdclient &c, O &items) +{ + using Item = typename O::value_type; + + auto *connection = c.GetConnection(); + if (connection == nullptr) + return; + + if (mpd_connection_cmp_server_version(connection, 0, 22, 0) < 0) + return; + + mpd_send_listpartitions(connection); + + while (auto *partition = mpd_recv_partition(connection)) + items.emplace_back(partition); + + c.FinishCommand(); + + items.emplace_back(Item::Special::NEW_PARTITION); +} + +#endif + +inline void +OutputsPage::Reload(struct mpdclient &c) noexcept +{ + const auto hash = lw.GetCursorHash(items); + + Clear(); + + fill_outputs_list(&c, items); + +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + FillPartitionList(c, items); +#endif + + lw.SetLength(items.size()); + SetDirty(); + + /* restore the cursor position */ + lw.SetCursorHash(items, hash); +} + static std::unique_ptr<Page> outputs_init(ScreenManager &, WINDOW *w, Size size) { @@ -145,13 +368,56 @@ return _("Outputs"); } +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + +static void +PaintPartition(WINDOW *w, unsigned width, bool selected, bool active, + const struct mpd_partition &partition) noexcept +{ + const char *name = mpd_partition_get_name(&partition); + + row_color(w, active ? Style::LIST_BOLD : Style::LIST, selected); + waddstr(w, _("Partition")); + waddstr(w, ": "); + waddstr(w, name); + row_clear_to_eol(w, width, selected); +} + +#endif + void OutputsPage::PaintListItem(WINDOW *w, unsigned i, - gcc_unused unsigned y, unsigned width, + maybe_unused unsigned y, unsigned width, bool selected) const noexcept { assert(i < items.size()); - const auto *output = itemsi.get(); + const auto &item = itemsi; + +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + switch (item.special) { + case Item::Special::NONE: + break; + + case Item::Special::NEW_PARTITION: + row_color(w, Style::LIST, selected); + waddch(w, ''); + waddstr(w, _("Create new partition")); + waddch(w, ''); + row_clear_to_eol(w, width, selected); + return; + } + + if (item.partition) { + PaintPartition(w, width, selected, + active_partition == item.GetHash(), + *item.partition); + return; + } +#endif + + assert(item.output); + + const auto *output = item.output.get(); row_color(w, Style::LIST, selected); waddstr(w, mpd_output_get_enabled(output) ? "X " : " "); @@ -168,12 +434,12 @@ void OutputsPage::Update(struct mpdclient &c, unsigned events) noexcept { - if (events & MPD_IDLE_OUTPUT) { - Clear(); - fill_outputs_list(&c, items); - lw.SetLength(items.size()); - SetDirty(); - } +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + active_partition = GetActivePartitionNameHash(c.status); +#endif + + if (events & RELOAD_IDLE_FLAGS) + Reload(c); } bool @@ -194,6 +460,11 @@ SetDirty(); return true; +#if LIBMPDCLIENT_CHECK_VERSION(2,18,0) + case Command::DELETE: + return Delete(c, lw.GetCursorIndex()); +#endif + default: break; }
View file
ncmpc-0.36.tar.xz/src/OutputsPage.hxx -> ncmpc-0.47.tar.xz/src/OutputsPage.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/Page.hxx -> ncmpc-0.47.tar.xz/src/Page.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -23,7 +22,6 @@ #include "config.h" #include "Point.hxx" #include "Size.hxx" -#include "util/Compiler.h" #include <curses.h> @@ -65,6 +63,7 @@ return; last_size = new_size; + SetDirty(); OnResize(new_size); } @@ -103,6 +102,9 @@ /** * Handle a command. * + * Exceptions thrown by this method will be caught and + * displayed on the status line. + * * @returns true if the command should not be handled by the * ncmpc core */ @@ -112,17 +114,20 @@ /** * Handle a mouse event. * + * Exceptions thrown by this method will be caught and + * displayed on the status line. + * * @return true if the event was handled (and should not be * handled by the ncmpc core) */ - virtual bool OnMouse(gcc_unused struct mpdclient &c, - gcc_unused Point position, - gcc_unused mmask_t bstate) { + virtual bool OnMouse(maybe_unused struct mpdclient &c, + maybe_unused Point position, + maybe_unused mmask_t bstate) { return false; } #endif - gcc_pure + gnu::pure virtual const char *GetTitle(char *s, size_t size) const noexcept = 0; };
View file
ncmpc-0.36.tar.xz/src/PageMeta.hxx -> ncmpc-0.47.tar.xz/src/PageMeta.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/Point.hxx -> ncmpc-0.47.tar.xz/src/Point.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -28,15 +27,15 @@ struct Point { int x, y; - constexpr Point operator+(Point other) const { + constexpr Point operator+(Point other) const noexcept { return {x + other.x, y + other.y}; } - constexpr Point operator-(Point other) const { + constexpr Point operator-(Point other) const noexcept { return {x - other.x, y - other.y}; } - constexpr Point operator+(Size size) const { + constexpr Point operator+(Size size) const noexcept { return {x + int(size.width), y + int(size.height)}; } };
View file
ncmpc-0.36.tar.xz/src/ProgressBar.cxx -> ncmpc-0.47.tar.xz/src/ProgressBar.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -30,7 +29,7 @@ leaveok(window.w, true); #ifdef ENABLE_COLORS if (options.enable_colors) - wbkgd(window.w, COLOR_PAIR(Style::PROGRESSBAR)); + window.SetBackgroundStyle(Style::PROGRESSBAR); #endif }
View file
ncmpc-0.36.tar.xz/src/ProgressBar.hxx -> ncmpc-0.47.tar.xz/src/ProgressBar.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/ProxyPage.cxx -> ncmpc-0.47.tar.xz/src/ProxyPage.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/ProxyPage.hxx -> ncmpc-0.47.tar.xz/src/ProxyPage.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/Queue.cxx -> ncmpc-0.47.tar.xz/src/Queue.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -24,14 +23,14 @@ #include <string.h> void -MpdQueue::clear() +MpdQueue::clear() noexcept { version = 0; items.clear(); } const struct mpd_song * -MpdQueue::GetChecked(int idx) const +MpdQueue::GetChecked(int idx) const noexcept { if (idx < 0 || (size_type)idx >= size()) return nullptr; @@ -40,7 +39,7 @@ } void -MpdQueue::Move(unsigned dest, unsigned src) +MpdQueue::Move(unsigned dest, unsigned src) noexcept { assert(src < size()); assert(dest < size()); @@ -63,7 +62,7 @@ } MpdQueue::size_type -MpdQueue::FindByReference(const struct mpd_song &song) const +MpdQueue::FindByReference(const struct mpd_song &song) const noexcept { for (size_type i = 0;; ++i) { assert(i < size()); @@ -74,7 +73,7 @@ } int -MpdQueue::FindById(unsigned id) const +MpdQueue::FindById(unsigned id) const noexcept { for (size_type i = 0; i < size(); ++i) { const auto &song = (*this)i; @@ -86,7 +85,7 @@ } int -MpdQueue::FindByUri(const char *filename) const +MpdQueue::FindByUri(const char *filename) const noexcept { for (size_type i = 0; i < size(); ++i) { const auto &song = (*this)i;
View file
ncmpc-0.36.tar.xz/src/Queue.hxx -> ncmpc-0.47.tar.xz/src/Queue.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,71 +19,64 @@ #ifndef QUEUE_HXX #define QUEUE_HXX -#include "util/Compiler.h" +#include "SongPtr.hxx" #include <mpd/client.h> #include <vector> -#include <memory> #include <assert.h> -struct SongDeleter { - void operator()(struct mpd_song *song) const { - mpd_song_free(song); - } -}; - struct MpdQueue { /* queue version number (obtained from mpd_status) */ unsigned version = 0; - using Vector = std::vector<std::unique_ptr<struct mpd_song, SongDeleter>>; + using Vector = std::vector<SongPtr>; /* the list */ Vector items; using size_type = Vector::size_type; - size_type size() const { + size_type size() const noexcept { return items.size(); } - bool empty() const { + bool empty() const noexcept { return items.empty(); } /** remove and free all songs in the playlist */ - void clear(); + void clear() noexcept; - const struct mpd_song &operator(size_type i) const { + const struct mpd_song &operator(size_type i) const noexcept { assert(i < size()); return *itemsi; } - struct mpd_song &operator(size_type i) { + struct mpd_song &operator(size_type i) noexcept { assert(i < size()); return *itemsi; } - gcc_pure - const struct mpd_song *GetChecked(int i) const; + gnu::pure + const struct mpd_song *GetChecked(int i) const noexcept; - void push_back(const struct mpd_song &song) { + void push_back(const struct mpd_song &song) noexcept { items.emplace_back(mpd_song_dup(&song)); } - void Replace(size_type i, const struct mpd_song &song) { + void Replace(size_type i, const struct mpd_song &song) noexcept { itemsi.reset(mpd_song_dup(&song)); } - void RemoveIndex(size_type i) { + void RemoveIndex(size_type i) noexcept { items.erase(std::next(items.begin(), i)); } - void Move(unsigned dest, unsigned src); + void Move(unsigned dest, unsigned src) noexcept; /** * Find a song by its reference. This method compares @@ -93,40 +85,40 @@ * * @return the song position */ - gcc_pure - size_type FindByReference(const struct mpd_song &song) const; + gnu::pure + size_type FindByReference(const struct mpd_song &song) const noexcept; /** * Find a song by its id. * * @return the song position */ - gcc_pure - int FindById(unsigned id) const; + gnu::pure + int FindById(unsigned id) const noexcept; /** * Find a song by its URI. * * @return the song position */ - gcc_pure - int FindByUri(const char *uri) const; + gnu::pure + int FindByUri(const char *uri) const noexcept; /** * Like FindByUri(), but return the song id, not the song position * * @return the song id */ - gcc_pure - int FindIdByUri(const char *uri) const { + gnu::pure + int FindIdByUri(const char *uri) const noexcept { int i = FindByUri(uri); if (i >= 0) i = mpd_song_get_id(itemsi.get()); return i; } - gcc_pure - bool ContainsUri(const char *uri) const { + gnu::pure + bool ContainsUri(const char *uri) const noexcept { return FindByUri(uri) >= 0; } };
View file
ncmpc-0.36.tar.xz/src/QueuePage.cxx -> ncmpc-0.47.tar.xz/src/QueuePage.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -42,7 +41,7 @@ #include "SongPage.hxx" #include "LyricsPage.hxx" #include "db_completion.hxx" -#include "util/Compiler.h" +#include "event/CoarseTimerEvent.hxx" #ifndef NCMPC_MINI #include "hscroll.hxx" @@ -50,8 +49,6 @@ #include <mpd/client.h> -#include <boost/asio/steady_timer.hpp> - #include <set> #include <string> @@ -66,7 +63,7 @@ mutable class hscroll hscroll; #endif - boost::asio::steady_timer hide_cursor_timer; + CoarseTimerEvent hide_cursor_timer; MpdQueue *playlist = nullptr; int current_song_id = -1; @@ -83,15 +80,16 @@ :ListPage(w, size), screen(_screen), #ifndef NCMPC_MINI - hscroll(screen.get_io_service(), + hscroll(screen.GetEventLoop(), w, options.scroll_sep.c_str()), #endif - hide_cursor_timer(screen.get_io_service()) + hide_cursor_timer(screen.GetEventLoop(), + BIND_THIS_METHOD(OnHideCursorTimer)) { } private: - gcc_pure + gnu::pure const struct mpd_song *GetSelectedSong() const; void SaveSelection(); @@ -107,16 +105,12 @@ bool OnSongChange(const struct mpd_status *status); - void OnHideCursorTimer(const boost::system::error_code &error) noexcept; + void OnHideCursorTimer() noexcept; void ScheduleHideCursor() { assert(options.hide_cursor > std::chrono::steady_clock::duration::zero()); - boost::system::error_code error; - hide_cursor_timer.expires_from_now(options.hide_cursor, - error); - hide_cursor_timer.async_wait(std::bind(&QueuePage::OnHideCursorTimer, this, - std::placeholders::_1)); + hide_cursor_timer.Schedule(options.hide_cursor); } /* virtual methods from class ListRenderer */ @@ -219,7 +213,7 @@ lw.FetchCursor(); } -gcc_pure +gnu::pure static int get_current_song_id(const struct mpd_status *status) { @@ -330,18 +324,15 @@ return std::make_unique<QueuePage>(_screen, w, size); } -void -QueuePage::OnHideCursorTimer(const boost::system::error_code &error) noexcept +inline void +QueuePage::OnHideCursorTimer() noexcept { - if (error) - return; - assert(options.hide_cursor > std::chrono::steady_clock::duration::zero()); /* hide the cursor when mpd is playing and the user is inactive */ if (playing) { - lw.DisableCursor(); + lw.HideCursor(); Repaint(); } else ScheduleHideCursor(); @@ -353,7 +344,7 @@ playlist = &c.playlist; if (options.hide_cursor > std::chrono::steady_clock::duration::zero()) { - lw.EnableCursor(); + lw.ShowCursor(); ScheduleHideCursor(); } @@ -364,7 +355,7 @@ void QueuePage::OnClose() noexcept { - hide_cursor_timer.cancel(); + hide_cursor_timer.Cancel(); #ifndef NCMPC_MINI if (options.scroll) @@ -500,9 +491,10 @@ mpd_song_get_id(song))) c.HandleError(); } - } else if (bstate & BUTTON3_CLICKED) { + } else if (bstate & (BUTTON3_CLICKED|BUTTON3_DOUBLE_CLICKED)) { /* delete */ - if (lw.GetCursorIndex() == old_selected) + if ((bstate & BUTTON3_DOUBLE_CLICKED) || + lw.GetCursorIndex() == old_selected) c.RunDelete(lw.GetCursorIndex()); lw.SetLength(playlist->size()); @@ -524,7 +516,7 @@ const Command prev_cmd = cached_cmd; cached_cmd = cmd; - lw.EnableCursor(); + lw.ShowCursor(); if (options.hide_cursor > std::chrono::steady_clock::duration::zero()) { ScheduleHideCursor(); @@ -536,22 +528,19 @@ } switch(cmd) { - int pos; - case Command::SCREEN_UPDATE: CenterPlayingItem(c.status, prev_cmd == Command::SCREEN_UPDATE); SetDirty(); return false; case Command::SELECT_PLAYING: - pos = c.GetCurrentSongPos(); - if (pos < 0) + if (int pos = c.GetCurrentSongPos(); pos >= 0) { + lw.SetCursor(pos); + SaveSelection(); + SetDirty(); + return true; + } else return false; - lw.SetCursor(pos); - SaveSelection(); - SetDirty(); - return true; - case Command::LIST_FIND: case Command::LIST_RFIND: case Command::LIST_FIND_NEXT: @@ -606,27 +595,24 @@ return false; switch(cmd) { - const struct mpd_song *song; - ListWindowRange range; - case Command::PLAY: - song = GetSelectedSong(); - if (song == nullptr) - return false; - - connection = c.GetConnection(); - if (connection != nullptr && - !mpd_run_play_id(connection, mpd_song_get_id(song))) - c.HandleError(); + if (const auto *song = GetSelectedSong()) { + if (connection = c.GetConnection(); + connection != nullptr && + !mpd_run_play_id(connection, mpd_song_get_id(song))) + c.HandleError(); - return true; + return true; + } else + return false; - case Command::DELETE: - range = lw.GetRange(); + case Command::DELETE: { + const auto range = lw.GetRange(); c.RunDeleteRange(range.start_index, range.end_index); lw.SetCursor(range.start_index); return true; + } case Command::SAVE_PLAYLIST: playlist_save(&c, nullptr, nullptr); @@ -636,8 +622,8 @@ handle_add_to_playlist(&c); return true; - case Command::SHUFFLE: - range = lw.GetRange(); + case Command::SHUFFLE: { + const auto range = lw.GetRange(); if (range.end_index <= range.start_index + 1) /* No range selection, shuffle all list. */ break; @@ -652,9 +638,10 @@ else c.HandleError(); return true; + } - case Command::LIST_MOVE_UP: - range = lw.GetRange(); + case Command::LIST_MOVE_UP: { + const auto range = lw.GetRange(); if (range.start_index == 0 || range.empty()) return false; @@ -664,9 +651,10 @@ lw.SelectionMovedUp(); SaveSelection(); return true; + } - case Command::LIST_MOVE_DOWN: - range = lw.GetRange(); + case Command::LIST_MOVE_DOWN: { + const auto range = lw.GetRange(); if (range.end_index >= playlist->size()) return false; @@ -676,6 +664,7 @@ lw.SelectionMovedDown(); SaveSelection(); return true; + } case Command::LOCATE: if (GetSelectedSong() != nullptr) {
View file
ncmpc-0.36.tar.xz/src/QueuePage.hxx -> ncmpc-0.47.tar.xz/src/QueuePage.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/SearchPage.cxx -> ncmpc-0.47.tar.xz/src/SearchPage.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -30,13 +29,15 @@ #include "screen_utils.hxx" #include "FileListPage.hxx" #include "filelist.hxx" -#include "util/Macros.hxx" + +#include <iterator> #include <string.h> enum { SEARCH_URI = MPD_TAG_COUNT + 100, - SEARCH_ARTIST_TITLE + SEARCH_MODIFIED, + SEARCH_ARTIST_TITLE, }; static constexpr struct { @@ -64,6 +65,9 @@ strcasecmp(name, _("file")) == 0) return SEARCH_URI; + if (strcasecmp(name, "modified") == 0) + return SEARCH_MODIFIED; + for (unsigned i = 0; search_tagi.name != nullptr; ++i) if (strcasecmp(search_tagi.name, name) == 0 || strcasecmp(search_tagi.localname, name) == 0) @@ -72,12 +76,12 @@ return -1; } -typedef struct { +struct SearchMode { enum mpd_tag_type table; const char *label; -} search_type_t; +}; -static constexpr search_type_t mode = { +static constexpr SearchMode mode = { { MPD_TAG_TITLE, N_("Title") }, { MPD_TAG_ARTIST, N_("Artist") }, { MPD_TAG_ALBUM, N_("Album") }, @@ -95,6 +99,7 @@ "", "Advanced - <tag>:<search term> <tag>:<search term>...", " Example: artist:radiohead album:pablo honey", + " Example: modified:14d (units: s, M, h, d, m, y)", "", " Available tags: artist, album, title, track,", " name, genre, date composer, performer, comment, file", @@ -108,17 +113,17 @@ std::string pattern; public: - SearchPage(ScreenManager &_screen, WINDOW *_w, Size size) + SearchPage(ScreenManager &_screen, WINDOW *_w, Size size) noexcept :FileListPage(_screen, _w, size, !options.search_format.empty() ? options.search_format.c_str() : options.list_format.c_str()) { - lw.DisableCursor(); - lw.SetLength(ARRAY_SIZE(help_text)); + lw.HideCursor(); + lw.SetLength(std::size(help_text)); } private: - void Clear(bool clear_pattern); + void Clear(bool clear_pattern) noexcept; void Reload(struct mpdclient &c); void Start(struct mpdclient &c); @@ -136,7 +141,7 @@ /* virtual methods from class ListText */ const char *GetListItemText(char *buffer, size_t size, unsigned idx) const noexcept override { - assert(idx < ARRAY_SIZE(help_text)); + assert(idx < std::size(help_text)); if (idx == 0) { snprintf(buffer, size, @@ -160,11 +165,10 @@ }; void -SearchPage::Clear(bool clear_pattern) +SearchPage::Clear(bool clear_pattern) noexcept { if (filelist) { - delete filelist; - filelist = new FileList(); + filelist = std::make_unique<FileList>(); lw.SetLength(0); } if (clear_pattern) @@ -173,11 +177,10 @@ SetDirty(); } -static FileList * +static std::unique_ptr<FileList> search_simple_query(struct mpd_connection *connection, bool exact_match, int table, const char *local_pattern) { - FileList *list; const LocaleToUtf8 filter_utf8(local_pattern); if (table == SEARCH_ARTIST_TITLE) { @@ -197,15 +200,16 @@ mpd_command_list_end(connection); - list = filelist_new_recv(connection); + auto list = filelist_new_recv(connection); list->RemoveDuplicateSongs(); + return list; } else if (table == SEARCH_URI) { mpd_search_db_songs(connection, exact_match); mpd_search_add_uri_constraint(connection, MPD_OPERATOR_DEFAULT, filter_utf8.c_str()); mpd_search_commit(connection); - list = filelist_new_recv(connection); + return filelist_new_recv(connection); } else { mpd_search_db_songs(connection, exact_match); mpd_search_add_tag_constraint(connection, MPD_OPERATOR_DEFAULT, @@ -213,10 +217,67 @@ filter_utf8.c_str()); mpd_search_commit(connection); - list = filelist_new_recv(connection); + return filelist_new_recv(connection); + } +} + +/** + * Throws on error. + */ +static time_t +ParseModifiedSince(const char *s) +{ + char *endptr; + time_t value = strtoul(s, &endptr, 10); + if (endptr == s) + throw _("Invalid number"); + + constexpr time_t MINUTE = 60; + constexpr time_t HOUR = 60 * MINUTE; + constexpr time_t DAY = 24 * HOUR; + constexpr time_t MONTH = 30 * DAY; // TODO: inaccurate + constexpr time_t YEAR = 365 * DAY; // TODO: inaccurate + + s = endptr; + switch (*s) { + case 's': + ++s; + break; + + case 'M': + ++s; + value *= MINUTE; + break; + + case 'h': + ++s; + value *= HOUR; + break; + + case 'd': + ++s; + value *= DAY; + break; + + case 'm': + ++s; + value *= MONTH; + break; + + case 'y': + case 'Y': + ++s; + value *= YEAR; + break; + + default: + throw _("Unrecognized suffix"); } - return list; + if (*s != '\0') + throw _("Unrecognized suffix"); + + return time(nullptr) - value; } /*----------------------------------------------------------------------- @@ -224,9 +285,9 @@ * Its ugly and MUST be redesigned before the next release! *----------------------------------------------------------------------- */ -static FileList * +static std::unique_ptr<FileList> search_advanced_query(struct mpd_connection *connection, const char *query) -{ +try { advanced_search_mode = false; if (strchr(query, ':') == nullptr) return nullptr; @@ -296,6 +357,10 @@ mpd_search_add_uri_constraint(connection, MPD_OPERATOR_DEFAULT, value.c_str()); + else if (tablei == SEARCH_MODIFIED) + mpd_search_add_modified_since_constraint(connection, + MPD_OPERATOR_DEFAULT, + ParseModifiedSince(value.c_str())); else mpd_search_add_tag_constraint(connection, MPD_OPERATOR_DEFAULT, @@ -304,23 +369,24 @@ } mpd_search_commit(connection); - auto *fl = filelist_new_recv(connection); - if (!mpd_response_finish(connection)) { - delete fl; - fl = nullptr; - } + auto fl = filelist_new_recv(connection); + if (!mpd_response_finish(connection)) + fl.reset(); return fl; +} catch (...) { + mpd_search_cancel(connection); + throw; } -static FileList * +static std::unique_ptr<FileList> do_search(struct mpdclient *c, const char *query) { auto *connection = c->GetConnection(); if (connection == nullptr) return nullptr; - auto *fl = search_advanced_query(connection, query); + auto fl = search_advanced_query(connection, query); if (fl != nullptr) return fl; @@ -343,14 +409,13 @@ if (pattern.empty()) return; - lw.EnableCursor(); - delete filelist; + lw.ShowCursor(); filelist = do_search(&c, pattern.c_str()); if (filelist == nullptr) - filelist = new FileList(); + filelist = std::make_unique<FileList>(); lw.SetLength(filelist->size()); - screen_browser_sync_highlights(filelist, &c.playlist); + screen_browser_sync_highlights(*filelist, c.playlist); SetDirty(); } @@ -413,7 +478,7 @@ SearchPage::Update(struct mpdclient &c, unsigned events) noexcept { if (filelist != nullptr && events & MPD_IDLE_QUEUE) { - screen_browser_sync_highlights(filelist, &c.playlist); + screen_browser_sync_highlights(*filelist, c.playlist); SetDirty(); } }
View file
ncmpc-0.36.tar.xz/src/SearchPage.hxx -> ncmpc-0.47.tar.xz/src/SearchPage.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/Size.hxx -> ncmpc-0.47.tar.xz/src/Size.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -26,19 +25,19 @@ struct Size { unsigned width, height; - constexpr bool operator==(Size other) const { + constexpr bool operator==(Size other) const noexcept { return width == other.width && height == other.height; } - constexpr bool operator!=(Size other) const { + constexpr bool operator!=(Size other) const noexcept { return !(*this == other); } - constexpr Size operator+(Size other) const { + constexpr Size operator+(Size other) const noexcept { return {width + other.width, height + other.height}; } - constexpr Size operator-(Size other) const { + constexpr Size operator-(Size other) const noexcept { return {width - other.width, height - other.height}; } };
View file
ncmpc-0.36.tar.xz/src/SongPage.cxx -> ncmpc-0.47.tar.xz/src/SongPage.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -32,12 +31,12 @@ #include "time_format.hxx" #include "mpdclient.hxx" #include "util/LocaleString.hxx" -#include "util/Macros.hxx" #include "util/StringStrip.hxx" #include <mpd/client.h> #include <algorithm> +#include <iterator> #include <vector> #include <string> @@ -58,13 +57,22 @@ const char *label; }; +/* note: add all tags mentioned here to #global_tag_whitelist in + Instance.cxx */ static constexpr struct tag_label tag_labels = { { MPD_TAG_ARTIST, N_("Artist") }, { MPD_TAG_TITLE, N_("Title") }, { MPD_TAG_ALBUM, N_("Album") }, +#if LIBMPDCLIENT_CHECK_VERSION(2,17,0) + { MPD_TAG_WORK, N_("Work") }, +#endif { LABEL_LENGTH, N_("Length") }, { LABEL_POSITION, N_("Position") }, { MPD_TAG_COMPOSER, N_("Composer") }, + { MPD_TAG_PERFORMER, N_("Performer") }, +#if LIBMPDCLIENT_CHECK_VERSION(2,17,0) + { MPD_TAG_CONDUCTOR, N_("Conductor") }, +#endif { MPD_TAG_NAME, N_("Name") }, { MPD_TAG_DISC, N_("Disc") }, { MPD_TAG_TRACK, N_("Track") }, @@ -115,7 +123,7 @@ SongPage(ScreenManager &_screen, WINDOW *w, Size size) noexcept :ListPage(w, size), screen(_screen) { - lw.DisableCursor(); + lw.HideCursor(); } ~SongPage() noexcept override { @@ -186,7 +194,7 @@ max_tag_label_width = width; } - for (unsigned i = 0; i < ARRAY_SIZE(stats_labels); ++i) { + for (unsigned i = 0; i < std::size(stats_labels); ++i) { if (stats_labelsi != nullptr) { unsigned width = StringWidthMB(gettext(stats_labelsi)); @@ -199,7 +207,8 @@ } const char * -SongPage::GetTitle(gcc_unused char *str, gcc_unused size_t size) const noexcept +SongPage::GetTitle(maybe_unused char *str, + maybe_unused size_t size) const noexcept { return _("Song viewer"); } @@ -267,7 +276,7 @@ } } -gcc_pure +gnu::pure static const char * get_tag_label(unsigned tag) noexcept { @@ -287,7 +296,7 @@ unsigned i = 0; const char *value; - assert((unsigned)tag < ARRAY_SIZE(tag_labels)); + assert((unsigned)tag < std::size(tag_labels)); assert(label != nullptr); while ((value = mpd_song_get_tag(song, tag, i++)) != nullptr) @@ -404,7 +413,6 @@ audio_format_to_string(char *buffer, size_t size, const struct mpd_audio_format *format) noexcept { -#if LIBMPDCLIENT_CHECK_VERSION(2,10,0) if (format->bits == MPD_SAMPLE_FORMAT_FLOAT) { snprintf(buffer, size, "%u:f:%u", format->sample_rate, @@ -428,7 +436,6 @@ format->channels); return; } -#endif snprintf(buffer, size, "%u:%u:%u", format->sample_rate, format->bits, @@ -541,8 +548,6 @@ } if (screen_find(screen, lw, cmd, *this)) { - /* center the row */ - lw.Center(lw.GetCursorIndex()); SetDirty(); return true; }
View file
ncmpc-0.36.tar.xz/src/SongPage.hxx -> ncmpc-0.47.tar.xz/src/SongPage.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.47.tar.xz/src/SongPtr.hxx
Added
@@ -0,0 +1,28 @@ +/* ncmpc (Ncurses MPD Client) + * Copyright 2004-2021 The Music Player Daemon Project + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef SONG_PTR_HXX +#define SONG_PTR_HXX + +#include "Deleter.hxx" + +#include <memory> + +using SongPtr = std::unique_ptr<struct mpd_song, LibmpdclientDeleter>; + +#endif
View file
ncmpc-0.36.tar.xz/src/SongRowPaint.cxx -> ncmpc-0.47.tar.xz/src/SongRowPaint.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -30,9 +29,9 @@ #include <string.h> void -paint_song_row(WINDOW *w, gcc_unused unsigned y, unsigned width, +paint_song_row(WINDOW *w, maybe_unused unsigned y, unsigned width, bool selected, bool highlight, const struct mpd_song *song, - gcc_unused class hscroll *hscroll, const char *format) + maybe_unused class hscroll *hscroll, const char *format) { char buffer1024; @@ -51,7 +50,8 @@ waddstr(w, duration); } - if (hscroll != nullptr && StringWidthMB(buffer) >= width) { + if (hscroll != nullptr && width > 3 && + StringWidthMB(buffer) >= width) { hscroll->Set(0, y, width, buffer, highlight ? Style::LIST_BOLD : Style::LIST, selected ? A_REVERSE : 0);
View file
ncmpc-0.36.tar.xz/src/SongRowPaint.hxx -> ncmpc-0.47.tar.xz/src/SongRowPaint.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/StatusBar.cxx -> ncmpc-0.47.tar.xz/src/StatusBar.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -30,12 +29,12 @@ #include <string.h> -StatusBar::StatusBar(boost::asio::io_service &io_service, +StatusBar::StatusBar(EventLoop &event_loop, Point p, unsigned width) noexcept :window(p, {width, 1u}), - message_timer(io_service) + message_timer(event_loop, BIND_THIS_METHOD(OnMessageTimer)) #ifndef NCMPC_MINI - , hscroll(io_service, window.w, options.scroll_sep.c_str()) + , hscroll(event_loop, window.w, options.scroll_sep.c_str()) #endif { leaveok(window.w, false); @@ -43,7 +42,7 @@ #ifdef ENABLE_COLORS if (options.enable_colors) - wbkgd(window.w, COLOR_PAIR(Style::STATUS)); + window.SetBackgroundStyle(Style::STATUS); #endif } @@ -58,28 +57,98 @@ void StatusBar::ClearMessage() noexcept { - message_timer.cancel(); + message_timer.Cancel(); message.clear(); Paint(); doupdate(); } -#ifndef NCMPC_MINI - -static void +static size_t format_bitrate(char *p, size_t max_length, const struct mpd_status *status) noexcept { - if (options.visible_bitrate && mpd_status_get_kbit_rate(status) > 0) + +#ifndef NCMPC_MINI + if (options.visible_bitrate && mpd_status_get_kbit_rate(status) > 0) { snprintf(p, max_length, " %d kbps", mpd_status_get_kbit_rate(status)); - else + return strlen(p); + } else { +#else + (void)max_length; + (void)status; +#endif p0 = '\0'; + return 0; +#ifndef NCMPC_MINI + } +#endif } -#endif /* !NCMPC_MINI */ +static void +FormatCurrentSongTime(char *buffer, size_t size, + const struct mpd_status &status, + const DelayedSeek &seek) noexcept +{ + if (options.current_time_display == CurrentTimeDisplay::NONE) + return; + + const unsigned total_time = mpd_status_get_total_time(&status); + + unsigned elapsed_time = seek.IsSeeking(mpd_status_get_song_id(&status)) + ? seek.GetTime() + : mpd_status_get_elapsed_time(&status); + + char elapsed_string32, duration_string32; + + /* checks the conf to see whether to display elapsed or + remaining time */ + switch (options.current_time_display) { + case CurrentTimeDisplay::NONE: + case CurrentTimeDisplay::ELAPSED: + break; + + case CurrentTimeDisplay::REMAINING: + if (total_time == 0) + return; + + elapsed_time = elapsed_time < total_time + ? total_time - elapsed_time + : 0; + break; + } + + /* write out the time */ + format_duration_short(elapsed_string, + sizeof(elapsed_string), + elapsed_time); + + if (total_time == 0) { + snprintf(buffer, size, " %s", elapsed_string); + return; + } + + format_duration_short(duration_string, + sizeof(duration_string), + total_time); + + snprintf(buffer, size, " %s/%s", elapsed_string, duration_string); +} + +inline size_t +FormatStatusRightText(char *buffer, size_t size, + const struct mpd_status &status, + const DelayedSeek &seek) noexcept +{ + /* display bitrate if visible-bitrate is true */ + size_t offset = format_bitrate(buffer, size, &status); + + FormatCurrentSongTime(buffer + offset, size - offset, status, seek); + + return StringWidthMB(buffer); +} void StatusBar::Update(const struct mpd_status *status, @@ -110,50 +179,9 @@ : 0; if (state == MPD_STATE_PLAY || state == MPD_STATE_PAUSE) { - unsigned elapsed_time = seek.IsSeeking(mpd_status_get_song_id(status)) - ? seek.GetTime() - : mpd_status_get_elapsed_time(status); - const unsigned total_time = mpd_status_get_total_time(status); - - if (elapsed_time > 0 || total_time > 0) { -#ifdef NCMPC_MINI - static char bitrate1; -#else - char bitrate16; -#endif - char elapsed_string32, duration_string32; - - /*checks the conf to see whether to display elapsed or remaining time */ - if (options.display_remaining_time) - elapsed_time = elapsed_time < total_time - ? total_time - elapsed_time - : 0; - - /* display bitrate if visible-bitrate is true */ -#ifndef NCMPC_MINI - format_bitrate(bitrate, sizeof(bitrate), status); -#endif - - /* write out the time */ - format_duration_short(elapsed_string, - sizeof(elapsed_string), - elapsed_time); - format_duration_short(duration_string, - sizeof(duration_string), - total_time); - - snprintf(right_text, sizeof(right_text), - "%s %s/%s", - bitrate, elapsed_string, duration_string); - } else { -#ifndef NCMPC_MINI - format_bitrate(right_text, sizeof(right_text), status); -#else - right_text0 = 0; -#endif - } - - right_width = StringWidthMB(right_text); + right_width = FormatStatusRightText(right_text, + sizeof(right_text), + *status, seek); #ifndef NCMPC_MINI int width = COLS - left_width - right_width; @@ -169,14 +197,16 @@ /* scroll if the song name is to long */ #ifndef NCMPC_MINI - center_width = StringWidthMB(center_text.c_str()); - if (options.scroll && width > 3 && - center_width > (unsigned)width) { - hscroll.Set(left_width, 0, width, center_text.c_str(), - Style::STATUS); - } else { - if (options.scroll) + if (options.scroll) { + const unsigned center_width = + StringWidthMB(center_text.c_str()); + if (width > 3 && center_width > (unsigned)width) { + hscroll.Set(left_width, 0, width, + center_text.c_str(), + Style::STATUS); + } else { hscroll.Clear(); + } } #endif } else { @@ -260,9 +290,5 @@ Paint(); doupdate(); - boost::system::error_code error; - message_timer.expires_from_now(options.status_message_time, - error); - message_timer.async_wait(std::bind(&StatusBar::OnMessageTimer, this, - std::placeholders::_1)); + message_timer.Schedule(options.status_message_time); }
View file
ncmpc-0.36.tar.xz/src/StatusBar.hxx -> ncmpc-0.47.tar.xz/src/StatusBar.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -21,15 +20,13 @@ #define NCMPC_STATUS_BAR_HXX #include "config.h" // IWYU pragma: keep -#include "AsioServiceFwd.hxx" #include "Window.hxx" +#include "event/CoarseTimerEvent.hxx" #ifndef NCMPC_MINI #include "hscroll.hxx" #endif -#include <boost/asio/steady_timer.hpp> - #include <string> struct mpd_status; @@ -40,7 +37,7 @@ Window window; std::string message; - boost::asio::steady_timer message_timer; + CoarseTimerEvent message_timer; #ifndef NCMPC_MINI class hscroll hscroll; @@ -52,12 +49,9 @@ std::string center_text; unsigned left_width, right_width; -#ifndef NCMPC_MINI - unsigned center_width; -#endif public: - StatusBar(boost::asio::io_service &io_service, + StatusBar(EventLoop &event_loop, Point p, unsigned width) noexcept; ~StatusBar() noexcept; @@ -75,9 +69,8 @@ void Paint() const noexcept; private: - void OnMessageTimer(const boost::system::error_code &error) noexcept { - if (!error) - ClearMessage(); + void OnMessageTimer() noexcept { + ClearMessage(); } };
View file
ncmpc-0.36.tar.xz/src/Styles.cxx -> ncmpc-0.47.tar.xz/src/Styles.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -23,7 +22,6 @@ #include "i18n.h" #include "util/RuntimeError.hxx" #include "util/StringStrip.hxx" -#include "util/Compiler.h" #ifdef ENABLE_COLORS #include "Options.hxx" @@ -195,7 +193,7 @@ #ifdef ENABLE_COLORS -gcc_pure +gnu::pure static Style StyleByName(const char *name) noexcept {
View file
ncmpc-0.36.tar.xz/src/Styles.hxx -> ncmpc-0.47.tar.xz/src/Styles.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/TabBar.cxx -> ncmpc-0.47.tar.xz/src/TabBar.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/TabBar.hxx -> ncmpc-0.47.tar.xz/src/TabBar.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/TagFilter.cxx -> ncmpc-0.47.tar.xz/src/TagFilter.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/TagFilter.hxx -> ncmpc-0.47.tar.xz/src/TagFilter.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,8 +19,6 @@ #ifndef NCMPC_TAG_FILTER_HXX #define NCMPC_TAG_FILTER_HXX -#include "util/Compiler.h" - #include <mpd/tag.h> #include <string> @@ -31,7 +28,7 @@ using TagFilter = std::forward_list<std::pair<enum mpd_tag_type, std::string>>; -gcc_pure +gnu::pure const char * FindTag(const TagFilter &filter, enum mpd_tag_type tag) noexcept; @@ -39,7 +36,7 @@ AddConstraints(struct mpd_connection *connection, const TagFilter &filter) noexcept; -gcc_pure +gnu::pure std::string ToString(const TagFilter &filter) noexcept;
View file
ncmpc-0.36.tar.xz/src/TagListPage.cxx -> ncmpc-0.47.tar.xz/src/TagListPage.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -49,7 +48,7 @@ return new_filter; } -gcc_pure +gnu::pure static bool CompareUTF8(const std::string &a, const std::string &b) { @@ -123,7 +122,7 @@ */ void TagListPage::PaintListItem(WINDOW *w, unsigned i, - gcc_unused unsigned y, unsigned width, + maybe_unused unsigned y, unsigned width, bool selected) const noexcept { if (parent != nullptr) { @@ -166,6 +165,16 @@ } } +bool +TagListPage::HandleEnter(struct mpdclient &c) +{ + if (lw.GetCursorIndex() == 0 && parent != nullptr) + /* handle ".." */ + return parent->OnCommand(c, Command::GO_PARENT_DIRECTORY); + + return false; +} + /* add_query - Add all songs satisfying specified criteria. _artist is actually only used in the ALBUM case to distinguish albums with the same name from different artists. */ @@ -178,8 +187,10 @@ return; const char *text = value; - if (value == nullptr) - value = filter.empty() ? "?" : filter.front().second.c_str(); + if (text == nullptr) + /* adding the special "All" entry: show the name of + the previous level in the filter */ + text = filter.empty() ? "?" : filter.front().second.c_str(); screen_status_printf(_("Adding \'%s\' to queue"), Utf8ToLocale(text).c_str()); @@ -196,31 +207,40 @@ } bool +TagListPage::HandleSelect(struct mpdclient &c) +{ + bool result = false; + + for (unsigned i : lw.GetRange()) { + if (parent != nullptr) { + if (i == 0) + continue; + + --i; + } + + add_query(&c, filter, tag, + i < values.size() + ? valuesi.c_str() : nullptr); + result = true; + } + + return result; +} + + +bool TagListPage::OnCommand(struct mpdclient &c, Command cmd) { switch(cmd) { case Command::PLAY: - if (lw.GetCursorIndex() == 0 && parent != nullptr) - /* handle ".." */ - return parent->OnCommand(c, Command::GO_PARENT_DIRECTORY); - - break; + return HandleEnter(c); case Command::SELECT: case Command::ADD: - for (unsigned i : lw.GetRange()) { - if (parent != nullptr) { - if (i == 0) - continue; - - --i; - } - - add_query(&c, filter, tag, - i < values.size() - ? valuesi.c_str() : nullptr); + if (HandleSelect(c)) cmd = Command::LIST_NEXT; /* continue and select next item... */ - } + break; /* continue and update... */ @@ -252,3 +272,33 @@ return false; } + +#ifdef HAVE_GETMOUSE + +bool +TagListPage::OnMouse(struct mpdclient &c, Point p, + mmask_t bstate) +{ + unsigned prev_selected = lw.GetCursorIndex(); + + if (ListPage::OnMouse(c, p, bstate)) + return true; + + lw.SetCursorFromOrigin(p.y); + + if (bstate & (BUTTON1_CLICKED|BUTTON1_DOUBLE_CLICKED)) { + if ((bstate & BUTTON1_DOUBLE_CLICKED) || + prev_selected == lw.GetCursorIndex()) + HandleEnter(c); + } else if (bstate & (BUTTON3_CLICKED|BUTTON3_DOUBLE_CLICKED)) { + if ((bstate & BUTTON3_DOUBLE_CLICKED) || + prev_selected == lw.GetCursorIndex()) + HandleSelect(c); + } + + SetDirty(); + + return true; +} + +#endif
View file
ncmpc-0.36.tar.xz/src/TagListPage.hxx -> ncmpc-0.47.tar.xz/src/TagListPage.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -30,7 +29,7 @@ class ScreenManager; -class TagListPage final : public ListPage, ListRenderer, ListText { +class TagListPage : public ListPage, ListRenderer, ListText { ScreenManager &screen; Page *const parent; @@ -74,7 +73,12 @@ */ TagFilter MakeCursorFilter() const noexcept; - gcc_pure + gnu::pure + bool HasMultipleValues() const noexcept { + return values.size() > 1; + } + + gnu::pure const char *GetSelectedValue() const { unsigned i = lw.GetCursorIndex(); @@ -90,7 +94,12 @@ : nullptr; } +protected: + virtual bool HandleEnter(struct mpdclient &c); + private: + bool HandleSelect(struct mpdclient &c); + void LoadValues(struct mpdclient &c) noexcept; void Reload(struct mpdclient &c); @@ -99,6 +108,12 @@ void Paint() const noexcept override; void Update(struct mpdclient &c, unsigned events) noexcept override; bool OnCommand(struct mpdclient &c, Command cmd) override; + +#ifdef HAVE_GETMOUSE + bool OnMouse(struct mpdclient &c, Point p, + mmask_t bstate) override; +#endif + const char *GetTitle(char *s, size_t size) const noexcept override; /* virtual methods from class ListRenderer */
View file
ncmpc-0.36.tar.xz/src/TagMask.hxx -> ncmpc-0.47.tar.xz/src/TagMask.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/TextListRenderer.cxx -> ncmpc-0.47.tar.xz/src/TextListRenderer.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/TextListRenderer.hxx -> ncmpc-0.47.tar.xz/src/TextListRenderer.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/TextPage.cxx -> ncmpc-0.47.tar.xz/src/TextPage.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -89,10 +88,14 @@ if (ListPage::OnCommand(c, cmd)) return true; - lw.SetCursorFromOrigin(0); + if (!lw.IsCursorVisible()) + /* start searching at the beginning of the page (not + where the invisible cursor just happens to be), + unless the cursor is still visible from the last + search */ + lw.SetCursorFromOrigin(0); + if (screen_find(screen, lw, cmd, *this)) { - /* center the row */ - lw.Center(lw.GetCursorIndex()); SetDirty(); return true; }
View file
ncmpc-0.36.tar.xz/src/TextPage.hxx -> ncmpc-0.47.tar.xz/src/TextPage.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -42,7 +41,7 @@ TextPage(ScreenManager &_screen, WINDOW *w, Size size) noexcept :ListPage(w, size), screen(_screen) { - lw.DisableCursor(); + lw.HideCursor(); } protected:
View file
ncmpc-0.36.tar.xz/src/TitleBar.cxx -> ncmpc-0.47.tar.xz/src/TitleBar.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -38,7 +37,7 @@ #ifdef ENABLE_COLORS if (options.enable_colors) - wbkgd(window.w, COLOR_PAIR(Style::TITLE)); + window.SetBackgroundStyle(Style::TITLE); #endif }
View file
ncmpc-0.36.tar.xz/src/TitleBar.hxx -> ncmpc-0.47.tar.xz/src/TitleBar.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/WaitUserInput.hxx -> ncmpc-0.47.tar.xz/src/WaitUserInput.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/Window.hxx -> ncmpc-0.47.tar.xz/src/Window.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -25,26 +24,32 @@ #include <curses.h> +enum class Style : unsigned; + struct Window { WINDOW *const w; Size size; - Window(Point p, Size _size) + Window(Point p, Size _size) noexcept :w(newwin(_size.height, _size.width, p.y, p.x)), size(_size) {} - ~Window() { + ~Window() noexcept { delwin(w); } Window(const Window &) = delete; Window &operator=(const Window &) = delete; - void Move(Point p) { + void SetBackgroundStyle(Style style) noexcept { + wbkgd(w, COLOR_PAIR(unsigned(style))); + } + + void Move(Point p) noexcept { mvwin(w, p.y, p.x); } - void Resize(Size new_size) { + void Resize(Size new_size) noexcept { size = new_size; wresize(w, size.height, size.width); }
View file
ncmpc-0.36.tar.xz/src/XdgBaseDirectory.cxx -> ncmpc-0.47.tar.xz/src/XdgBaseDirectory.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -24,7 +23,7 @@ #include <stdlib.h> #include <sys/stat.h> -gcc_pure +gnu::pure static bool IsDirectory(const char *path) noexcept { @@ -74,3 +73,27 @@ ? BuildPath(directory, filename) : std::string(); } + +std::string +GetHomeCacheDirectory() noexcept +{ + const char *cache_home = getenv("XDG_CACHE_HOME"); + if (cache_home != nullptr && *cache_home != 0) + return cache_home; + + const char *home = GetHomeDirectory(); + if (home != nullptr) + return BuildPath(home, ".cache"); + + return {}; +} + +std::string +GetHomeCacheDirectory(const char *package) noexcept +{ + const auto dir = GetHomeCacheDirectory(); + if (dir.empty()) + return {}; + + return BuildPath(dir, package); +}
View file
ncmpc-0.36.tar.xz/src/XdgBaseDirectory.hxx -> ncmpc-0.47.tar.xz/src/XdgBaseDirectory.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,19 +19,17 @@ #ifndef XDG_BASE_DIRECTORY_HXX #define XDG_BASE_DIRECTORY_HXX -#include "util/Compiler.h" - #include <string> -gcc_const +gnu::const const char * GetHomeDirectory() noexcept; -gcc_const +gnu::const std::string GetHomeConfigDirectory() noexcept; -gcc_pure +gnu::pure std::string GetHomeConfigDirectory(const char *package) noexcept; @@ -45,4 +42,12 @@ std::string MakeUserConfigPath(const char *filename) noexcept; +gnu::const +std::string +GetHomeCacheDirectory() noexcept; + +gnu::pure +std::string +GetHomeCacheDirectory(const char *package) noexcept; + #endif
View file
ncmpc-0.36.tar.xz/src/aconnect.cxx -> ncmpc-0.47.tar.xz/src/aconnect.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - (c) 2004-2019 The Music Player Daemon Project - Project homepage: http://musicpd.org + Copyright 2004-2021 The Music Player Daemon Project Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -28,104 +27,94 @@ #include "aconnect.hxx" #include "net/AsyncResolveConnect.hxx" -#include "net/AsyncHandler.hxx" +#include "net/SocketError.hxx" +#include "net/UniqueSocketDescriptor.hxx" +#include "system/Error.hxx" +#include "event/SocketEvent.hxx" #include <mpd/client.h> #include <mpd/async.h> -#include <boost/asio/generic/stream_protocol.hpp> +#include <cstdio> +#include <cstring> -struct AsyncMpdConnect final : AsyncConnectHandler { +struct AsyncMpdConnect final : ConnectSocketHandler { AsyncMpdConnectHandler &handler; AsyncResolveConnect rconnect; - boost::asio::generic::stream_protocol::socket socket; + SocketEvent socket; - char buffer256; - - explicit AsyncMpdConnect(boost::asio::io_service &io_service, + explicit AsyncMpdConnect(EventLoop &event_loop, AsyncMpdConnectHandler &_handler) noexcept :handler(_handler), - rconnect(io_service, *this), socket(io_service) {} + rconnect(event_loop, *this), + socket(event_loop, BIND_THIS_METHOD(OnReceive)) {} - void OnReceive(const boost::system::error_code &error, - std::size_t bytes_transferred) noexcept; + ~AsyncMpdConnect() noexcept { + socket.Close(); + } + + void OnReceive(unsigned events) noexcept; /* virtual methods from AsyncConnectHandler */ - void OnConnect(boost::asio::generic::stream_protocol::socket socket) override; - void OnConnectError(const char *message) override; + void OnSocketConnectSuccess(UniqueSocketDescriptor fd) noexcept override; + void OnSocketConnectError(std::exception_ptr ep) noexcept override; }; void -AsyncMpdConnect::OnReceive(const boost::system::error_code &error, - std::size_t bytes_transferred) noexcept -{ - if (error) { - if (error == boost::asio::error::operation_aborted) - /* this object has already been deleted; bail out - quickly without touching anything */ - return; - - snprintf(buffer, sizeof(buffer), - "Failed to receive from MPD: %s", - error.message().c_str()); - handler.OnAsyncMpdConnectError(buffer); - delete this; - return; - } +AsyncMpdConnect::OnReceive(unsigned) noexcept +try { + char buffer256; + ssize_t nbytes = socket.GetSocket().Read(buffer, sizeof(buffer)); - bufferbytes_transferred = 0; + if (nbytes < 0) + throw MakeSocketError("Failed to receive from MPD"); - /* the dup() is necessary because Boost 1.62 doesn't have the - release() method yet */ - struct mpd_async *async = mpd_async_new(dup(socket.native_handle())); - if (async == nullptr) { - handler.OnAsyncMpdConnectError("Out of memory"); - delete this; - return; - } + buffernbytes = 0; + + struct mpd_async *async = mpd_async_new(socket.ReleaseSocket().Get()); + if (async == nullptr) + throw std::bad_alloc{}; struct mpd_connection *c = mpd_connection_new_async(async, buffer); if (c == nullptr) { mpd_async_free(async); - handler.OnAsyncMpdConnectError("Out of memory"); - delete this; - return; + throw std::bad_alloc{}; } handler.OnAsyncMpdConnect(c); delete this; +} catch (...) { + handler.OnAsyncMpdConnectError(std::current_exception()); + delete this; } void -AsyncMpdConnect::OnConnect(boost::asio::generic::stream_protocol::socket _socket) +AsyncMpdConnect::OnSocketConnectSuccess(UniqueSocketDescriptor fd) noexcept { - socket = std::move(_socket); - socket.async_receive(boost::asio::buffer(buffer, sizeof(buffer) - 1), - std::bind(&AsyncMpdConnect::OnReceive, this, - std::placeholders::_1, - std::placeholders::_2)); + socket.Open(fd.Release()); + socket.ScheduleRead(); } void -AsyncMpdConnect::OnConnectError(const char *message) +AsyncMpdConnect::OnSocketConnectError(std::exception_ptr e) noexcept { - handler.OnAsyncMpdConnectError(message); + handler.OnAsyncMpdConnectError(std::move(e)); delete this; } void -aconnect_start(boost::asio::io_service &io_service, +aconnect_start(EventLoop &event_loop, AsyncMpdConnect **acp, const char *host, unsigned port, AsyncMpdConnectHandler &handler) { - auto *ac = new AsyncMpdConnect(io_service, handler); + auto *ac = new AsyncMpdConnect(event_loop, handler); *acp = ac; - ac->rconnect.Start(io_service, host, port); + ac->rconnect.Start(host, port); } void
View file
ncmpc-0.36.tar.xz/src/aconnect.hxx -> ncmpc-0.47.tar.xz/src/aconnect.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - (c) 2004-2019 The Music Player Daemon Project - Project homepage: http://musicpd.org + Copyright 2004-2021 The Music Player Daemon Project Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -29,21 +28,22 @@ #ifndef ACONNECT_H #define ACONNECT_H -#include "AsioServiceFwd.hxx" +#include <exception> #include <mpd/client.h> struct mpd_connection; struct AsyncMpdConnect; +class EventLoop; class AsyncMpdConnectHandler { public: virtual void OnAsyncMpdConnect(struct mpd_connection *c) noexcept = 0; - virtual void OnAsyncMpdConnectError(const char *message) noexcept = 0; + virtual void OnAsyncMpdConnectError(std::exception_ptr e) noexcept = 0; }; void -aconnect_start(boost::asio::io_service &io_service, +aconnect_start(EventLoop &event_loop, AsyncMpdConnect **acp, const char *host, unsigned port, AsyncMpdConnectHandler &handler);
View file
ncmpc-0.36.tar.xz/src/callbacks.cxx -> ncmpc-0.47.tar.xz/src/callbacks.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -24,16 +23,14 @@ #include <curses.h> -static bool -_mpdclient_auth_callback(struct mpdclient *c, unsigned recursion) +bool +mpdclient_auth_callback(struct mpdclient *c) noexcept { auto *connection = c->GetConnection(); if (connection == nullptr) return false; mpd_connection_clear_error(connection); - if (recursion > 2) - return false; const auto password = screen_read_password(nullptr); if (password.empty()) @@ -41,26 +38,27 @@ mpd_send_password(connection, password.c_str()); - mpd_response_finish(connection); - c->Update(); - - if (mpd_connection_get_error(connection) == MPD_ERROR_SERVER && - mpd_connection_get_server_error(connection) == MPD_SERVER_ERROR_PASSWORD) - return _mpdclient_auth_callback(c, ++recursion); + if (!mpd_response_finish(connection)) { + c->HandleAuthError(); + return false; + } + c->Update(); return true; } -bool -mpdclient_auth_callback(struct mpdclient *c) +void +mpdclient_error_callback(const char *message) noexcept { - return _mpdclient_auth_callback(c, 0); + screen_status_message(message); + screen_bell(); + doupdate(); } void -mpdclient_error_callback(const char *message) +mpdclient_error_callback(std::exception_ptr e) noexcept { - screen_status_message(message); + screen_status_error(std::move(e)); screen_bell(); doupdate(); }
View file
ncmpc-0.36.tar.xz/src/callbacks.hxx -> ncmpc-0.47.tar.xz/src/callbacks.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,27 +19,29 @@ #ifndef NCMPC_CALLBACKS_H #define NCMPC_CALLBACKS_H +#include <exception> + struct mpdclient; /** * A connection to MPD has been established. */ void -mpdclient_connected_callback(); +mpdclient_connected_callback() noexcept; /** * An attempt to connect to MPD has failed. * mpdclient_error_callback() has been called already. */ void -mpdclient_failed_callback(); +mpdclient_failed_callback() noexcept; /** * The connection to MPD was lost. If this was due to an error, then * mpdclient_error_callback() has already been called. */ void -mpdclient_lost_callback(); +mpdclient_lost_callback() noexcept; /** * To be implemented by the application: mpdclient.c calls this to @@ -49,12 +50,15 @@ * @param message a human-readable error message in the locale charset */ void -mpdclient_error_callback(const char *message); +mpdclient_error_callback(const char *message) noexcept; + +void +mpdclient_error_callback(std::exception_ptr e) noexcept; bool -mpdclient_auth_callback(struct mpdclient *c); +mpdclient_auth_callback(struct mpdclient *c) noexcept; void -mpdclient_idle_callback(unsigned events); +mpdclient_idle_callback(unsigned events) noexcept; #endif
View file
ncmpc-0.36.tar.xz/src/charset.cxx -> ncmpc-0.47.tar.xz/src/charset.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -117,7 +116,7 @@ return Iconv(i, dest, dest_size, src, src_length); } -gcc_pure +gnu::pure static std::string Iconv(iconv_t i, const char *src, size_t src_length) noexcept @@ -164,7 +163,7 @@ return dest; } -gcc_pure +gnu::pure static std::string Iconv(const char *tocode, const char *fromcode, const char *src, size_t src_length) noexcept @@ -178,7 +177,7 @@ return Iconv(i, src, src_length); } -gcc_pure +gnu::pure static std::string utf8_to_locale(const char *src, size_t length) noexcept { @@ -230,7 +229,7 @@ #ifdef HAVE_ICONV -gcc_pure +gnu::pure static std::string locale_to_utf8(const char *src) noexcept {
View file
ncmpc-0.36.tar.xz/src/charset.hxx -> ncmpc-0.47.tar.xz/src/charset.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -21,7 +20,6 @@ #define CHARSET_H #include "config.h" -#include "util/Compiler.h" #include <string> @@ -39,7 +37,7 @@ CopyUtf8ToLocale(char *dest, size_t dest_size, const char *src, size_t src_length) noexcept; -gcc_pure +gnu::pure const char * utf8_to_locale(const char *src, char *buffer, size_t size) noexcept;
View file
ncmpc-0.36.tar.xz/src/db_completion.cxx -> ncmpc-0.47.tar.xz/src/db_completion.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/db_completion.hxx -> ncmpc-0.47.tar.xz/src/db_completion.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/defaults.hxx -> ncmpc-0.47.tar.xz/src/defaults.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.47.tar.xz/src/event
Added
+(directory)
View file
ncmpc-0.47.tar.xz/src/event/Backend.hxx
Added
@@ -0,0 +1,42 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef EVENT_BACKEND_HXX +#define EVENT_BACKEND_HXX + +#include "event/Features.h" + +#ifdef _WIN32 + +#include "WinSelectBackend.hxx" +using EventPollBackend = WinSelectBackend; + +#elif defined(USE_EPOLL) + +#include "EpollBackend.hxx" +using EventPollBackend = EpollBackend; + +#else + +#include "PollBackend.hxx" +using EventPollBackend = PollBackend; + +#endif + +#endif
View file
ncmpc-0.47.tar.xz/src/event/BackendEvents.hxx
Added
@@ -0,0 +1,42 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef EVENT_BACKEND_EVENTS_HXX +#define EVENT_BACKEND_EVENTS_HXX + +#include "event/Features.h" + +#ifdef _WIN32 + +#include "WinSelectEvents.hxx" +using EventPollBackendEvents = WinSelectEvents; + +#elif defined(USE_EPOLL) + +#include "EpollEvents.hxx" +using EventPollBackendEvents = EpollEvents; + +#else + +#include "PollEvents.hxx" +using EventPollBackendEvents = PollEvents; + +#endif + +#endif
View file
ncmpc-0.47.tar.xz/src/event/Chrono.hxx
Added
@@ -0,0 +1,37 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_EVENT_CHRONO_HXX +#define MPD_EVENT_CHRONO_HXX + +#include <chrono> + +namespace Event { + +/** + * The clock used by classes #EventLoop, #CoarseTimerEvent and #FineTimerEvent. + */ +using Clock = std::chrono::steady_clock; + +using Duration = Clock::duration; +using TimePoint = Clock::time_point; + +} // namespace Event + +#endif /* MAIN_NOTIFY_H */
View file
ncmpc-0.47.tar.xz/src/event/CoarseTimerEvent.cxx
Added
@@ -0,0 +1,59 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "CoarseTimerEvent.hxx" +#include "Loop.hxx" + +void +CoarseTimerEvent::Schedule(Event::Duration d) noexcept +{ + Cancel(); + + due = loop.SteadyNow() + d; + loop.Insert(*this); +} + +void +CoarseTimerEvent::ScheduleEarlier(Event::Duration d) noexcept +{ + const auto new_due = loop.SteadyNow() + d; + + if (IsPending()) { + if (new_due >= due) + return; + + Cancel(); + } + + due = new_due; + loop.Insert(*this); +}
View file
ncmpc-0.47.tar.xz/src/event/CoarseTimerEvent.hxx
Added
@@ -0,0 +1,103 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "Chrono.hxx" +#include "util/BindMethod.hxx" +#include "util/IntrusiveList.hxx" + +class EventLoop; + +/** + * This class invokes a callback function after a certain amount of + * time. Use Schedule() to start the timer or Cancel() to cancel it. + * + * Unlike #FineTimerEvent, this class has a granularity of about 1 + * second, and is optimized for timeouts between 1 and 60 seconds + * which are often canceled before they expire (i.e. optimized for + * fast insertion and deletion, at the cost of granularity). + * + * This class is not thread-safe, all methods must be called from the + * thread that runs the #EventLoop, except where explicitly documented + * as thread-safe. + */ +class CoarseTimerEvent final : AutoUnlinkIntrusiveListHook +{ + friend class TimerWheel; + friend struct IntrusiveListBaseHookTraits<CoarseTimerEvent>; + + EventLoop &loop; + + using Callback = BoundMethod<void() noexcept>; + const Callback callback; + + /** + * When is this timer due? This is only valid if IsPending() + * returns true. + */ + Event::TimePoint due; + +public: + CoarseTimerEvent(EventLoop &_loop, Callback _callback) noexcept + :loop(_loop), callback(_callback) {} + + auto &GetEventLoop() const noexcept { + return loop; + } + + constexpr auto GetDue() const noexcept { + return due; + } + + bool IsPending() const noexcept { + return is_linked(); + } + + void Schedule(Event::Duration d) noexcept; + + /** + * Like Schedule(), but is a no-op if there is a due time + * earlier than the given one. + */ + void ScheduleEarlier(Event::Duration d) noexcept; + + void Cancel() noexcept { + if (IsPending()) + unlink(); + } + +private: + void Run() noexcept { + callback(); + } +};
View file
ncmpc-0.47.tar.xz/src/event/DeferEvent.cxx
Added
@@ -0,0 +1,39 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "DeferEvent.hxx" +#include "Loop.hxx" + +void +DeferEvent::Schedule() noexcept +{ + if (!IsPending()) + loop.AddDefer(*this); + + assert(IsPending()); +} + +void +DeferEvent::ScheduleIdle() noexcept +{ + if (!IsPending()) + loop.AddIdle(*this); + + assert(IsPending()); +}
View file
ncmpc-0.47.tar.xz/src/event/DeferEvent.hxx
Added
@@ -0,0 +1,80 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_DEFER_EVENT_HXX +#define MPD_DEFER_EVENT_HXX + +#include "util/BindMethod.hxx" +#include "util/IntrusiveList.hxx" + +class EventLoop; + +/** + * Defer execution until the next event loop iteration. Use this to + * move calls out of the current stack frame, to avoid surprising side + * effects for callers up in the call chain. + * + * This class is not thread-safe, all methods must be called from the + * thread that runs the #EventLoop. + */ +class DeferEvent final : AutoUnlinkIntrusiveListHook +{ + friend class EventLoop; + friend struct IntrusiveListBaseHookTraits<DeferEvent>; + + EventLoop &loop; + + using Callback = BoundMethod<void() noexcept>; + const Callback callback; + +public: + DeferEvent(EventLoop &_loop, Callback _callback) noexcept + :loop(_loop), callback(_callback) {} + + DeferEvent(const DeferEvent &) = delete; + DeferEvent &operator=(const DeferEvent &) = delete; + + auto &GetEventLoop() const noexcept { + return loop; + } + + bool IsPending() const noexcept { + return is_linked(); + } + + void Schedule() noexcept; + + /** + * Schedule this event, but only after the #EventLoop is idle, + * i.e. before going to sleep. + */ + void ScheduleIdle() noexcept; + + void Cancel() noexcept { + if (IsPending()) + unlink(); + } + +private: + void Run() noexcept { + callback(); + } +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/event/EpollBackend.hxx
Added
@@ -0,0 +1,85 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef EVENT_EPOLL_BACKEND_HXX +#define EVENT_EPOLL_BACKEND_HXX + +#include "system/EpollFD.hxx" + +#include <array> +#include <algorithm> + +class EpollBackendResult +{ + friend class EpollBackend; + + std::array<epoll_event, 16> events; + size_t n_events = 0; + +public: + size_t GetSize() const noexcept { + return n_events; + } + + unsigned GetEvents(size_t i) const noexcept { + return eventsi.events; + } + + void *GetObject(size_t i) const noexcept { + return eventsi.data.ptr; + } +}; + +class EpollBackend +{ + EpollFD epoll; + + EpollBackend(EpollBackend &) = delete; + EpollBackend &operator=(EpollBackend &) = delete; +public: + EpollBackend() = default; + + auto ReadEvents(int timeout_ms) noexcept { + EpollBackendResult result; + int ret = epoll.Wait(result.events.data(), result.events.size(), + timeout_ms); + result.n_events = std::max(0, ret); + return result; + } + + bool Add(int fd, unsigned events, void *obj) noexcept { + return epoll.Add(fd, events, obj); + } + + bool Modify(int fd, unsigned events, void *obj) noexcept { + return epoll.Modify(fd, events, obj); + } + + bool Remove(int fd) noexcept { + return epoll.Remove(fd); + } + + bool Abandon(maybe_unused int fd) noexcept { + // Nothing to do in this implementation. + // Closed descriptors are automatically unregistered. + return true; + } +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/event/EpollEvents.hxx
Added
@@ -0,0 +1,32 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef EVENT_EPOLL_EVENTS_HXX +#define EVENT_EPOLL_EVENTS_HXX + +#include <sys/epoll.h> + +struct EpollEvents { + static constexpr unsigned READ = EPOLLIN; + static constexpr unsigned WRITE = EPOLLOUT; + static constexpr unsigned ERROR = EPOLLERR; + static constexpr unsigned HANGUP = EPOLLHUP; +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/event/FarTimerEvent.hxx
Added
@@ -0,0 +1,48 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "FineTimerEvent.hxx" + +/** + * A coarse timer event which schedules far into the future. Use this + * when you need a coarse resolution, but the supported time span of + * #CoarseTimerEvent is not enough. For example, a good use case is + * timers which fire only every few minutes and do periodic cleanup. + * + * Right now, this is just an alias for #FineTimerEvent. This class + * supports arbitrary time spans, but uses a high-resolution timer. + * Eventually, we may turn this into a timer wheel with minute + * resolution. + */ +using FarTimerEvent = FineTimerEvent;
View file
ncmpc-0.47.tar.xz/src/event/FineTimerEvent.cxx
Added
@@ -0,0 +1,59 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "FineTimerEvent.hxx" +#include "Loop.hxx" + +void +FineTimerEvent::Schedule(Event::Duration d) noexcept +{ + Cancel(); + + due = loop.SteadyNow() + d; + loop.Insert(*this); +} + +void +FineTimerEvent::ScheduleEarlier(Event::Duration d) noexcept +{ + const auto new_due = loop.SteadyNow() + d; + + if (IsPending()) { + if (new_due >= due) + return; + + Cancel(); + } + + due = new_due; + loop.Insert(*this); +}
View file
ncmpc-0.47.tar.xz/src/event/FineTimerEvent.hxx
Added
@@ -0,0 +1,116 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "Chrono.hxx" +#include "event/Features.h" +#include "util/BindMethod.hxx" + +#ifdef NO_BOOST +#include "util/IntrusiveList.hxx" +#else +#include <boost/intrusive/set_hook.hpp> +#endif + +class EventLoop; + +/** + * This class invokes a callback function after a certain amount of + * time. Use Schedule() to start the timer or Cancel() to cancel it. + * + * Unlike #CoarseTimerEvent, this class uses a high-resolution timer, + * but at the cost of more expensive insertion and deletion. + * + * This class is not thread-safe, all methods must be called from the + * thread that runs the #EventLoop, except where explicitly documented + * as thread-safe. + */ +class FineTimerEvent final : +#ifdef NO_BOOST + AutoUnlinkIntrusiveListHook +#else + public boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>> +#endif +{ + friend class TimerList; +#ifdef NO_BOOST + friend struct IntrusiveListBaseHookTraits<FineTimerEvent>; +#endif + + EventLoop &loop; + + using Callback = BoundMethod<void() noexcept>; + const Callback callback; + + /** + * When is this timer due? This is only valid if IsPending() + * returns true. + */ + Event::TimePoint due; + +public: + FineTimerEvent(EventLoop &_loop, Callback _callback) noexcept + :loop(_loop), callback(_callback) {} + + auto &GetEventLoop() const noexcept { + return loop; + } + + constexpr auto GetDue() const noexcept { + return due; + } + + bool IsPending() const noexcept { + return is_linked(); + } + + void Schedule(Event::Duration d) noexcept; + + /** + * Like Schedule(), but is a no-op if there is a due time + * earlier than the given one. + */ + void ScheduleEarlier(Event::Duration d) noexcept; + + void Cancel() noexcept { +#ifdef NO_BOOST + if (IsPending()) +#endif + unlink(); + } + +private: + void Run() noexcept { + callback(); + } +};
View file
ncmpc-0.47.tar.xz/src/event/IdleEvent.cxx
Added
@@ -0,0 +1,20 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "IdleEvent.hxx"
View file
ncmpc-0.47.tar.xz/src/event/IdleEvent.hxx
Added
@@ -0,0 +1,61 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_SOCKET_IDLE_EVENT_HXX +#define MPD_SOCKET_IDLE_EVENT_HXX + +#include "DeferEvent.hxx" + +class EventLoop; + +/** + * An event that runs when the EventLoop has become idle, before + * waiting for more events. + * + * This class is not thread-safe, all methods must be called from the + * thread that runs the #EventLoop, except where explicitly documented + * as thread-safe. + */ +class IdleEvent final { + DeferEvent event; + + using Callback = BoundMethod<void() noexcept>; + +public: + IdleEvent(EventLoop &_loop, Callback _callback) noexcept + :event(_loop, _callback) {} + + auto &GetEventLoop() const noexcept { + return event.GetEventLoop(); + } + + bool IsPending() const noexcept { + return event.IsPending(); + } + + void Schedule() noexcept { + event.ScheduleIdle(); + } + + void Cancel() noexcept { + event.Cancel(); + } +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/event/Loop.cxx
Added
@@ -0,0 +1,431 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "Loop.hxx" +#include "DeferEvent.hxx" +#include "SocketEvent.hxx" +#include "IdleEvent.hxx" +#include "util/ScopeExit.hxx" + +#ifdef HAVE_THREADED_EVENT_LOOP +#include "InjectEvent.hxx" +#endif + +#ifdef HAVE_URING +#include "UringManager.hxx" +#include "util/PrintException.hxx" +#include <stdio.h> +#endif + +EventLoop::EventLoop( +#ifdef HAVE_THREADED_EVENT_LOOP + ThreadId _thread +#endif + ) +#ifdef HAVE_THREADED_EVENT_LOOP + :thread(_thread), + /* if this instance is hosted by an EventThread (no ThreadId + known yet) then we're not yet alive until the thread is + started; for the main EventLoop instance, we assume it's + already alive, because nobody but EventThread will call + SetAlive() */ + alive(!_thread.IsNull()) +#endif +{ +} + +EventLoop::~EventLoop() noexcept +{ +#if defined(HAVE_URING) && !defined(NDEBUG) + /* if Run() was never called (maybe because startup failed and + an exception is pending), we need to destruct the + Uring::Manager here or else the assertions below fail */ + uring.reset(); +#endif + + assert(defer.empty()); + assert(idle.empty()); +#ifdef HAVE_THREADED_EVENT_LOOP + assert(inject.empty()); +#endif + assert(sockets.empty()); + assert(ready_sockets.empty()); +} + +#ifdef HAVE_URING + +Uring::Queue * +EventLoop::GetUring() noexcept +{ + if (!uring_initialized) { + uring_initialized = true; + try { + uring = std::make_unique<Uring::Manager>(*this); + } catch (...) { + fprintf(stderr, "Failed to initialize io_uring: "); + PrintException(std::current_exception()); + } + } + + return uring.get(); +} + +#endif + +void +EventLoop::Break() noexcept +{ + if (quit.exchange(true)) + return; + +#ifdef HAVE_THREADED_EVENT_LOOP + wake_fd.Write(); +#endif +} + +bool +EventLoop::AddFD(int fd, unsigned events, SocketEvent &event) noexcept +{ +#ifdef HAVE_THREADED_EVENT_LOOP + assert(!IsAlive() || IsInside()); +#endif + assert(events != 0); + + if (!poll_backend.Add(fd, events, &event)) + return false; + + sockets.push_back(event); + return true; +} + +bool +EventLoop::ModifyFD(int fd, unsigned events, SocketEvent &event) noexcept +{ +#ifdef HAVE_THREADED_EVENT_LOOP + assert(!IsAlive() || IsInside()); +#endif + assert(events != 0); + + return poll_backend.Modify(fd, events, &event); +} + +bool +EventLoop::RemoveFD(int fd, SocketEvent &event) noexcept +{ +#ifdef HAVE_THREADED_EVENT_LOOP + assert(!IsAlive() || IsInside()); +#endif + + event.unlink(); + return poll_backend.Remove(fd); +} + +bool +EventLoop::AbandonFD(SocketEvent &event) noexcept +{ +#ifdef HAVE_THREADED_EVENT_LOOP + assert(!IsAlive() || IsInside()); +#endif + assert(event.IsDefined()); + + event.unlink(); + + return poll_backend.Abandon(event.GetSocket().Get()); +} + +void +EventLoop::Insert(CoarseTimerEvent &t) noexcept +{ + coarse_timers.Insert(t, SteadyNow()); + again = true; +} + +void +EventLoop::Insert(FineTimerEvent &t) noexcept +{ + assert(IsInside()); + + timers.Insert(t); + again = true; +} + +inline Event::Duration +EventLoop::HandleTimers() noexcept +{ + const auto now = SteadyNow(); + + auto fine_timeout = timers.Run(now); + auto coarse_timeout = coarse_timers.Run(now); + + return fine_timeout.count() < 0 || + (coarse_timeout.count() >= 0 && coarse_timeout < fine_timeout) + ? coarse_timeout + : fine_timeout; +} + +void +EventLoop::AddDefer(DeferEvent &d) noexcept +{ +#ifdef HAVE_THREADED_EVENT_LOOP + assert(!IsAlive() || IsInside()); +#endif + + defer.push_back(d); + again = true; +} + +void +EventLoop::AddIdle(DeferEvent &e) noexcept +{ + idle.push_front(e); + again = true; +} + +void +EventLoop::RunDeferred() noexcept +{ + while (!defer.empty() && !quit) { + defer.pop_front_and_dispose((DeferEvent *e){ + e->Run(); + }); + } +} + +bool +EventLoop::RunOneIdle() noexcept +{ + if (idle.empty()) + return false; + + idle.pop_front_and_dispose((DeferEvent *e){ + e->Run(); + }); + + return true; +} + +template<class ToDuration, class Rep, class Period> +static constexpr ToDuration +duration_cast_round_up(std::chrono::duration<Rep, Period> d) noexcept +{ + using FromDuration = decltype(d); + constexpr auto one = std::chrono::duration_cast<FromDuration>(ToDuration(1)); + constexpr auto round_add = one > one.zero() + ? one - FromDuration(1) + : one.zero(); + return std::chrono::duration_cast<ToDuration>(d + round_add); +} + +/** + * Convert the given timeout specification to a milliseconds integer, + * to be used by functions like poll() and epoll_wait(). Any negative + * value (= never times out) is translated to the magic value -1. + */ +static constexpr int +ExportTimeoutMS(Event::Duration timeout) noexcept +{ + return timeout >= timeout.zero() + ? int(duration_cast_round_up<std::chrono::milliseconds>(timeout).count()) + : -1; +} + +inline bool +EventLoop::Wait(Event::Duration timeout) noexcept +{ + const auto poll_result = + poll_backend.ReadEvents(ExportTimeoutMS(timeout)); + + for (size_t i = 0; i < poll_result.GetSize(); ++i) { + auto &socket_event = *(SocketEvent *)poll_result.GetObject(i); + socket_event.SetReadyFlags(poll_result.GetEvents(i)); + + /* move from "sockets" to "ready_sockets" */ + socket_event.unlink(); + ready_sockets.push_back(socket_event); + } + + return poll_result.GetSize() > 0; +} + +void +EventLoop::Run() noexcept +{ +#ifdef HAVE_THREADED_EVENT_LOOP + if (thread.IsNull()) + thread = ThreadId::GetCurrent(); +#endif + + assert(IsInside()); + assert(!quit); +#ifdef HAVE_THREADED_EVENT_LOOP + assert(alive); + assert(busy); + + wake_event.Schedule(SocketEvent::READ); +#endif + +#ifdef HAVE_URING + AtScopeExit(this) { + /* make sure that the Uring::Manager gets destructed + from within the EventThread, or else its + destruction in another thread will cause assertion + failures */ + uring.reset(); + uring_initialized = false; + }; +#endif + +#ifdef HAVE_THREADED_EVENT_LOOP + AtScopeExit(this) { + wake_event.Cancel(); + }; +#endif + + steady_clock_cache.flush(); + + do { + again = false; + + /* invoke timers */ + + const auto timeout = HandleTimers(); + if (quit) + break; + + RunDeferred(); + if (quit) + break; + + if (RunOneIdle()) + /* check for other new events after each + "idle" invocation to ensure that the other + "idle" events are really invoked at the + very end */ + continue; + +#ifdef HAVE_THREADED_EVENT_LOOP + /* try to handle DeferEvents without WakeFD + overhead */ + { + const std::scoped_lock<Mutex> lock(mutex); + HandleInject(); +#endif + + if (again) + /* re-evaluate timers because one of + the DeferEvents may have added a + new timeout */ + continue; + +#ifdef HAVE_THREADED_EVENT_LOOP + busy = false; + } +#endif + + /* wait for new event */ + + Wait(timeout); + + steady_clock_cache.flush(); + +#ifdef HAVE_THREADED_EVENT_LOOP + { + const std::scoped_lock<Mutex> lock(mutex); + busy = true; + } +#endif + + /* invoke sockets */ + while (!ready_sockets.empty() && !quit) { + auto &socket_event = ready_sockets.front(); + + /* move from "ready_sockets" back to "sockets" */ + socket_event.unlink(); + sockets.push_back(socket_event); + + socket_event.Dispatch(); + } + } while (!quit); + +#ifdef HAVE_THREADED_EVENT_LOOP +#ifndef NDEBUG + assert(thread.IsInside()); +#endif +#endif +} + +#ifdef HAVE_THREADED_EVENT_LOOP + +void +EventLoop::AddInject(InjectEvent &d) noexcept +{ + bool must_wake; + + { + const std::scoped_lock<Mutex> lock(mutex); + if (d.IsPending()) + return; + + /* we don't need to wake up the EventLoop if another + InjectEvent has already done it */ + must_wake = !busy && inject.empty(); + + inject.push_back(d); + again = true; + } + + if (must_wake) + wake_fd.Write(); +} + +void +EventLoop::RemoveInject(InjectEvent &d) noexcept +{ + const std::scoped_lock<Mutex> protect(mutex); + + if (d.IsPending()) + inject.erase(inject.iterator_to(d)); +} + +void +EventLoop::HandleInject() noexcept +{ + while (!inject.empty() && !quit) { + auto &m = inject.front(); + assert(m.IsPending()); + + inject.pop_front(); + + const ScopeUnlock unlock(mutex); + m.Run(); + } +} + +void +EventLoop::OnSocketReady(maybe_unused unsigned flags) noexcept +{ + assert(IsInside()); + + wake_fd.Read(); + + const std::scoped_lock<Mutex> lock(mutex); + HandleInject(); +} + +#endif
View file
ncmpc-0.47.tar.xz/src/event/Loop.hxx
Added
@@ -0,0 +1,302 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef EVENT_LOOP_HXX +#define EVENT_LOOP_HXX + +#include "Chrono.hxx" +#include "TimerWheel.hxx" +#include "TimerList.hxx" +#include "Backend.hxx" +#include "SocketEvent.hxx" +#include "event/Features.h" +#include "time/ClockCache.hxx" +#include "util/IntrusiveList.hxx" + +#ifdef HAVE_THREADED_EVENT_LOOP +#include "WakeFD.hxx" +#include "thread/Id.hxx" +#include "thread/Mutex.hxx" + +#include <boost/intrusive/list.hpp> +#endif + +#include <atomic> +#include <cassert> + +#include "io/uring/Features.h" +#ifdef HAVE_URING +#include <memory> +namespace Uring { class Queue; class Manager; } +#endif + +class DeferEvent; +class InjectEvent; + +/** + * An event loop that polls for events on file/socket descriptors. + * + * This class is not thread-safe, all methods must be called from the + * thread that runs it, except where explicitly documented as + * thread-safe. + * + * @see SocketEvent, MultiSocketMonitor, TimerEvent, DeferEvent, InjectEvent + */ +class EventLoop final +{ +#ifdef HAVE_THREADED_EVENT_LOOP + WakeFD wake_fd; + SocketEvent wake_event{*this, BIND_THIS_METHOD(OnSocketReady), wake_fd.GetSocket()}; +#endif + + TimerWheel coarse_timers; + TimerList timers; + + using DeferList = IntrusiveList<DeferEvent>; + + DeferList defer; + + /** + * This is like #defer, but gets invoked when the loop is idle. + */ + DeferList idle; + +#ifdef HAVE_THREADED_EVENT_LOOP + Mutex mutex; + + using InjectList = + boost::intrusive::list<InjectEvent, + boost::intrusive::base_hook<boost::intrusive::list_base_hook<>>, + boost::intrusive::constant_time_size<false>>; + InjectList inject; +#endif + + using SocketList = IntrusiveList<SocketEvent>; + + /** + * A list of scheduled #SocketEvent instances, without those + * which are ready (these are in #ready_sockets). + */ + SocketList sockets; + + /** + * A linked list of #SocketEvent instances which have a + * non-zero "ready_flags" field, and need to be dispatched. + */ + SocketList ready_sockets; + +#ifdef HAVE_URING + std::unique_ptr<Uring::Manager> uring; +#endif + +#ifdef HAVE_THREADED_EVENT_LOOP + /** + * A reference to the thread that is currently inside Run(). + */ + ThreadId thread = ThreadId::Null(); + + /** + * Is this #EventLoop alive, i.e. can events be scheduled? + * This is used by BlockingCall() to determine whether + * schedule in the #EventThread or to call directly (if + * there's no #EventThread yet/anymore). + */ + bool alive; +#endif + + std::atomic_bool quit{false}; + + /** + * True when the object has been modified and another check is + * necessary before going to sleep via EventPollBackend::ReadEvents(). + */ + bool again; + +#ifdef HAVE_THREADED_EVENT_LOOP + /** + * True when handling callbacks, false when waiting for I/O or + * timeout. + * + * Protected with #mutex. + */ + bool busy = true; +#endif + +#ifdef HAVE_URING + bool uring_initialized = false; +#endif + + EventPollBackend poll_backend; + + ClockCache<std::chrono::steady_clock> steady_clock_cache; + +public: + /** + * Throws on error. + */ +#ifdef HAVE_THREADED_EVENT_LOOP + explicit EventLoop(ThreadId _thread); + + EventLoop():EventLoop(ThreadId::GetCurrent()) {} +#else + EventLoop(); +#endif + + ~EventLoop() noexcept; + + EventLoop(const EventLoop &other) = delete; + EventLoop &operator=(const EventLoop &other) = delete; + + const auto &GetSteadyClockCache() const noexcept { + return steady_clock_cache; + } + + /** + * Caching wrapper for std::chrono::steady_clock::now(). The + * real clock is queried at most once per event loop + * iteration, because it is assumed that the event loop runs + * for a negligible duration. + */ + gnu::pure + const auto &SteadyNow() const noexcept { +#ifdef HAVE_THREADED_EVENT_LOOP + assert(IsInside()); +#endif + + return steady_clock_cache.now(); + } + +#ifdef HAVE_URING + gnu::pure + Uring::Queue *GetUring() noexcept; +#endif + + /** + * Stop execution of this #EventLoop at the next chance. This + * method is thread-safe and non-blocking: after returning, it + * is not guaranteed that the EventLoop has really stopped. + */ + void Break() noexcept; + + bool AddFD(int fd, unsigned events, SocketEvent &event) noexcept; + bool ModifyFD(int fd, unsigned events, SocketEvent &event) noexcept; + bool RemoveFD(int fd, SocketEvent &event) noexcept; + + /** + * Remove the given #SocketEvent after the file descriptor + * has been closed. This is like RemoveFD(), but does not + * attempt to use #EPOLL_CTL_DEL. + */ + bool AbandonFD(SocketEvent &event) noexcept; + + void Insert(CoarseTimerEvent &t) noexcept; + void Insert(FineTimerEvent &t) noexcept; + + /** + * Schedule a call to DeferEvent::RunDeferred(). + */ + void AddDefer(DeferEvent &d) noexcept; + void AddIdle(DeferEvent &e) noexcept; + +#ifdef HAVE_THREADED_EVENT_LOOP + /** + * Schedule a call to the InjectEvent. + * + * This method is thread-safe. + */ + void AddInject(InjectEvent &d) noexcept; + + /** + * Cancel a pending call to the InjectEvent. + * However after returning, the call may still be running. + * + * This method is thread-safe. + */ + void RemoveInject(InjectEvent &d) noexcept; +#endif + + /** + * The main function of this class. It will loop until + * Break() gets called. Can be called only once. + */ + void Run() noexcept; + +private: + void RunDeferred() noexcept; + + /** + * Invoke one "idle" #DeferEvent. + * + * @return false if there was no such event + */ + bool RunOneIdle() noexcept; + +#ifdef HAVE_THREADED_EVENT_LOOP + /** + * Invoke all pending InjectEvents. + * + * Caller must lock the mutex. + */ + void HandleInject() noexcept; +#endif + + /** + * Invoke all expired #TimerEvent instances and return the + * duration until the next timer expires. Returns a negative + * duration if there is no timeout. + */ + Event::Duration HandleTimers() noexcept; + + /** + * Call epoll_wait() and pass all returned events to + * SocketEvent::SetReadyFlags(). + * + * @return true if one or more sockets have become ready + */ + bool Wait(Event::Duration timeout) noexcept; + +#ifdef HAVE_THREADED_EVENT_LOOP + void OnSocketReady(unsigned flags) noexcept; +#endif + +public: +#ifdef HAVE_THREADED_EVENT_LOOP + void SetAlive(bool _alive) noexcept { + alive = _alive; + } + + bool IsAlive() const noexcept { + return alive; + } +#endif + + /** + * Are we currently running inside this EventLoop's thread? + */ + gnu::pure + bool IsInside() const noexcept { +#ifdef HAVE_THREADED_EVENT_LOOP + return thread.IsInside(); +#else + return true; +#endif + } +}; + +#endif /* MAIN_NOTIFY_H */
View file
ncmpc-0.47.tar.xz/src/event/PipeEvent.hxx
Added
@@ -0,0 +1,103 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "SocketEvent.hxx" +#include "io/FileDescriptor.hxx" + +/** + * A variant of #SocketEvent for pipes (and other kinds of + * #FileDescriptor which can be used with epoll). + */ +class PipeEvent final { + SocketEvent event; + +public: + template<typename C> + PipeEvent(EventLoop &event_loop, C callback, + FileDescriptor fd=FileDescriptor::Undefined()) noexcept + :event(event_loop, callback, + SocketDescriptor::FromFileDescriptor(fd)) {} + + EventLoop &GetEventLoop() const noexcept { + return event.GetEventLoop(); + } + + bool IsDefined() const noexcept { + return event.IsDefined(); + } + + FileDescriptor GetFileDescriptor() const noexcept { + return event.GetSocket().ToFileDescriptor(); + } + + FileDescriptor ReleaseFileDescriptor() noexcept { + return event.ReleaseSocket().ToFileDescriptor(); + } + + void Open(FileDescriptor fd) noexcept { + event.Open(SocketDescriptor::FromFileDescriptor(fd)); + } + + void Close() noexcept { + event.Close(); + } + + bool Schedule(unsigned flags) noexcept { + return event.Schedule(flags); + } + + void Cancel() noexcept { + event.Cancel(); + } + + bool ScheduleRead() noexcept { + return event.ScheduleRead(); + } + + bool ScheduleWrite() noexcept { + return event.ScheduleWrite(); + } + + void CancelRead() noexcept { + event.CancelRead(); + } + + void CancelWrite() noexcept { + event.CancelWrite(); + } + + void ScheduleImplicit() noexcept { + event.ScheduleImplicit(); + } +};
View file
ncmpc-0.47.tar.xz/src/event/PollBackend.cxx
Added
@@ -0,0 +1,100 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "PollBackend.hxx" + +#include <cassert> + +PollBackend::PollBackend() noexcept = default; +PollBackend::~PollBackend() noexcept = default; + +static constexpr auto +MakePollfd(int fd, short events) noexcept +{ + struct pollfd pfd{}; + pfd.fd = fd; + pfd.events = events; + return pfd; +} + +bool +PollBackend::Add(int fd, unsigned events, void *obj) noexcept +{ + assert(items.find(fd) == items.end()); + + const std::size_t index = poll_events.size(); + poll_events.push_back(MakePollfd(fd, events)); + + items.emplace(std::piecewise_construct, + std::forward_as_tuple(fd), + std::forward_as_tuple(index, obj)); + return true; +} + +bool +PollBackend::Modify(int fd, unsigned events, void *obj) noexcept +{ + auto item_iter = items.find(fd); + assert(item_iter != items.end()); + auto &item = item_iter->second; + item.obj = obj; + auto &e = poll_eventsitem.index; + e.events = events; + e.revents &= events; + return true; +} + +bool +PollBackend::Remove(int fd) noexcept +{ + auto item_iter = items.find(fd); + assert(item_iter != items.end()); + const auto &item = item_iter->second; + std::size_t index = item.index; + std::size_t last_index = poll_events.size() - 1; + if (index != last_index) { + std::swap(poll_eventsindex, poll_eventslast_index); + items.find(poll_eventsindex.fd)->second.index = index; + } + poll_events.pop_back(); + items.erase(item_iter); + return true; +} + +PollResultGeneric +PollBackend::ReadEvents(int timeout_ms) noexcept +{ + int n = poll(poll_events.empty() ? nullptr : &poll_events0, + poll_events.size(), timeout_ms); + + PollResultGeneric result; + for (std::size_t i = 0; n > 0 && i < poll_events.size(); ++i) { + const auto &e = poll_eventsi; + if (e.revents != 0) { + auto it = items.find(e.fd); + assert(it != items.end()); + assert(it->second.index == i); + + result.Add(e.revents, it->second.obj); + --n; + } + } + + return result; +}
View file
ncmpc-0.47.tar.xz/src/event/PollBackend.hxx
Added
@@ -0,0 +1,63 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef EVENT_POLL_BACKEND_HXX +#define EVENT_POLL_BACKEND_HXX + +#include "PollResultGeneric.hxx" + +#include <cstddef> +#include <vector> +#include <unordered_map> + +#include <sys/poll.h> + +class PollBackend +{ + struct Item + { + std::size_t index; + void *obj; + + constexpr Item(std::size_t _index, void *_obj) noexcept + :index(_index), obj(_obj) {} + + Item(const Item &) = delete; + Item &operator=(const Item &) = delete; + }; + + std::vector<pollfd> poll_events; + std::unordered_map<int, Item> items; + + PollBackend(PollBackend &) = delete; + PollBackend &operator=(PollBackend &) = delete; +public: + PollBackend() noexcept; + ~PollBackend() noexcept; + + PollResultGeneric ReadEvents(int timeout_ms) noexcept; + bool Add(int fd, unsigned events, void *obj) noexcept; + bool Modify(int fd, unsigned events, void *obj) noexcept; + bool Remove(int fd) noexcept; + bool Abandon(int fd) noexcept { + return Remove(fd); + } +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/event/PollEvents.hxx
Added
@@ -0,0 +1,32 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef EVENT_POLL_EVENTS_HXX +#define EVENT_POLL_EVENTS_HXX + +#include <sys/poll.h> + +struct PollEvents { + static constexpr unsigned READ = POLLIN; + static constexpr unsigned WRITE = POLLOUT; + static constexpr unsigned ERROR = POLLERR; + static constexpr unsigned HANGUP = POLLHUP; +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/event/PollResultGeneric.hxx
Added
@@ -0,0 +1,65 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_EVENT_POLLRESULT_GENERIC_HXX +#define MPD_EVENT_POLLRESULT_GENERIC_HXX + +#include <cstddef> +#include <vector> + +#ifdef _WIN32 +#include <windows.h> +/* damn you, windows.h! */ +#ifdef GetObject +#undef GetObject +#endif +#endif + +class PollResultGeneric +{ + struct Item + { + unsigned events; + void *obj; + + Item() = default; + constexpr Item(unsigned _events, void *_obj) noexcept + : events(_events), obj(_obj) { } + }; + + std::vector<Item> items; +public: + size_t GetSize() const noexcept { + return items.size(); + } + + unsigned GetEvents(size_t i) const noexcept { + return itemsi.events; + } + + void *GetObject(size_t i) const noexcept { + return itemsi.obj; + } + + void Add(unsigned events, void *obj) noexcept { + items.emplace_back(events, obj); + } +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/event/SignalMonitor.cxx
Added
@@ -0,0 +1,223 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "SignalMonitor.hxx" +#include "event/Features.h" + +#ifndef _WIN32 + +#include "SocketEvent.hxx" +#include "util/Manual.hxx" +#include "system/Error.hxx" + +#ifdef USE_SIGNALFD +#include "system/SignalFD.hxx" +#else +#include "WakeFD.hxx" +#endif + +#ifndef USE_SIGNALFD +#include <atomic> +#endif + +#include <algorithm> +#include <array> +#include <cassert> +#include <csignal> + +#ifdef USE_SIGNALFD +#include <pthread.h> +#endif + +class SignalMonitor final { +#ifdef USE_SIGNALFD + SignalFD fd; +#else + WakeFD fd; +#endif + + SocketEvent event; + +public: + explicit SignalMonitor(EventLoop &_loop) + :event(_loop, BIND_THIS_METHOD(OnSocketReady)) { +#ifndef USE_SIGNALFD + event.Open(fd.GetSocket()); + event.ScheduleRead(); +#endif + } + + nodiscard auto &GetEventLoop() const noexcept { + return event.GetEventLoop(); + } + +#ifdef USE_SIGNALFD + void Update(sigset_t &mask) noexcept { + const bool was_open = event.IsDefined(); + + fd.Create(mask); + + if (!was_open) { + event.Open(SocketDescriptor(fd.Get())); + event.ScheduleRead(); + } + } +#else + void WakeUp() noexcept { + fd.Write(); + } +#endif + +private: + void OnSocketReady(unsigned flags) noexcept; +}; + +/* this should be enough - is it? */ +static constexpr unsigned MAX_SIGNAL = 64; + +static std::array<SignalHandler, MAX_SIGNAL> signal_handlers; + +#ifdef USE_SIGNALFD +static sigset_t signal_mask; +#else +static std::array<std::atomic_bool, MAX_SIGNAL> signal_pending; +#endif + +static Manual<SignalMonitor> monitor; + +#ifdef USE_SIGNALFD + +/** + * This is a pthread_atfork() callback that unblocks the signals that + * were blocked for our signalfd(). Without this, our child processes + * would inherit the blocked signals. + */ +static void +at_fork_child() noexcept +{ + sigprocmask(SIG_UNBLOCK, &signal_mask, nullptr); +} + +#else + +static void +SignalCallback(int signo) noexcept +{ + assert(signal_handlerssigno); + + if (!signal_pendingsigno.exchange(true)) + monitor->WakeUp(); +} + +#endif + +void +SignalMonitorInit(EventLoop &loop) +{ +#ifdef USE_SIGNALFD + sigemptyset(&signal_mask); + + pthread_atfork(nullptr, nullptr, at_fork_child); +#endif + + monitor.Construct(loop); +} + +#ifndef USE_SIGNALFD + +static void +x_sigaction(int signum, const struct sigaction &act) +{ + if (sigaction(signum, &act, nullptr) < 0) + throw MakeErrno("sigaction() failed"); +} + +#endif + +void +SignalMonitorFinish() noexcept +{ +#ifdef USE_SIGNALFD + signal_handlers = {}; +#else + struct sigaction sa; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_DFL; + + for (unsigned i = 0; i < MAX_SIGNAL; ++i) { + if (signal_handlersi) { + sigaction(i, &sa, nullptr); + signal_handlersi = nullptr; + } + } + + std::fill(signal_pending.begin(), signal_pending.end(), false); +#endif + + monitor.Destruct(); +} + +void +SignalMonitorRegister(int signo, SignalHandler handler) +{ + assert(!signal_handlerssigno); +#ifndef USE_SIGNALFD + assert(!signal_pendingsigno); +#endif + + signal_handlerssigno = handler; + +#ifdef USE_SIGNALFD + sigaddset(&signal_mask, signo); + + if (sigprocmask(SIG_BLOCK, &signal_mask, nullptr) < 0) + throw MakeErrno("sigprocmask() failed"); + + monitor->Update(signal_mask); +#else + struct sigaction sa; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sa.sa_handler = SignalCallback; + x_sigaction(signo, sa); +#endif +} + +void +SignalMonitor::OnSocketReady(unsigned) noexcept +{ +#ifdef USE_SIGNALFD + int signo; + while ((signo = fd.Read()) >= 0) { + assert(unsigned(signo) < MAX_SIGNAL); + assert(signal_handlerssigno); + + signal_handlerssigno(); + } +#else + fd.Read(); + + for (unsigned i = 0; i < MAX_SIGNAL; ++i) + if (signal_pendingi.exchange(false)) + signal_handlersi(); +#endif +} + +#endif
View file
ncmpc-0.47.tar.xz/src/event/SignalMonitor.hxx
Added
@@ -0,0 +1,66 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_SOCKET_SIGNAL_MONITOR_HXX +#define MPD_SOCKET_SIGNAL_MONITOR_HXX + +class EventLoop; + +#ifndef _WIN32 + +#include "util/BindMethod.hxx" + +using SignalHandler = BoundMethod<void() noexcept>; + +/** + * Initialise the signal monitor subsystem. + * + * Throws on error. + */ +void +SignalMonitorInit(EventLoop &loop); + +/** + * Deinitialise the signal monitor subsystem. + */ +void +SignalMonitorFinish() noexcept; + +/** + * Register a handler for the specified signal. The handler will be + * invoked in a safe context. + */ +void +SignalMonitorRegister(int signo, SignalHandler handler); + +#else + +static inline void +SignalMonitorInit(EventLoop &) +{ +} + +static inline void +SignalMonitorFinish() noexcept +{ +} + +#endif + +#endif /* MAIN_NOTIFY_H */
View file
ncmpc-0.47.tar.xz/src/event/SocketEvent.cxx
Added
@@ -0,0 +1,122 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "SocketEvent.hxx" +#include "Loop.hxx" +#include "event/Features.h" + +#include <cassert> +#include <utility> + +#ifdef USE_EPOLL +#include <cerrno> +#endif + +void +SocketEvent::Open(SocketDescriptor _fd) noexcept +{ + assert(_fd.IsDefined()); + assert(!fd.IsDefined()); + assert(GetScheduledFlags() == 0); + + fd = _fd; +} + +void +SocketEvent::Close() noexcept +{ + if (!fd.IsDefined()) + return; + + /* closing the socket automatically unregisters it from epoll, + so we can omit the epoll_ctl(EPOLL_CTL_DEL) call and save + one system call */ + if (std::exchange(scheduled_flags, 0) != 0) { +#ifdef HAVE_THREADED_EVENT_LOOP + /* can't use this optimization in multi-threaded + programs, because all file descriptors get + duplicated in forked processes, leaving them + registered in epoll, which could cause the parent + to crash */ + loop.RemoveFD(fd.Get(), *this); +#else + loop.AbandonFD(*this); +#endif + } + fd.Close(); +} + +void +SocketEvent::Abandon() noexcept +{ + if (std::exchange(scheduled_flags, 0) != 0) + loop.AbandonFD(*this); + + fd = SocketDescriptor::Undefined(); +} + +bool +SocketEvent::Schedule(unsigned flags) noexcept +{ + if (flags != 0) + flags |= IMPLICIT_FLAGS; + + if (flags == GetScheduledFlags()) + return true; + + assert(IsDefined()); + + bool success; + if (scheduled_flags == 0) + success = loop.AddFD(fd.Get(), flags, *this); + else if (flags == 0) + success = loop.RemoveFD(fd.Get(), *this); + else + success = loop.ModifyFD(fd.Get(), flags, *this); + + if (success) + scheduled_flags = flags; +#ifdef USE_EPOLL + else if (errno == EBADF || errno == ENOENT) + /* the socket was probably closed by somebody else + (EBADF) or a new file descriptor with the same + number was created but not registered already + (ENOENT) - we can assume that there are no + scheduled events */ + /* note that when this happens, we're actually lucky + that it has failed - imagine another thread may + meanwhile have created something on the same file + descriptor number, and has registered it; the + epoll_ctl() call above would then have succeeded, + but broke the other thread's epoll registration */ + scheduled_flags = 0; +#endif + + return success; +} + +void +SocketEvent::Dispatch() noexcept +{ + const unsigned flags = std::exchange(ready_flags, 0) & + GetScheduledFlags(); + + if (flags != 0) + callback(flags); +}
View file
ncmpc-0.47.tar.xz/src/event/SocketEvent.hxx
Added
@@ -0,0 +1,185 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_SOCKET_EVENT_HXX +#define MPD_SOCKET_EVENT_HXX + +#include "BackendEvents.hxx" +#include "net/SocketDescriptor.hxx" +#include "util/BindMethod.hxx" +#include "util/IntrusiveList.hxx" + +#include <cstddef> +#include <type_traits> + +class EventLoop; + +/** + * Monitor events on a socket. Call Schedule() to announce events + * you're interested in, or Cancel() to cancel your subscription. The + * #EventLoop will invoke the callback as soon as any of the + * subscribed events are ready. + * + * This class does not feel responsible for closing the socket. Call + * Close() to do it manually. + * + * This class is not thread-safe, all methods must be called from the + * thread that runs the #EventLoop, except where explicitly documented + * as thread-safe. + */ +class SocketEvent final : IntrusiveListHook, public EventPollBackendEvents +{ + friend class EventLoop; + friend struct IntrusiveListBaseHookTraits<SocketEvent>; + + EventLoop &loop; + + using Callback = BoundMethod<void(unsigned events) noexcept>; + const Callback callback; + + SocketDescriptor fd; + + /** + * A bit mask of events that are currently registered in the + * #EventLoop. + */ + unsigned scheduled_flags = 0; + + /** + * A bit mask of events which have been reported as "ready" by + * epoll_wait(). If non-zero, then the #EventLoop will call + * Dispatch() soon. + */ + unsigned ready_flags = 0; + +public: + /** + * These flags are always reported by epoll_wait() and don't + * need to be registered with epoll_ctl(). + */ + static constexpr unsigned IMPLICIT_FLAGS = ERROR|HANGUP; + + using ssize_t = std::make_signed<size_t>::type; + + SocketEvent(EventLoop &_loop, Callback _callback, + SocketDescriptor _fd=SocketDescriptor::Undefined()) noexcept + :loop(_loop), + callback(_callback), + fd(_fd) {} + + ~SocketEvent() noexcept { + Cancel(); + } + + SocketEvent(const SocketEvent &) = delete; + SocketEvent &operator=(const SocketEvent &) = delete; + + auto &GetEventLoop() const noexcept { + return loop; + } + + bool IsDefined() const noexcept { + return fd.IsDefined(); + } + + SocketDescriptor GetSocket() const noexcept { + return fd; + } + + SocketDescriptor ReleaseSocket() noexcept { + Cancel(); + return std::exchange(fd, SocketDescriptor::Undefined()); + } + + void Open(SocketDescriptor fd) noexcept; + + /** + * Close the socket (and cancel all scheduled events). + */ + void Close() noexcept; + + /** + * Call this instead of Cancel() to unregister this object + * after the underlying socket has already been closed. This + * skips the `EPOLL_CTL_DEL` call because the kernel + * automatically removes closed file descriptors from epoll. + * + * Doing `EPOLL_CTL_DEL` on a closed file descriptor usually + * fails with `-EBADF` or could unregister a different socket + * which happens to be on the same file descriptor number. + */ + void Abandon() noexcept; + + unsigned GetScheduledFlags() const noexcept { + return scheduled_flags; + } + + void SetReadyFlags(unsigned flags) noexcept { + ready_flags = flags; + } + + /** + * @return true on success, false on error (with errno set if + * USE_EPOLL is defined) + */ + bool Schedule(unsigned flags) noexcept; + + void Cancel() noexcept { + Schedule(0); + } + + bool ScheduleRead() noexcept { + return Schedule(GetScheduledFlags() | READ); + } + + bool ScheduleWrite() noexcept { + return Schedule(GetScheduledFlags() | WRITE); + } + + void CancelRead() noexcept { + Schedule(GetScheduledFlags() & ~READ); + } + + void CancelWrite() noexcept { + Schedule(GetScheduledFlags() & ~WRITE); + } + + /** + * Schedule only the #IMPLICIT_FLAGS without #READ and #WRITE. + */ + void ScheduleImplicit() noexcept { + Schedule(IMPLICIT_FLAGS); + } + + bool IsReadPending() const noexcept { + return GetScheduledFlags() & READ; + } + + bool IsWritePending() const noexcept { + return GetScheduledFlags() & WRITE; + } + +private: + /** + * Dispatch the events that were passed to SetReadyFlags(). + */ + void Dispatch() noexcept; +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/event/TimerEvent.hxx
Added
@@ -0,0 +1,41 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "FineTimerEvent.hxx" + +/** + * This is a transitional alias. Use #FineTimerEvent or + * #CoarseTimerEvent instead. + */ +using TimerEvent = FineTimerEvent;
View file
ncmpc-0.47.tar.xz/src/event/TimerList.cxx
Added
@@ -0,0 +1,91 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Loop.hxx" +#include "FineTimerEvent.hxx" + +#ifdef NO_BOOST +#include <algorithm> +#endif + +constexpr bool +TimerList::Compare::operator()(const FineTimerEvent &a, + const FineTimerEvent &b) const noexcept +{ + return a.due < b.due; +} + +TimerList::TimerList() = default; + +TimerList::~TimerList() noexcept +{ + assert(timers.empty()); +} + +void +TimerList::Insert(FineTimerEvent &t) noexcept +{ +#ifdef NO_BOOST + auto i = std::find_if(timers.begin(), timers.end(), due = t.GetDue()(const auto &other){ + return other.GetDue() >= due; + }); + + timers.insert(i, t); +#else + timers.insert(t); +#endif +} + +Event::Duration +TimerList::Run(const Event::TimePoint now) noexcept +{ + while (true) { + auto i = timers.begin(); + if (i == timers.end()) + break; + + auto &t = *i; + const auto timeout = t.due - now; + if (timeout > timeout.zero()) + return timeout; + +#ifdef NO_BOOST + t.Cancel(); +#else + timers.erase(i); +#endif + + t.Run(); + } + + return Event::Duration(-1); +}
View file
ncmpc-0.47.tar.xz/src/event/TimerList.hxx
Added
@@ -0,0 +1,85 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "Chrono.hxx" +#include "event/Features.h" +#include "util/IntrusiveList.hxx" + +#ifndef NO_BOOST +#include <boost/intrusive/set.hpp> +#endif + +class FineTimerEvent; + +/** + * A list of #FineTimerEvent instances sorted by due time point. + */ +class TimerList final { + struct Compare { + constexpr bool operator()(const FineTimerEvent &a, + const FineTimerEvent &b) const noexcept; + }; + +#ifdef NO_BOOST + /* when building without Boost, then this is just a sorted + doubly-linked list - this doesn't scale well, but is good + enough for most programs */ + IntrusiveList<FineTimerEvent> timers; +#else + boost::intrusive::multiset<FineTimerEvent, + boost::intrusive::base_hook<boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>>, + boost::intrusive::compare<Compare>, + boost::intrusive::constant_time_size<false>> timers; +#endif + +public: + TimerList(); + ~TimerList() noexcept; + + TimerList(const TimerList &other) = delete; + TimerList &operator=(const TimerList &other) = delete; + + bool IsEmpty() const noexcept { + return timers.empty(); + } + + void Insert(FineTimerEvent &t) noexcept; + + /** + * Invoke all expired #FineTimerEvent instances and return the + * duration until the next timer expires. Returns a negative + * duration if there is no timeout. + */ + Event::Duration Run(Event::TimePoint now) noexcept; +};
View file
ncmpc-0.47.tar.xz/src/event/TimerWheel.cxx
Added
@@ -0,0 +1,175 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TimerWheel.hxx" +#include "CoarseTimerEvent.hxx" + +#include <cassert> + +TimerWheel::TimerWheel() noexcept +{ + /* cannot use "=default" due to bug in GCC9 and older + ("defaulted on its redeclaration with an + exception-specification that differs from the implicit + exception-specification") */ +} + +TimerWheel::~TimerWheel() noexcept = default; + +void +TimerWheel::Insert(CoarseTimerEvent &t, + Event::TimePoint now) noexcept +{ + assert(now >= last_time); + + auto &list = t.GetDue() > now + ? bucketsBucketIndexAt(t.GetDue()) + /* if this timer is already due, insert it into the + "ready" list to be invoked without delay */ + : ready; + + list.push_back(t); + + empty = false; +} + +void +TimerWheel::Run(List &list, Event::TimePoint now) noexcept +{ + /* move all timers to a temporary list to avoid problems with + canceled timers while we traverse the list */ + auto tmp = std::move(list); + + tmp.clear_and_dispose(&(auto *t){ + if (t->GetDue() <= now) { + /* this timer is due: run it */ + t->Run(); + } else { + /* not yet due: move it back to the given + list */ + list.push_back(*t); + } + }); +} + +inline Event::TimePoint +TimerWheel::GetNextDue(const std::size_t bucket_index, + const Event::TimePoint bucket_start_time) const noexcept +{ + Event::TimePoint t = bucket_start_time; + + for (std::size_t i = bucket_index;;) { + t += RESOLUTION; + + if (!bucketsi.empty()) + /* found a non-empty bucket; return this + bucket's end time */ + return t; + + i = NextBucketIndex(i); + if (i == bucket_index) + /* no timer scheduled - no wakeup */ + return Event::TimePoint::max(); + } +} + +inline Event::Duration +TimerWheel::GetSleep(Event::TimePoint now) const noexcept +{ + /* note: not checking the "ready" list here because this + method gets called only from Run() after the "ready" list + has been processed already */ + + if (empty) + return Event::Duration(-1); + + auto t = GetNextDue(BucketIndexAt(now), GetBucketStartTime(now)); + assert(t > now); + if (t == Event::TimePoint::max()) { + empty = true; + return Event::Duration(-1); + } + + return t - now; +} + +Event::Duration +TimerWheel::Run(const Event::TimePoint now) noexcept +{ + /* invoke the "ready" list unconditionally */ + ready.clear_and_dispose(&(auto *t){ + t->Run(); + }); + + /* check all buckets between the last time we were invoked and + now */ + const std::size_t start_bucket = BucketIndexAt(last_time); + std::size_t end_bucket; + + if (now < last_time || now >= last_time + SPAN - RESOLUTION) { + /* too much time has passed (or time warp): check all + buckets */ + end_bucket = start_bucket; + } else { + /* check only the relevant range of buckets (between + the last run and now) */ + /* note, we're not checking the current bucket index, + we stop at the one before that; all timers in the + same bucket shall be combined, so we only execute + it when the bucket end has passed by */ + end_bucket = BucketIndexAt(now); + + if (start_bucket == end_bucket) + /* still on the same bucket - don't run any + timers, instead wait until this bucket end + has passed by */ + return GetSleep(now); + } + + last_time = GetBucketStartTime(now); + assert(BucketIndexAt(last_time) == BucketIndexAt(now)); + + /* run those buckets */ + + for (std::size_t i = start_bucket;;) { + Run(bucketsi, now); + + i = NextBucketIndex(i); + if (i == end_bucket) + break; + } + + /* now determine how much time remains until the next + non-empty bucket passes */ + + return GetSleep(now); +}
View file
ncmpc-0.47.tar.xz/src/event/TimerWheel.hxx
Added
@@ -0,0 +1,145 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "Chrono.hxx" +#include "util/IntrusiveList.hxx" + +#include <array> +#include <algorithm> + +class CoarseTimerEvent; + +/** + * A list of #CoarseTimerEvent instances managed in a circular timer + * wheel. + */ +class TimerWheel final { + static constexpr Event::Duration RESOLUTION = std::chrono::milliseconds(250); + static constexpr Event::Duration SPAN = std::chrono::minutes(1); + + static_assert(SPAN % RESOLUTION == Event::Duration::zero()); + + static constexpr std::size_t N_BUCKETS = SPAN / RESOLUTION; + + using List = IntrusiveList<CoarseTimerEvent>; + + /** + * Each bucket contains a doubly linked list of + * #CoarseTimerEvent instances scheduled for one #RESOLUTION. + * + * Timers scheduled far into the future (more than #SPAN) may + * also sit in between, so anybody walking those lists should + * check the due time. + */ + std::array<List, N_BUCKETS> buckets; + + /** + * A list of timers which are already ready. This can happen + * if they are scheduled with a zero duration or scheduled in + * the past. + */ + List ready; + + /** + * The last time Run() was invoked. This is needed to + * determine the range of buckets to be checked, because we + * can't rely on getting a caller for every bucket; there may + * be arbitrary delays. + */ + Event::TimePoint last_time{}; + + /** + * If this flag is true, then all buckets are guaranteed to be + * empty. If it is false, the buckets may or may not be + * empty; if so, the next full scan will set it back to true. + * + * This field is "mutable" so the "const" method GetSleep() + * can update it. + */ + mutable bool empty = true; + +public: + TimerWheel() noexcept; + ~TimerWheel() noexcept; + + bool IsEmpty() const noexcept { + return ready.empty() && + std::all_of(buckets.begin(), buckets.end(), + (const auto &list){ + return list.empty(); + }); + } + + void Insert(CoarseTimerEvent &t, + Event::TimePoint now) noexcept; + + /** + * Invoke all expired #CoarseTimerEvent instances and return + * the duration until the next timer expires. Returns a + * negative duration if there is no timeout. + */ + Event::Duration Run(Event::TimePoint now) noexcept; + +private: + static constexpr std::size_t NextBucketIndex(std::size_t i) noexcept { + return (i + 1) % N_BUCKETS; + } + + static constexpr std::size_t BucketIndexAt(Event::TimePoint t) noexcept { + return std::size_t(t.time_since_epoch() / RESOLUTION) + % N_BUCKETS; + } + + static constexpr Event::TimePoint GetBucketStartTime(Event::TimePoint t) noexcept { + return t - t.time_since_epoch() % RESOLUTION; + } + + /** + * What is the end time of the next non-empty bucket? + * + * @param bucket_index start searching at this bucket index + * @return the bucket end time or max() if the wheel is empty + */ + gnu::pure + Event::TimePoint GetNextDue(std::size_t bucket_index, + Event::TimePoint bucket_start_time) const noexcept; + + gnu::pure + Event::Duration GetSleep(Event::TimePoint now) const noexcept; + + /** + * Run all due timers in this bucket. + */ + static void Run(List &list, Event::TimePoint now) noexcept; +};
View file
ncmpc-0.47.tar.xz/src/event/WakeFD.hxx
Added
@@ -0,0 +1,57 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_WAKE_FD_HXX +#define MPD_WAKE_FD_HXX + +#include "net/SocketDescriptor.hxx" +#include "event/Features.h" + +#ifdef USE_EVENTFD +#include "system/EventFD.hxx" +#else +#include "system/EventPipe.hxx" +#endif + +class WakeFD { +#ifdef USE_EVENTFD + EventFD fd; +#else + EventPipe fd; +#endif + +public: + SocketDescriptor GetSocket() const noexcept { +#ifdef _WIN32 + return fd.Get(); +#else + return SocketDescriptor::FromFileDescriptor(fd.Get()); +#endif + } + + bool Read() noexcept { + return fd.Read(); + } + + void Write() noexcept { + fd.Write(); + } +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/event/WinSelectBackend.cxx
Added
@@ -0,0 +1,170 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "WinSelectBackend.hxx" +#include "WinSelectEvents.hxx" + +static constexpr int EVENT_READ = 0; +static constexpr int EVENT_WRITE = 1; + +static constexpr +bool HasEvent(unsigned events, int event_id) noexcept +{ + return (events & (1 << event_id)) != 0; +} + +WinSelectBackend::WinSelectBackend() noexcept = default; +WinSelectBackend::~WinSelectBackend() noexcept = default; + +bool +WinSelectBackend::CanModify(WinSelectBackend::Item &item, + unsigned events, int event_id) const noexcept +{ + if (item.indexevent_id < 0 && HasEvent(events, event_id)) + return !event_setevent_id.IsFull(); + return true; +} + +void +WinSelectBackend::Modify(WinSelectBackend::Item &item, SOCKET fd, + unsigned events, int event_id) noexcept +{ + int index = item.indexevent_id; + auto &set = event_setevent_id; + + if (index < 0 && HasEvent(events, event_id)) + item.indexevent_id = set.Add(fd); + else if (index >= 0 && !HasEvent(events, event_id)) { + if (size_t(index) != set.Size() - 1) { + set.MoveToEnd(index); + items.find(setindex)->second.indexevent_id = index; + } + set.RemoveLast(); + item.indexevent_id = -1; + } +} + +bool +WinSelectBackend::Add(SOCKET fd, unsigned events, void *obj) noexcept +{ + assert(items.find(fd) == items.end()); + auto i = items.emplace(std::piecewise_construct, + std::forward_as_tuple(fd), + std::forward_as_tuple(obj)).first; + auto &item = i->second; + + if (!CanModify(item, events, EVENT_READ)) { + items.erase(i); + return false; + } + if (!CanModify(item, events, EVENT_WRITE)) { + items.erase(i); + return false; + } + + Modify(item, fd, events, EVENT_READ); + Modify(item, fd, events, EVENT_WRITE); + return true; +} + +bool +WinSelectBackend::Modify(SOCKET fd, unsigned events, void *obj) noexcept +{ + auto item_iter = items.find(fd); + assert(item_iter != items.end()); + auto &item = item_iter->second; + + if (!CanModify(item, events, EVENT_READ)) + return false; + if (!CanModify(item, events, EVENT_WRITE)) + return false; + + item.obj = obj; + Modify(item, fd, events, EVENT_READ); + Modify(item, fd, events, EVENT_WRITE); + return true; +} + +bool +WinSelectBackend::Remove(SOCKET fd) noexcept +{ + auto item_iter = items.find(fd); + assert(item_iter != items.end()); + auto &item = item_iter->second; + + Modify(item, fd, 0, EVENT_READ); + Modify(item, fd, 0, EVENT_WRITE); + items.erase(item_iter); + return true; +} + +void +WinSelectBackend::ApplyReady(const SocketSet &src, unsigned events) noexcept +{ + for (const auto i : src) { + auto it = items.find(i); + assert(it != items.end()); + + it->second.events |= events; + } +} + +PollResultGeneric +WinSelectBackend::ReadEvents(int timeout_ms) noexcept +{ + bool use_sleep = event_setEVENT_READ.IsEmpty() && + event_setEVENT_WRITE.IsEmpty(); + + PollResultGeneric result; + if (use_sleep) { + Sleep(timeout_ms < 0 ? INFINITE : (DWORD) timeout_ms); + return result; + } + + SocketSet read_set(event_setEVENT_READ); + SocketSet write_set(event_setEVENT_WRITE); + SocketSet except_set(event_setEVENT_WRITE); + + timeval tv; + if (timeout_ms >= 0) { + tv.tv_sec = timeout_ms / 1000; + tv.tv_usec = (timeout_ms % 1000) * 1000; + } + + int ret = select(0, + read_set.GetPtr(), + write_set.GetPtr(), + except_set.GetPtr(), + timeout_ms < 0 ? nullptr : &tv); + + if (ret == 0 || ret == SOCKET_ERROR) + return result; + + ApplyReady(read_set, WinSelectEvents::READ); + ApplyReady(write_set, WinSelectEvents::WRITE); + ApplyReady(except_set, WinSelectEvents::WRITE); + + for (auto &key, item : items) + if (item.events != 0) { + result.Add(item.events, item.obj); + item.events = 0; + } + + return result; +}
View file
ncmpc-0.47.tar.xz/src/event/WinSelectBackend.hxx
Added
@@ -0,0 +1,132 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef EVENT_WINSELECT_BACKEND_HXX +#define EVENT_WINSELECT_BACKEND_HXX + +#include "PollResultGeneric.hxx" + +#include <algorithm> +#include <cassert> +#include <unordered_map> + +#include <winsock2.h> + +class SocketSet +{ + fd_set set; +public: + SocketSet() noexcept { + set.fd_count = 0; + } + + SocketSet(const SocketSet &other) noexcept { + set.fd_count = other.set.fd_count; + std::copy_n(other.set.fd_array, set.fd_count, set.fd_array); + } + + fd_set *GetPtr() noexcept { + return IsEmpty() ? nullptr : &set; + } + + size_t Size() const noexcept { + return set.fd_count; + } + + bool IsEmpty() const noexcept { + return set.fd_count == 0; + } + + bool IsFull() const noexcept { + return set.fd_count == FD_SETSIZE; + } + + SOCKET operator(size_t index) const noexcept { + assert(index < set.fd_count); + return set.fd_arrayindex; + } + + size_t Add(SOCKET fd) noexcept { + assert(!IsFull()); + set.fd_arrayset.fd_count = fd; + return set.fd_count++; + } + + void MoveToEnd(size_t index) noexcept { + assert(index < set.fd_count); + std::swap(set.fd_arrayindex, set.fd_arrayset.fd_count - 1); + } + + void RemoveLast() noexcept { + assert(!IsEmpty()); + --set.fd_count; + } + + const auto *begin() const noexcept { + return set.fd_array; + } + + const auto *end() const noexcept { + return set.fd_array + set.fd_count; + } +}; + +class WinSelectBackend +{ + struct Item + { + int index2{-1, -1}; + void *obj; + unsigned events = 0; + + explicit constexpr Item(void *_obj) noexcept + :obj(_obj) {} + + Item(const Item &) = delete; + Item &operator=(const Item &) = delete; + }; + + SocketSet event_set2; + std::unordered_map<SOCKET, Item> items; + +public: + WinSelectBackend() noexcept; + ~WinSelectBackend() noexcept; + + WinSelectBackend(const WinSelectBackend &) = delete; + WinSelectBackend &operator=(const WinSelectBackend &) = delete; + + PollResultGeneric ReadEvents(int timeout_ms) noexcept; + bool Add(SOCKET fd, unsigned events, void *obj) noexcept; + bool Modify(SOCKET fd, unsigned events, void *obj) noexcept; + bool Remove(SOCKET fd) noexcept; + bool Abandon(SOCKET fd) noexcept { + return Remove(fd); + } + +private: + bool CanModify(Item &item, unsigned events, + int event_id) const noexcept; + void Modify(Item &item, SOCKET fd, unsigned events, + int event_id) noexcept; + + void ApplyReady(const SocketSet &src, unsigned events) noexcept; +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/event/WinSelectEvents.hxx
Added
@@ -0,0 +1,38 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef EVENT_WINSELECT_EVENTS_HXX +#define EVENT_WINSELECT_EVENTS_HXX + +#include <windows.h> + +/* ERROR is a WIN32 macro that poisons our namespace; this is a kludge + to allow us to use it anyway */ +#ifdef ERROR +#undef ERROR +#endif + +struct WinSelectEvents { + static constexpr unsigned READ = 1; + static constexpr unsigned WRITE = 2; + static constexpr unsigned ERROR = 0; + static constexpr unsigned HANGUP = 0; +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/event/meson.build
Added
@@ -0,0 +1,42 @@ +event_features = configuration_data() +event_features.set('USE_EVENTFD', is_linux and get_option('eventfd')) +event_features.set('USE_SIGNALFD', is_linux and get_option('signalfd')) +event_features.set('USE_EPOLL', is_linux and get_option('epoll')) +event_features.set('NO_BOOST', true) +configure_file(output: 'Features.h', configuration: event_features) + +event_sources = + +if is_windows + event_sources += 'WinSelectBackend.cxx' +elif is_linux and get_option('epoll') + # epoll support is header-only +else + event_sources += 'PollBackend.cxx' +endif + +event = static_library( + 'event', + 'SignalMonitor.cxx', + 'TimerWheel.cxx', + 'TimerList.cxx', + 'CoarseTimerEvent.cxx', + 'FineTimerEvent.cxx', + 'DeferEvent.cxx', + 'IdleEvent.cxx', + 'SocketEvent.cxx', + 'Loop.cxx', + event_sources, + include_directories: inc, + dependencies: + , +) + +event_dep = declare_dependency( + link_with: event, + dependencies: + thread_dep, + net_dep, + system_dep, + , +)
View file
ncmpc-0.47.tar.xz/src/event/net
Added
+(directory)
View file
ncmpc-0.47.tar.xz/src/event/net/ConnectSocket.cxx
Added
@@ -0,0 +1,170 @@ +/* + * Copyright 2007-2021 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ConnectSocket.hxx" +#include "net/UniqueSocketDescriptor.hxx" +#include "net/SocketAddress.hxx" +#include "net/AddressInfo.hxx" +#include "net/SocketError.hxx" + +#include <cassert> +#include <stdexcept> + +void +ConnectSocketHandler::OnSocketConnectTimeout() noexcept +{ + /* default implementation falls back to OnSocketConnectError() */ + OnSocketConnectError(std::make_exception_ptr(std::runtime_error("Connect timeout"))); +} + +ConnectSocket::ConnectSocket(EventLoop &_event_loop, + ConnectSocketHandler &_handler) noexcept + :handler(_handler), + event(_event_loop, BIND_THIS_METHOD(OnEvent)), + timeout_event(_event_loop, BIND_THIS_METHOD(OnTimeout)) +{ +} + +ConnectSocket::~ConnectSocket() noexcept +{ + event.Close(); +} + +void +ConnectSocket::Cancel() noexcept +{ + assert(IsPending()); + + timeout_event.Cancel(); + event.Close(); +} + +static UniqueSocketDescriptor +Connect(const SocketAddress address) +{ + UniqueSocketDescriptor fd; + if (!fd.CreateNonBlock(address.GetFamily(), SOCK_STREAM, 0)) + throw MakeSocketError("Failed to create socket"); + + if (!fd.Connect(address)) { + const auto e = GetSocketError(); + if (!IsSocketErrorConnectWouldBlock(e)) + throw MakeSocketError(e, "Failed to connect"); + } + + return fd; +} + +bool +ConnectSocket::Connect(const SocketAddress address, + Event::Duration timeout) noexcept +{ + assert(!event.IsDefined()); + + try { + WaitConnected(::Connect(address), timeout); + return true; + } catch (...) { + handler.OnSocketConnectError(std::current_exception()); + return false; + } +} + +static UniqueSocketDescriptor +Connect(const AddressInfo &address) +{ + UniqueSocketDescriptor fd; + if (!fd.CreateNonBlock(address.GetFamily(), address.GetType(), + address.GetProtocol())) + throw MakeSocketError("Failed to create socket"); + + if (!fd.Connect(address)) { + const auto e = GetSocketError(); + if (!IsSocketErrorConnectWouldBlock(e)) + throw MakeSocketError(e, "Failed to connect"); + } + + return fd; +} + +bool +ConnectSocket::Connect(const AddressInfo &address, + Event::Duration timeout) noexcept +{ + assert(!event.IsDefined()); + + try { + WaitConnected(::Connect(address), timeout); + return true; + } catch (...) { + handler.OnSocketConnectError(std::current_exception()); + return false; + } +} + +void +ConnectSocket::WaitConnected(UniqueSocketDescriptor _fd, + Event::Duration timeout) noexcept +{ + assert(!event.IsDefined()); + + event.Open(_fd.Release()); + event.ScheduleWrite(); + + if (timeout >= Event::Duration{}) + timeout_event.Schedule(timeout); +} + +void +ConnectSocket::OnEvent(unsigned events) noexcept +{ + timeout_event.Cancel(); + + if (SocketEvent::ERROR == 0 || events & SocketEvent::ERROR) { + int s_err = event.GetSocket().GetError(); + if (s_err != 0) { + event.Close(); + handler.OnSocketConnectError(std::make_exception_ptr(MakeSocketError(s_err, "Failed to connect"))); + return; + } + } + + handler.OnSocketConnectSuccess(UniqueSocketDescriptor(event.ReleaseSocket())); +} + +void +ConnectSocket::OnTimeout() noexcept +{ + event.Close(); + + handler.OnSocketConnectTimeout(); +}
View file
ncmpc-0.47.tar.xz/src/event/net/ConnectSocket.hxx
Added
@@ -0,0 +1,98 @@ +/* + * Copyright 2007-2021 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "event/SocketEvent.hxx" +#include "event/CoarseTimerEvent.hxx" +#include "util/Cancellable.hxx" + +#include <exception> + +class UniqueSocketDescriptor; +class SocketAddress; +class AddressInfo; + +class ConnectSocketHandler { +public: + virtual void OnSocketConnectSuccess(UniqueSocketDescriptor fd) noexcept = 0; + virtual void OnSocketConnectTimeout() noexcept; + virtual void OnSocketConnectError(std::exception_ptr ep) noexcept = 0; +}; + +/** + * A class that connects to a SocketAddress. + */ +class ConnectSocket final : public Cancellable { + ConnectSocketHandler &handler; + + SocketEvent event; + CoarseTimerEvent timeout_event; + +public: + ConnectSocket(EventLoop &_event_loop, + ConnectSocketHandler &_handler) noexcept; + ~ConnectSocket() noexcept; + + auto &GetEventLoop() const noexcept { + return event.GetEventLoop(); + } + + bool IsPending() const noexcept { + return event.IsDefined(); + } + + /** + * @param timeout a timeout or a negative value to disable + * timeouts + */ + bool Connect(const SocketAddress address, + Event::Duration timeout) noexcept; + + bool Connect(const AddressInfo &address, + Event::Duration timeout) noexcept; + + /** + * Wait until the given socket is connected (this method returns + * immediately and invokes the #ConnectSocketHandler on completion + * or error). + */ + void WaitConnected(UniqueSocketDescriptor _fd, + Event::Duration timeout=Event::Duration(-1)) noexcept; + + /* virtual methods from Cancellable */ + void Cancel() noexcept override; + +private: + void OnEvent(unsigned events) noexcept; + void OnTimeout() noexcept; +};
View file
ncmpc-0.36.tar.xz/src/filelist.cxx -> ncmpc-0.47.tar.xz/src/filelist.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -27,15 +26,15 @@ #include <string.h> #include <assert.h> -FileListEntry::~FileListEntry() +FileListEntry::~FileListEntry() noexcept { if (entity) mpd_entity_free(entity); } -gcc_pure +gnu::pure static bool -Less(const struct mpd_entity &a, struct mpd_entity &b) +Less(const struct mpd_entity &a, struct mpd_entity &b) noexcept { const auto a_type = mpd_entity_get_type(&a); const auto b_type = mpd_entity_get_type(&b); @@ -61,9 +60,9 @@ return false; } -gcc_pure +gnu::pure static bool -Less(const struct mpd_entity *a, struct mpd_entity *b) +Less(const struct mpd_entity *a, struct mpd_entity *b) noexcept { if (a == nullptr) return b != nullptr; @@ -74,20 +73,20 @@ } bool -FileListEntry::operator<(const FileListEntry &other) const +FileListEntry::operator<(const FileListEntry &other) const noexcept { return Less(entity, other.entity); } FileListEntry & -FileList::emplace_back(struct mpd_entity *entity) +FileList::emplace_back(struct mpd_entity *entity) noexcept { entries.emplace_back(entity); return entries.back(); } void -FileList::MoveFrom(FileList &&src) +FileList::MoveFrom(FileList &&src) noexcept { entries.reserve(size() + src.size()); for (auto &i : src.entries) @@ -96,13 +95,13 @@ } void -FileList::Sort() +FileList::Sort() noexcept { std::stable_sort(entries.begin(), entries.end()); } void -FileList::RemoveDuplicateSongs() +FileList::RemoveDuplicateSongs() noexcept { for (int i = size() - 1; i >= 0; --i) { auto &entry = (*this)i; @@ -117,14 +116,15 @@ } } +gnu::pure static bool -same_song(const struct mpd_song *a, const struct mpd_song *b) +same_song(const struct mpd_song *a, const struct mpd_song *b) noexcept { return strcmp(mpd_song_get_uri(a), mpd_song_get_uri(b)) == 0; } int -FileList::FindSong(const struct mpd_song &song) const +FileList::FindSong(const struct mpd_song &song) const noexcept { for (unsigned i = 0; i < size(); ++i) { auto &entry = (*this)i; @@ -142,7 +142,7 @@ } int -FileList::FindDirectory(const char *name) const +FileList::FindDirectory(const char *name) const noexcept { assert(name != nullptr); @@ -161,7 +161,7 @@ } void -FileList::Receive(struct mpd_connection &connection) +FileList::Receive(struct mpd_connection &connection) noexcept { struct mpd_entity *entity; @@ -169,10 +169,10 @@ emplace_back(entity); } -FileList * -filelist_new_recv(struct mpd_connection *connection) +std::unique_ptr<FileList> +filelist_new_recv(struct mpd_connection *connection) noexcept { - auto *filelist = new FileList(); + auto filelist = std::make_unique<FileList>(); filelist->Receive(*connection); return filelist; }
View file
ncmpc-0.36.tar.xz/src/filelist.hxx -> ncmpc-0.47.tar.xz/src/filelist.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,8 +19,7 @@ #ifndef FILELIST_H #define FILELIST_H -#include "util/Compiler.h" - +#include <memory> #include <vector> #include <utility> @@ -32,23 +30,23 @@ unsigned flags = 0; struct mpd_entity *entity; - explicit FileListEntry(struct mpd_entity *_entity) + explicit FileListEntry(struct mpd_entity *_entity) noexcept :entity(_entity) {} - ~FileListEntry(); + ~FileListEntry() noexcept; - FileListEntry(FileListEntry &&src) + FileListEntry(FileListEntry &&src) noexcept :flags(src.flags), entity(std::exchange(src.entity, nullptr)) {} - FileListEntry &operator=(FileListEntry &&src) { + FileListEntry &operator=(FileListEntry &&src) noexcept { using std::swap; flags = src.flags; swap(entity, src.entity); return *this; } - gcc_pure - bool operator<(const FileListEntry &other) const; + gnu::pure + bool operator<(const FileListEntry &other) const noexcept; }; class FileList { @@ -65,55 +63,55 @@ FileList(const FileList &) = delete; FileList &operator=(const FileList &) = delete; - size_type size() const { + size_type size() const noexcept { return entries.size(); } - bool empty() const { + bool empty() const noexcept { return entries.empty(); } - FileListEntry &operator(size_type i) { + FileListEntry &operator(size_type i) noexcept { return entriesi; } - const FileListEntry &operator(size_type i) const { + const FileListEntry &operator(size_type i) const noexcept { return entriesi; } - FileListEntry &emplace_back(struct mpd_entity *entity); + FileListEntry &emplace_back(struct mpd_entity *entity) noexcept; - void MoveFrom(FileList &&src); + void MoveFrom(FileList &&src) noexcept; /** * Sort the whole list. */ - void Sort(); + void Sort() noexcept; /** * Eliminates duplicate songs from the FileList. */ - void RemoveDuplicateSongs(); + void RemoveDuplicateSongs() noexcept; - gcc_pure - int FindSong(const struct mpd_song &song) const; + gnu::pure + int FindSong(const struct mpd_song &song) const noexcept; - gcc_pure - int FindDirectory(const char *name) const; + gnu::pure + int FindDirectory(const char *name) const noexcept; /** * Receives entities from the connection, and appends them to the * specified FileList. This does not finish the response, and does * not check for errors. */ - void Receive(struct mpd_connection &connection); + void Receive(struct mpd_connection &connection) noexcept; }; /** * Creates a new FileList and receives entities from the connection. * This does not finish the response, and does not check for errors. */ -FileList * -filelist_new_recv(struct mpd_connection *connection); +std::unique_ptr<FileList> +filelist_new_recv(struct mpd_connection *connection) noexcept; #endif
View file
ncmpc-0.36.tar.xz/src/gidle.cxx -> ncmpc-0.47.tar.xz/src/gidle.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - (c) 2004-2019 The Music Player Daemon Project - Project homepage: http://musicpd.org + Copyright 2004-2021 The Music Player Daemon Project Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -34,22 +33,21 @@ #include <assert.h> #include <string.h> -MpdIdleSource::MpdIdleSource(boost::asio::io_service &io_service, +MpdIdleSource::MpdIdleSource(EventLoop &event_loop, struct mpd_connection &_connection, MpdIdleHandler &_handler) noexcept :connection(&_connection), async(mpd_connection_get_async(connection)), parser(mpd_parser_new()), - handler(_handler), - socket(io_service, mpd_async_get_fd(async)) + event(event_loop, BIND_THIS_METHOD(OnSocketReady), + SocketDescriptor(mpd_async_get_fd(async))), + handler(_handler) { /* TODO check parser!=nullptr */ } MpdIdleSource::~MpdIdleSource() noexcept { - socket.release(); - mpd_parser_free(parser); } @@ -70,6 +68,7 @@ result = mpd_parser_feed(parser, line); switch (result) { case MPD_PARSER_MALFORMED: + event.Cancel(); io_events = 0; InvokeError(MPD_ERROR_MALFORMED, @@ -78,12 +77,14 @@ return false; case MPD_PARSER_SUCCESS: + event.Cancel(); io_events = 0; InvokeCallback(); return false; case MPD_PARSER_ERROR: + event.Cancel(); io_events = 0; InvokeError(MPD_ERROR_SERVER, @@ -113,6 +114,7 @@ } if (mpd_async_get_error(async) != MPD_ERROR_SUCCESS) { + event.Cancel(); io_events = 0; InvokeAsyncError(); @@ -123,88 +125,44 @@ } void -MpdIdleSource::OnReadable(const boost::system::error_code &error) noexcept +MpdIdleSource::OnSocketReady(unsigned flags) noexcept { - io_events &= ~MPD_ASYNC_EVENT_READ; - - if (error) { - if (error == boost::asio::error::operation_aborted) - return; - - // TODO - return; - } - - if (!mpd_async_io(async, MPD_ASYNC_EVENT_READ)) { - socket.cancel(); + unsigned events = 0; + if (flags & SocketEvent::READ) + events |= MPD_ASYNC_EVENT_READ; + if (flags & SocketEvent::WRITE) + events |= MPD_ASYNC_EVENT_WRITE; + + if (!mpd_async_io(async, (enum mpd_async_event)events)) { + event.Cancel(); io_events = 0; InvokeAsyncError(); return; } - if (!Receive()) - return; - - UpdateSocket(); -} - -void -MpdIdleSource::OnWritable(const boost::system::error_code &error) noexcept -{ - io_events &= ~MPD_ASYNC_EVENT_WRITE; - - if (error) { - if (error == boost::asio::error::operation_aborted) + if (flags & SocketEvent::READ) + if (!Receive()) return; - // TODO - return; - } - - if (!mpd_async_io(async, MPD_ASYNC_EVENT_WRITE)) { - socket.cancel(); - io_events = 0; - - InvokeAsyncError(); - return; - } - UpdateSocket(); } void -MpdIdleSource::AsyncRead() noexcept -{ - io_events |= MPD_ASYNC_EVENT_READ; - socket.async_read_some(boost::asio::null_buffers(), - std::bind(&MpdIdleSource::OnReadable, this, - std::placeholders::_1)); -} - -void -MpdIdleSource::AsyncWrite() noexcept -{ - io_events |= MPD_ASYNC_EVENT_WRITE; - socket.async_write_some(boost::asio::null_buffers(), - std::bind(&MpdIdleSource::OnWritable, this, - std::placeholders::_1)); -} - -void MpdIdleSource::UpdateSocket() noexcept { enum mpd_async_event events = mpd_async_events(async); if (events == io_events) return; - socket.cancel(); - + unsigned flags = 0; if (events & MPD_ASYNC_EVENT_READ) - AsyncRead(); + flags |= SocketEvent::READ; if (events & MPD_ASYNC_EVENT_WRITE) - AsyncWrite(); + flags |= SocketEvent::WRITE; + + event.Schedule(flags); io_events = events; } @@ -232,7 +190,7 @@ /* already left, callback was invoked */ return; - socket.cancel(); + event.Cancel(); io_events = 0; enum mpd_idle events = idle_events == 0
View file
ncmpc-0.36.tar.xz/src/gidle.hxx -> ncmpc-0.47.tar.xz/src/gidle.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - (c) 2004-2019 The Music Player Daemon Project - Project homepage: http://musicpd.org + Copyright 2004-2021 The Music Player Daemon Project Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -29,12 +28,10 @@ #ifndef MPD_GLIB_SOURCE_H #define MPD_GLIB_SOURCE_H -#include "AsioServiceFwd.hxx" +#include "event/SocketEvent.hxx" #include <mpd/client.h> -#include <boost/asio/posix/stream_descriptor.hpp> - class MpdIdleHandler { public: virtual void OnIdle(unsigned events) noexcept = 0; @@ -43,21 +40,21 @@ const char *message) noexcept = 0; }; -class MpdIdleSource { +class MpdIdleSource final { struct mpd_connection *connection; struct mpd_async *async; struct mpd_parser *parser; - MpdIdleHandler &handler; + SocketEvent event; - boost::asio::posix::stream_descriptor socket; + MpdIdleHandler &handler; unsigned io_events = 0; unsigned idle_events; public: - MpdIdleSource(boost::asio::io_service &io_service, + MpdIdleSource(EventLoop &event_loop, struct mpd_connection &_connection, MpdIdleHandler &_handler) noexcept; ~MpdIdleSource() noexcept; @@ -103,11 +100,8 @@ */ bool Receive() noexcept; - void OnReadable(const boost::system::error_code &error) noexcept; - void OnWritable(const boost::system::error_code &error) noexcept; + void OnSocketReady(unsigned flags) noexcept; - void AsyncRead() noexcept; - void AsyncWrite() noexcept; void UpdateSocket() noexcept; };
View file
ncmpc-0.36.tar.xz/src/hscroll.cxx -> ncmpc-0.47.tar.xz/src/hscroll.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -22,12 +21,9 @@ #include <assert.h> -inline void -hscroll::TimerCallback(const boost::system::error_code &error) noexcept +void +hscroll::OnTimer() noexcept { - if (error) - return; - Step(); Paint(); wrefresh(w); @@ -56,7 +52,7 @@ hscroll::Clear() noexcept { basic.Clear(); - timer.cancel(); + timer.Cancel(); } void
View file
ncmpc-0.36.tar.xz/src/hscroll.hxx -> ncmpc-0.47.tar.xz/src/hscroll.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -21,12 +20,10 @@ #define HSCROLL_H #include "BasicMarquee.hxx" -#include "AsioServiceFwd.hxx" +#include "event/FineTimerEvent.hxx" #include <curses.h> -#include <boost/asio/steady_timer.hpp> - enum class Style : unsigned; /** @@ -55,12 +52,13 @@ /** * A timer which updates the scrolled area every second. */ - boost::asio::steady_timer timer; + FineTimerEvent timer; public: - hscroll(boost::asio::io_service &io_service, + hscroll(EventLoop &event_loop, WINDOW *_w, const char *_separator) noexcept - :w(_w), basic(_separator), timer(io_service) + :w(_w), basic(_separator), + timer(event_loop, BIND_THIS_METHOD(OnTimer)) { } @@ -97,13 +95,10 @@ void Paint() const noexcept; private: - void TimerCallback(const boost::system::error_code &error) noexcept; + void OnTimer() noexcept; void ScheduleTimer() noexcept { - boost::system::error_code error; - timer.expires_from_now(std::chrono::seconds(1), error); - timer.async_wait(std::bind(&hscroll::TimerCallback, this, - std::placeholders::_1)); + timer.Schedule(std::chrono::seconds(1)); } };
View file
ncmpc-0.36.tar.xz/src/i18n.h -> ncmpc-0.47.tar.xz/src/i18n.h
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.47.tar.xz/src/io/FileDescriptor.cxx
Added
@@ -0,0 +1,374 @@ +/* + * Copyright 2012-2020 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "FileDescriptor.hxx" +#include "UniqueFileDescriptor.hxx" +#include "system/Error.hxx" + +#include <cassert> +#include <stdexcept> + +#include <sys/stat.h> +#include <fcntl.h> + +#ifndef _WIN32 +#include <poll.h> +#endif + +#ifdef __linux__ +#include <sys/eventfd.h> +#include <sys/signalfd.h> +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +#ifndef _WIN32 + +bool +FileDescriptor::IsValid() const noexcept +{ + return IsDefined() && fcntl(fd, F_GETFL) >= 0; +} + +bool +FileDescriptor::IsRegularFile() const noexcept +{ + struct stat st; + return IsDefined() && fstat(fd, &st) == 0 && S_ISREG(st.st_mode); +} + +bool +FileDescriptor::IsPipe() const noexcept +{ + struct stat st; + return IsDefined() && fstat(fd, &st) == 0 && S_ISFIFO(st.st_mode); +} + +bool +FileDescriptor::IsSocket() const noexcept +{ + struct stat st; + return IsDefined() && fstat(fd, &st) == 0 && S_ISSOCK(st.st_mode); +} + +#endif + +#ifdef __linux__ + +bool +FileDescriptor::Open(FileDescriptor dir, const char *pathname, + int flags, mode_t mode) noexcept +{ + fd = ::openat(dir.Get(), pathname, flags | O_NOCTTY | O_CLOEXEC, mode); + return IsDefined(); +} + +#endif + +bool +FileDescriptor::Open(const char *pathname, int flags, mode_t mode) noexcept +{ + fd = ::open(pathname, flags | O_NOCTTY | O_CLOEXEC, mode); + return IsDefined(); +} + +#ifdef _WIN32 + +bool +FileDescriptor::Open(const wchar_t *pathname, int flags, mode_t mode) noexcept +{ + fd = ::_wopen(pathname, flags | O_NOCTTY | O_CLOEXEC, mode); + return IsDefined(); +} + +#endif + +bool +FileDescriptor::OpenReadOnly(const char *pathname) noexcept +{ + return Open(pathname, O_RDONLY); +} + +#ifdef __linux__ + +bool +FileDescriptor::OpenReadOnly(FileDescriptor dir, const char *pathname) noexcept +{ + return Open(dir, pathname, O_RDONLY); +} + +#endif // __linux__ + +#ifndef _WIN32 + +bool +FileDescriptor::OpenNonBlocking(const char *pathname) noexcept +{ + return Open(pathname, O_RDWR | O_NONBLOCK); +} + +#endif + +#ifdef __linux__ + +bool +FileDescriptor::CreatePipe(FileDescriptor &r, FileDescriptor &w, + int flags) noexcept +{ + int fds2; + const int result = pipe2(fds, flags); + if (result < 0) + return false; + + r = FileDescriptor(fds0); + w = FileDescriptor(fds1); + return true; +} + +#endif + +bool +FileDescriptor::CreatePipe(FileDescriptor &r, FileDescriptor &w) noexcept +{ +#ifdef __linux__ + return CreatePipe(r, w, O_CLOEXEC); +#else + int fds2; + +#ifdef _WIN32 + const int result = _pipe(fds, 512, _O_BINARY); +#else + const int result = pipe(fds); +#endif + + if (result < 0) + return false; + + r = FileDescriptor(fds0); + w = FileDescriptor(fds1); + return true; +#endif +} + +#ifdef _WIN32 + +void +FileDescriptor::SetBinaryMode() noexcept +{ + _setmode(fd, _O_BINARY); +} + +#else // !_WIN32 + +bool +FileDescriptor::CreatePipeNonBlock(FileDescriptor &r, + FileDescriptor &w) noexcept +{ +#ifdef __linux__ + return CreatePipe(r, w, O_CLOEXEC|O_NONBLOCK); +#else + if (!CreatePipe(r, w)) + return false; + + r.SetNonBlocking(); + w.SetNonBlocking(); + return true; +#endif +} + +void +FileDescriptor::SetNonBlocking() noexcept +{ + assert(IsDefined()); + + int flags = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); +} + +void +FileDescriptor::SetBlocking() noexcept +{ + assert(IsDefined()); + + int flags = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); +} + +void +FileDescriptor::EnableCloseOnExec() noexcept +{ + assert(IsDefined()); + + const int old_flags = fcntl(fd, F_GETFD, 0); + fcntl(fd, F_SETFD, old_flags | FD_CLOEXEC); +} + +void +FileDescriptor::DisableCloseOnExec() noexcept +{ + assert(IsDefined()); + + const int old_flags = fcntl(fd, F_GETFD, 0); + fcntl(fd, F_SETFD, old_flags & ~FD_CLOEXEC); +} + +UniqueFileDescriptor +FileDescriptor::Duplicate() const noexcept +{ + return UniqueFileDescriptor{::dup(Get())}; +} + +bool +FileDescriptor::CheckDuplicate(FileDescriptor new_fd) noexcept +{ + if (*this == new_fd) { + DisableCloseOnExec(); + return true; + } else + return Duplicate(new_fd); +} + +#endif + +#ifdef __linux__ + +bool +FileDescriptor::CreateEventFD(unsigned initval) noexcept +{ + fd = ::eventfd(initval, EFD_NONBLOCK|EFD_CLOEXEC); + return fd >= 0; +} + +bool +FileDescriptor::CreateSignalFD(const sigset_t *mask) noexcept +{ + int new_fd = ::signalfd(fd, mask, SFD_NONBLOCK|SFD_CLOEXEC); + if (new_fd < 0) + return false; + + fd = new_fd; + return true; +} + +#endif + +bool +FileDescriptor::Rewind() noexcept +{ + assert(IsDefined()); + + return lseek(fd, 0, SEEK_SET) == 0; +} + +off_t +FileDescriptor::GetSize() const noexcept +{ + struct stat st; + return ::fstat(fd, &st) >= 0 + ? (long)st.st_size + : -1; +} + +void +FileDescriptor::FullRead(void *_buffer, std::size_t length) +{ + auto buffer = (std::byte *)_buffer; + + while (length > 0) { + ssize_t nbytes = Read(buffer, length); + if (nbytes <= 0) { + if (nbytes < 0) + throw MakeErrno("Failed to read"); + throw std::runtime_error("Unexpected end of file"); + } + + buffer += nbytes; + length -= nbytes; + } +} + +void +FileDescriptor::FullWrite(const void *_buffer, std::size_t length) +{ + auto buffer = (const std::byte *)_buffer; + + while (length > 0) { + ssize_t nbytes = Write(buffer, length); + if (nbytes <= 0) { + if (nbytes < 0) + throw MakeErrno("Failed to write"); + throw std::runtime_error("Failed to write"); + } + + buffer += nbytes; + length -= nbytes; + } +} + +#ifndef _WIN32 + +int +FileDescriptor::Poll(short events, int timeout) const noexcept +{ + assert(IsDefined()); + + struct pollfd pfd; + pfd.fd = fd; + pfd.events = events; + int result = poll(&pfd, 1, timeout); + return result > 0 + ? pfd.revents + : result; +} + +int +FileDescriptor::WaitReadable(int timeout) const noexcept +{ + return Poll(POLLIN, timeout); +} + +int +FileDescriptor::WaitWritable(int timeout) const noexcept +{ + return Poll(POLLOUT, timeout); +} + +bool +FileDescriptor::IsReadyForWriting() const noexcept +{ + return WaitWritable(0) > 0; +} + +#endif
View file
ncmpc-0.47.tar.xz/src/io/FileDescriptor.hxx
Added
@@ -0,0 +1,276 @@ +/* + * Copyright 2012-2020 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <cstddef> +#include <utility> + +#include <unistd.h> +#include <sys/types.h> + +#ifdef __linux__ +#include <csignal> +#endif + +#ifdef _WIN32 +#include <wchar.h> +#endif + +class UniqueFileDescriptor; + +/** + * An OO wrapper for a UNIX file descriptor. + * + * This class is unmanaged and trivial; for a managed version, see + * #UniqueFileDescriptor. + */ +class FileDescriptor { +protected: + int fd; + +public: + FileDescriptor() = default; + explicit constexpr FileDescriptor(int _fd) noexcept:fd(_fd) {} + + constexpr bool operator==(FileDescriptor other) const noexcept { + return fd == other.fd; + } + + constexpr bool operator!=(FileDescriptor other) const noexcept { + return !(*this == other); + } + + constexpr bool IsDefined() const noexcept { + return fd >= 0; + } + +#ifndef _WIN32 + /** + * Ask the kernel whether this is a valid file descriptor. + */ + gnu::pure + bool IsValid() const noexcept; + + /** + * Ask the kernel whether this is a regular file. + */ + gnu::pure + bool IsRegularFile() const noexcept; + + /** + * Ask the kernel whether this is a pipe. + */ + gnu::pure + bool IsPipe() const noexcept; + + /** + * Ask the kernel whether this is a socket descriptor. + */ + gnu::pure + bool IsSocket() const noexcept; +#endif + + /** + * Returns the file descriptor. This may only be called if + * IsDefined() returns true. + */ + constexpr int Get() const noexcept { + return fd; + } + + void Set(int _fd) noexcept { + fd = _fd; + } + + int Steal() noexcept { + return std::exchange(fd, -1); + } + + void SetUndefined() noexcept { + fd = -1; + } + + static constexpr FileDescriptor Undefined() noexcept { + return FileDescriptor(-1); + } + +#ifdef __linux__ + bool Open(FileDescriptor dir, const char *pathname, + int flags, mode_t mode=0666) noexcept; +#endif + + bool Open(const char *pathname, int flags, mode_t mode=0666) noexcept; + +#ifdef _WIN32 + bool Open(const wchar_t *pathname, int flags, mode_t mode=0666) noexcept; +#endif + + bool OpenReadOnly(const char *pathname) noexcept; + +#ifdef __linux__ + bool OpenReadOnly(FileDescriptor dir, + const char *pathname) noexcept; +#endif + +#ifndef _WIN32 + bool OpenNonBlocking(const char *pathname) noexcept; +#endif + +#ifdef __linux__ + static bool CreatePipe(FileDescriptor &r, FileDescriptor &w, + int flags) noexcept; +#endif + + static bool CreatePipe(FileDescriptor &r, FileDescriptor &w) noexcept; + +#ifdef _WIN32 + void EnableCloseOnExec() noexcept {} + void DisableCloseOnExec() noexcept {} + void SetBinaryMode() noexcept; +#else + static bool CreatePipeNonBlock(FileDescriptor &r, + FileDescriptor &w) noexcept; + + void SetBinaryMode() noexcept {} + + /** + * Enable non-blocking mode on this file descriptor. + */ + void SetNonBlocking() noexcept; + + /** + * Enable blocking mode on this file descriptor. + */ + void SetBlocking() noexcept; + + /** + * Auto-close this file descriptor when a new program is + * executed. + */ + void EnableCloseOnExec() noexcept; + + /** + * Do not auto-close this file descriptor when a new program + * is executed. + */ + void DisableCloseOnExec() noexcept; + + /** + * Duplicate this file descriptor. + * + * @return the new file descriptor or UniqueFileDescriptor{} + * on error + */ + UniqueFileDescriptor Duplicate() const noexcept; + + /** + * Duplicate the file descriptor onto the given file descriptor. + */ + bool Duplicate(FileDescriptor new_fd) const noexcept { + return ::dup2(Get(), new_fd.Get()) != -1; + } + + /** + * Similar to Duplicate(), but if destination and source file + * descriptor are equal, clear the close-on-exec flag. Use + * this method to inject file descriptors into a new child + * process, to be used by a newly executed program. + */ + bool CheckDuplicate(FileDescriptor new_fd) noexcept; +#endif + +#ifdef __linux__ + bool CreateEventFD(unsigned initval=0) noexcept; + bool CreateSignalFD(const sigset_t *mask) noexcept; +#endif + + /** + * Close the file descriptor. It should not be called on an + * "undefined" object. After this call, IsDefined() is guaranteed + * to return false, and this object may be reused. + */ + bool Close() noexcept { + return ::close(Steal()) == 0; + } + + /** + * Rewind the pointer to the beginning of the file. + */ + bool Rewind() noexcept; + + off_t Seek(off_t offset) noexcept { + return lseek(Get(), offset, SEEK_SET); + } + + off_t Skip(off_t offset) noexcept { + return lseek(Get(), offset, SEEK_CUR); + } + + gnu::pure + off_t Tell() const noexcept { + return lseek(Get(), 0, SEEK_CUR); + } + + /** + * Returns the size of the file in bytes, or -1 on error. + */ + gnu::pure + off_t GetSize() const noexcept; + + ssize_t Read(void *buffer, std::size_t length) noexcept { + return ::read(fd, buffer, length); + } + + /** + * Read until all of the given buffer has been filled. Throws + * on error. + */ + void FullRead(void *buffer, std::size_t length); + + ssize_t Write(const void *buffer, std::size_t length) noexcept { + return ::write(fd, buffer, length); + } + + /** + * Write until all of the given buffer has been written. + * Throws on error. + */ + void FullWrite(const void *buffer, std::size_t length); + +#ifndef _WIN32 + int Poll(short events, int timeout) const noexcept; + + int WaitReadable(int timeout) const noexcept; + int WaitWritable(int timeout) const noexcept; + + gnu::pure + bool IsReadyForWriting() const noexcept; +#endif +};
View file
ncmpc-0.36.tar.xz/src/io/Path.hxx -> ncmpc-0.47.tar.xz/src/io/Path.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,8 +19,6 @@ #ifndef IO_PATH_HXX #define IO_PATH_HXX -#include "util/Compiler.h" - #include <string> #include <string.h> @@ -34,14 +31,14 @@ static constexpr char SEPARATOR = '/'; #endif -gcc_pure +gnu::pure inline size_t GetLength(const char *s) noexcept { return strlen(s); } -gcc_pure +gnu::pure inline size_t GetLength(const std::string &s) noexcept {
View file
ncmpc-0.47.tar.xz/src/io/UniqueFileDescriptor.hxx
Added
@@ -0,0 +1,102 @@ +/* + * Copyright 2012-2020 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UNIQUE_FILE_DESCRIPTOR_HXX +#define UNIQUE_FILE_DESCRIPTOR_HXX + +#include "FileDescriptor.hxx" // IWYU pragma: export + +#include <cassert> +#include <utility> + +/** + * An OO wrapper for a UNIX file descriptor. + */ +class UniqueFileDescriptor : public FileDescriptor { +public: + UniqueFileDescriptor() noexcept + :FileDescriptor(FileDescriptor::Undefined()) {} + + explicit UniqueFileDescriptor(int _fd) noexcept + :FileDescriptor(_fd) {} + + explicit UniqueFileDescriptor(FileDescriptor _fd) noexcept + :FileDescriptor(_fd) {} + + UniqueFileDescriptor(const UniqueFileDescriptor &) = delete; + + UniqueFileDescriptor(UniqueFileDescriptor &&other) noexcept + :FileDescriptor(other.Steal()) {} + + ~UniqueFileDescriptor() noexcept { + Close(); + } + + UniqueFileDescriptor &operator=(UniqueFileDescriptor &&other) noexcept { + using std::swap; + swap(fd, other.fd); + return *this; + } + + /** + * Release ownership and return the descriptor as an unmanaged + * #FileDescriptor instance. + */ + FileDescriptor Release() noexcept { + return std::exchange(*(FileDescriptor *)this, Undefined()); + } + +protected: + void Set(int _fd) noexcept { + assert(!IsDefined()); + assert(_fd >= 0); + + FileDescriptor::Set(_fd); + } + +public: +#ifndef _WIN32 + static bool CreatePipe(UniqueFileDescriptor &r, UniqueFileDescriptor &w) noexcept { + return FileDescriptor::CreatePipe(r, w); + } + + static bool CreatePipeNonBlock(UniqueFileDescriptor &r, + UniqueFileDescriptor &w) noexcept { + return FileDescriptor::CreatePipeNonBlock(r, w); + } + + static bool CreatePipe(FileDescriptor &r, FileDescriptor &w) noexcept; +#endif + + bool Close() noexcept { + return IsDefined() && FileDescriptor::Close(); + } +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/io/meson.build
Added
@@ -0,0 +1,9 @@ +io = static_library( + 'io', + 'FileDescriptor.cxx', + include_directories: inc, +) + +io_dep = declare_dependency( + link_with: io, +)
View file
ncmpc-0.47.tar.xz/src/io/uring
Added
+(directory)
View file
ncmpc-0.47.tar.xz/src/io/uring/Features.h
Added
@@ -0,0 +1,19 @@ +/* ncmpc (Ncurses MPD Client) + * Copyright 2004-2021 The Music Player Daemon Project + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* no definitions, ncmpc doesn't use io_uring */
View file
ncmpc-0.47.tar.xz/src/io/uring/Features.hxx
Added
@@ -0,0 +1,19 @@ +/* ncmpc (Ncurses MPD Client) + * Copyright 2004-2021 The Music Player Daemon Project + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* no definitions, ncmpc doesn't use io_uring */
View file
ncmpc-0.36.tar.xz/src/lirc.cxx -> ncmpc-0.47.tar.xz/src/lirc.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -25,11 +24,8 @@ #include <lirc/lirc_client.h> void -LircInput::OnReadable(const boost::system::error_code &error) +LircInput::OnSocketReady(unsigned) noexcept { - if (error) - return; - char *code, *txt; begin_input_event(); @@ -37,17 +33,16 @@ if (lirc_nextcode(&code) == 0) { while (lirc_code2char(lc, code, &txt) == 0 && txt != nullptr) { const auto cmd = get_key_command_from_name(txt); - if (!do_input_event(get_io_context(), cmd)) + if (!do_input_event(GetEventLoop(), cmd)) return; } } end_input_event(); - AsyncWait(); } -LircInput::LircInput(boost::asio::io_service &io_service) - :d(io_service) +LircInput::LircInput(EventLoop &_event_loop) noexcept + :event(_event_loop, BIND_THIS_METHOD(OnSocketReady)) { int lirc_socket = 0; @@ -59,14 +54,14 @@ return; } - d.assign(lirc_socket); - AsyncWait(); + event.Open(SocketDescriptor(lirc_socket)); + event.ScheduleRead(); } LircInput::~LircInput() { if (lc) lirc_freeconfig(lc); - if (d.is_open()) + if (event.IsDefined()) lirc_deinit(); }
View file
ncmpc-0.36.tar.xz/src/lirc.hxx -> ncmpc-0.47.tar.xz/src/lirc.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,32 +19,23 @@ #ifndef LIRC_H #define LIRC_H -#include "AsioServiceFwd.hxx" -#include "AsioGetIoService.hxx" - -#include <boost/asio/posix/stream_descriptor.hpp> - -class LircInput { - boost::asio::posix::stream_descriptor d; +#include "event/SocketEvent.hxx" +class LircInput final { struct lirc_config *lc = nullptr; + SocketEvent event; + public: - explicit LircInput(boost::asio::io_service &io_service); + explicit LircInput(EventLoop &event_loop) noexcept; ~LircInput(); - auto &get_io_context() noexcept { - return ::get_io_service(d); + auto &GetEventLoop() const noexcept { + return event.GetEventLoop(); } private: - void AsyncWait() { - d.async_read_some(boost::asio::null_buffers(), - std::bind(&LircInput::OnReadable, this, - std::placeholders::_1)); - } - - void OnReadable(const boost::system::error_code &error); + void OnSocketReady(unsigned flags) noexcept; }; #endif
View file
ncmpc-0.36.tar.xz/src/mpdclient.cxx -> ncmpc-0.47.tar.xz/src/mpdclient.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -28,32 +27,17 @@ #include <assert.h> void -mpdclient::OnEnterIdleTimer(const boost::system::error_code &error) noexcept +mpdclient::OnEnterIdleTimer() noexcept { - if (error) - return; - assert(source != nullptr); assert(!idle); idle = source->Enter(); } -void -mpdclient::ScheduleEnterIdle() noexcept -{ - assert(source != nullptr); - - /* automatically re-enter MPD "idle" mode */ - boost::system::error_code error; - enter_idle_timer.expires_from_now(std::chrono::seconds(0), error); - enter_idle_timer.async_wait(std::bind(&mpdclient::OnEnterIdleTimer, - this, std::placeholders::_1)); -} - static void mpdclient_invoke_error_callback(enum mpd_error error, - const char *message) + const char *message) noexcept { if (error == MPD_ERROR_SERVER) /* server errors are UTF-8, the others are locale */ @@ -93,7 +77,7 @@ void mpdclient::OnIdleError(enum mpd_error error, - gcc_unused enum mpd_server_error server_error, + enum mpd_server_error, const char *message) noexcept { assert(IsConnected()); @@ -110,16 +94,14 @@ /****************************************************************************/ bool -mpdclient::HandleError() +mpdclient::HandleError() noexcept { enum mpd_error error = mpd_connection_get_error(connection); - assert(error != MPD_ERROR_SUCCESS); if (error == MPD_ERROR_SERVER && - mpd_connection_get_server_error(connection) == MPD_SERVER_ERROR_PERMISSION && - mpdclient_auth_callback(this)) - return true; + mpd_connection_get_server_error(connection) == MPD_SERVER_ERROR_PERMISSION) + return mpdclient_auth_callback(this); mpdclient_invoke_error_callback(error, mpd_connection_get_error_message(connection)); @@ -132,17 +114,32 @@ return false; } +void +mpdclient::HandleAuthError() noexcept +{ + enum mpd_error error = mpd_connection_get_error(connection); + assert(error != MPD_ERROR_SUCCESS); + + mpdclient_invoke_error_callback(error, + mpd_connection_get_error_message(connection)); + + if (!mpd_connection_clear_error(connection)) { + Disconnect(); + mpdclient_lost_callback(); + } +} + #ifdef ENABLE_ASYNC_CONNECT #ifndef _WIN32 static bool -is_local_socket(const char *host) +is_local_socket(const char *host) noexcept { return *host == '/' || *host == '@'; } static bool -settings_is_local_socket(const struct mpd_settings *settings) +settings_is_local_socket(const struct mpd_settings *settings) noexcept { const char *host = mpd_settings_get_host(settings); return host != nullptr && is_local_socket(host); @@ -151,14 +148,12 @@ #endif #endif -mpdclient::mpdclient(boost::asio::io_service &io_service, +mpdclient::mpdclient(EventLoop &_event_loop, const char *_host, unsigned _port, unsigned _timeout_ms, const char *_password) - :timeout_ms(_timeout_ms), password(_password), -#if BOOST_VERSION >= 107000 - io_context(io_service), -#endif - enter_idle_timer(io_service) + :event_loop(_event_loop), + timeout_ms(_timeout_ms), password(_password), + enter_idle_timer(event_loop, BIND_THIS_METHOD(OnEnterIdleTimer)) { #ifdef ENABLE_ASYNC_CONNECT settings = mpd_settings_new(_host, _port, _timeout_ms, @@ -180,7 +175,7 @@ } static std::string -settings_name(const struct mpd_settings *settings) +settings_name(const struct mpd_settings *settings) noexcept { assert(settings != nullptr); @@ -201,7 +196,7 @@ } std::string -mpdclient::GetSettingsName() const +mpdclient::GetSettingsName() const noexcept { #ifdef ENABLE_ASYNC_CONNECT return settings_name(settings); @@ -213,12 +208,10 @@ auto name = settings_name(settings); mpd_settings_free(settings); - return std::move(name); + return name; #endif } -#ifdef HAVE_TAG_WHITELIST - void mpdclient::WhitelistTags(TagMask mask) noexcept { @@ -230,8 +223,6 @@ tag_whitelist |= mask; } -#endif - void mpdclient::ClearStatus() noexcept { @@ -248,7 +239,7 @@ } void -mpdclient::Disconnect() +mpdclient::Disconnect() noexcept { #ifdef ENABLE_ASYNC_CONNECT if (async_connect != nullptr) { @@ -279,11 +270,61 @@ events |= MPD_IDLE_ALL; } -#ifdef HAVE_TAG_WHITELIST +/** + * Receive a "tagtypes" response and convert it to a #TagMask. + */ +static TagMask +ReceiveTagList(struct mpd_connection *c) noexcept +{ + auto result = TagMask::None(); + + while (auto *pair = mpd_recv_tag_type_pair(c)) { + const auto type = mpd_tag_name_parse(pair->value); + if (type != MPD_TAG_UNKNOWN) + result |= type; + + mpd_return_pair(c, pair); + } + + return result; +} + +/** + * Reset the tag mask and return all tag types known to MPD as a + * #TagMask. (Without the reset, we would only see the tags currently + * enabled for this client.) + * + * Returns an empty mask on error. + */ +static TagMask +ResetAndObtainTagList(struct mpd_connection *c) noexcept +{ + if (!mpd_command_list_begin(c, false) || +#if LIBMPDCLIENT_CHECK_VERSION(2,19,0) + !mpd_send_all_tag_types(c) || +#endif + !mpd_send_list_tag_types(c) || + !mpd_command_list_end(c)) + return TagMask::None(); + + auto mask = ReceiveTagList(c); + if (!mpd_response_finish(c)) + return TagMask::None(); + + return mask; +} static bool SendTagWhitelist(struct mpd_connection *c, const TagMask whitelist) noexcept { + const auto available_tags = ResetAndObtainTagList(c); + if (!available_tags.TestAny()) + return false; + + /* enable only the tags supported by MPD (or else the + "tagtypes" request will fail */ + const auto mask = whitelist & available_tags; + if (!mpd_command_list_begin(c, false) || !mpd_send_clear_tag_types(c)) return false; @@ -291,11 +332,11 @@ /* convert the "tag_bits" mask to an array of enum mpd_tag_type for mpd_send_enable_tag_types() */ - enum mpd_tag_type types64; + enum mpd_tag_type typesMPD_TAG_COUNT; unsigned n = 0; for (unsigned i = 0; i < MPD_TAG_COUNT; ++i) - if (whitelist.Test((enum mpd_tag_type)i)) + if (mask.Test((enum mpd_tag_type)i)) typesn++ = (enum mpd_tag_type)i; return (n == 0 || mpd_send_enable_tag_types(c, types, n)) && @@ -303,8 +344,6 @@ mpd_response_finish(c); } -#endif - bool mpdclient::OnConnected(struct mpd_connection *_connection) noexcept { @@ -331,17 +370,18 @@ return false; } -#ifdef HAVE_TAG_WHITELIST if (enable_tag_whitelist && !SendTagWhitelist(connection, tag_whitelist)) { InvokeErrorCallback(); - Disconnect(); - mpdclient_failed_callback(); - return false; + + if (!mpd_connection_clear_error(connection)) { + Disconnect(); + mpdclient_failed_callback(); + return false; + } } -#endif - source = new MpdIdleSource(get_io_service(), *connection, *this); + source = new MpdIdleSource(GetEventLoop(), *connection, *this); ScheduleEnterIdle(); ++connection_id; @@ -375,7 +415,7 @@ } void -mpdclient::OnAsyncMpdConnectError(const char *message) noexcept +mpdclient::OnAsyncMpdConnectError(std::exception_ptr e) noexcept { assert(async_connect != nullptr); async_connect = nullptr; @@ -388,14 +428,14 @@ } #endif - mpdclient_error_callback(message); + mpdclient_error_callback(std::move(e)); mpdclient_failed_callback(); } void mpdclient::StartConnect(const struct mpd_settings &s) noexcept { - aconnect_start(get_io_service(), &async_connect, + aconnect_start(GetEventLoop(), &async_connect, mpd_settings_get_host(&s), mpd_settings_get_port(&s), *this); @@ -404,7 +444,7 @@ #endif void -mpdclient::Connect() +mpdclient::Connect() noexcept { /* close any open connection */ Disconnect(); @@ -426,7 +466,7 @@ } bool -mpdclient::Update() +mpdclient::Update() noexcept { auto *c = GetConnection(); @@ -467,7 +507,7 @@ } struct mpd_connection * -mpdclient::GetConnection() +mpdclient::GetConnection() noexcept { if (source != nullptr && idle) { idle = false; @@ -501,7 +541,7 @@ /****************************************************************************/ bool -mpdclient_cmd_crop(struct mpdclient *c) +mpdclient_cmd_crop(struct mpdclient *c) noexcept { if (!c->playing_or_paused) return false; @@ -568,12 +608,9 @@ bool mpdclient::RunVolume(unsigned value) noexcept { - struct mpd_connection *c = GetConnection(); - if (c == nullptr) - return false; - - mpd_send_set_volume(c, value); - return FinishCommand(); + return WithConnection(value(struct mpd_connection &c){ + return mpd_run_set_volume(&c, value); + }); } bool @@ -595,14 +632,11 @@ } bool -mpdclient_cmd_add_path(struct mpdclient *c, const char *path_utf8) +mpdclient_cmd_add_path(struct mpdclient *c, const char *path_utf8) noexcept { - struct mpd_connection *connection = c->GetConnection(); - if (connection == nullptr) - return false; - - return mpd_send_add(connection, path_utf8)? - c->FinishCommand() : false; + return c->WithConnection(path_utf8(struct mpd_connection &conn){ + return mpd_run_add(&conn, path_utf8); + }); } bool @@ -804,44 +838,28 @@ /* The client-to-client protocol (MPD 0.17.0) */ bool -mpdclient_cmd_subscribe(struct mpdclient *c, const char *channel) +mpdclient_cmd_subscribe(struct mpdclient *c, const char *channel) noexcept { - struct mpd_connection *connection = c->GetConnection(); - - if (connection == nullptr) - return false; - - if (!mpd_send_subscribe(connection, channel)) - return c->HandleError(); - - return c->FinishCommand(); + return c->WithConnection(channel(struct mpd_connection &conn){ + return mpd_run_subscribe(&conn, channel); + }); } bool -mpdclient_cmd_unsubscribe(struct mpdclient *c, const char *channel) +mpdclient_cmd_unsubscribe(struct mpdclient *c, const char *channel) noexcept { - struct mpd_connection *connection = c->GetConnection(); - if (connection == nullptr) - return false; - - if (!mpd_send_unsubscribe(connection, channel)) - return c->HandleError(); - - return c->FinishCommand(); + return c->WithConnection(channel(struct mpd_connection &conn){ + return mpd_run_unsubscribe(&conn, channel); + }); } bool mpdclient_cmd_send_message(struct mpdclient *c, const char *channel, - const char *text) + const char *text) noexcept { - struct mpd_connection *connection = c->GetConnection(); - if (connection == nullptr) - return false; - - if (!mpd_send_send_message(connection, channel, text)) - return c->HandleError(); - - return c->FinishCommand(); + return c->WithConnection(channel, text(struct mpd_connection &conn){ + return mpd_run_send_message(&conn, channel, text); + }); } /****************************************************************************/ @@ -850,7 +868,7 @@ /* update playlist */ bool -mpdclient::UpdateQueue() +mpdclient::UpdateQueue() noexcept { auto *c = GetConnection(); if (c == nullptr) @@ -876,7 +894,7 @@ /* update playlist (plchanges) */ bool -mpdclient::UpdateQueueChanges() +mpdclient::UpdateQueueChanges() noexcept { auto *c = GetConnection(); if (c == nullptr)
View file
ncmpc-0.36.tar.xz/src/mpdclient.hxx -> ncmpc-0.47.tar.xz/src/mpdclient.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -23,8 +22,8 @@ #include "config.h" #include "Queue.hxx" #include "gidle.hxx" -#include "util/Compiler.h" -#include "AsioServiceFwd.hxx" +#include "TagMask.hxx" +#include "event/FineTimerEvent.hxx" #ifdef ENABLE_ASYNC_CONNECT #include "aconnect.hxx" @@ -32,13 +31,6 @@ #include <mpd/client.h> // IWYU pragma: export -#if LIBMPDCLIENT_CHECK_VERSION(2,12,0) -#define HAVE_TAG_WHITELIST -#include "TagMask.hxx" -#endif - -#include <boost/asio/steady_timer.hpp> - #include <string> struct AsyncMpdConnect; @@ -49,6 +41,8 @@ , AsyncMpdConnectHandler #endif { + EventLoop &event_loop; + #ifdef ENABLE_ASYNC_CONNECT /** * These settings are used to connect to MPD asynchronously. @@ -92,15 +86,11 @@ struct mpd_status *status = nullptr; const struct mpd_song *current_song = nullptr; -#if BOOST_VERSION >= 107000 - boost::asio::io_context &io_context; -#endif - /** * A timer which re-enters MPD idle mode before the next main * loop iteration. */ - boost::asio::steady_timer enter_idle_timer; + FineTimerEvent enter_idle_timer; /** * This attribute is incremented whenever the connection changes @@ -117,10 +107,8 @@ enum mpd_state state = MPD_STATE_UNKNOWN; -#ifdef HAVE_TAG_WHITELIST bool enable_tag_whitelist = false; TagMask tag_whitelist; -#endif #if defined(ENABLE_ASYNC_CONNECT) && !defined(_WIN32) bool connecting2; @@ -142,11 +130,11 @@ */ bool playing_or_paused = false; - mpdclient(boost::asio::io_service &io_service, + mpdclient(EventLoop &_event_loop, const char *host, unsigned port, unsigned _timeout_ms, const char *_password); - ~mpdclient() { + ~mpdclient() noexcept { Disconnect(); #ifdef ENABLE_ASYNC_CONNECT @@ -159,12 +147,8 @@ #endif } - auto &get_io_service() noexcept { -#if BOOST_VERSION >= 107000 - return io_context; -#else - return enter_idle_timer.get_io_service(); -#endif + auto &GetEventLoop() const noexcept { + return event_loop; } #ifdef ENABLE_ASYNC_CONNECT @@ -187,13 +171,11 @@ * @return an allocated string that needs to be freed (with g_free()) * by the caller */ - std::string GetSettingsName() const; + std::string GetSettingsName() const noexcept; -#ifdef HAVE_TAG_WHITELIST void WhitelistTags(TagMask mask) noexcept; -#endif - bool IsConnected() const { + bool IsConnected() const noexcept { return connection != nullptr; } @@ -201,8 +183,8 @@ * Is this object "dead"? i.e. not connected and not * currently doing anything to connect. */ - gcc_pure - bool IsDead() const { + gnu::pure + bool IsDead() const noexcept { return connection == nullptr #ifdef ENABLE_ASYNC_CONNECT && async_connect == nullptr @@ -210,14 +192,14 @@ ; } - gcc_pure + gnu::pure int GetCurrentSongId() const noexcept { return status != nullptr ? mpd_status_get_song_id(status) : -1; } - gcc_pure + gnu::pure int GetCurrentSongPos() const noexcept { return status != nullptr ? mpd_status_get_song_pos(status) @@ -228,12 +210,12 @@ * Returns the song that is "current". This can be valid even * if MPD is not playing. */ - gcc_pure - const struct mpd_song *GetCurrentSong() const { + gnu::pure + const struct mpd_song *GetCurrentSong() const noexcept { return current_song; } - gcc_pure + gnu::pure int GetPlayingSongId() const noexcept { return playing_or_paused ? GetCurrentSongId() @@ -244,31 +226,64 @@ * Returns the song that is currently being played (or * paused). */ - gcc_pure - const struct mpd_song *GetPlayingSong() const { + gnu::pure + const struct mpd_song *GetPlayingSong() const noexcept { return playing_or_paused ? GetCurrentSong() : nullptr; } - void Connect(); + void Connect() noexcept; + + void Disconnect() noexcept; - void Disconnect(); + /** + * @return true if the cause has been fixed (e.g. by sending a + * password) and the caller may retry the operation + */ + bool HandleError() noexcept; - bool HandleError(); + /** + * Like HandleError(), but called from inside the auth + * callback, and avoids recursion into the auth callback. + */ + void HandleAuthError() noexcept; - struct mpd_connection *GetConnection(); + struct mpd_connection *GetConnection() noexcept; - bool FinishCommand() { - return mpd_response_finish(connection) || HandleError(); + bool FinishCommand() noexcept { + if (mpd_response_finish(connection)) + return true; + + HandleError(); + return false; } - bool Update(); + bool Update() noexcept; bool OnConnected(struct mpd_connection *_connection) noexcept; const struct mpd_status *ReceiveStatus() noexcept; + template<typename F> + bool WithConnection(F &&f) noexcept { + while (true) { + auto *c = GetConnection(); + if (c == nullptr) + return false; + + if (f(*c)) + return true; + + enum mpd_error error = mpd_connection_get_error(c); + if (error == MPD_ERROR_SUCCESS) + return false; + + if (!HandleError()) + return false; + } + } + bool RunVolume(unsigned new_volume) noexcept; bool RunVolumeUp() noexcept; bool RunVolumeDown() noexcept; @@ -286,21 +301,25 @@ void InvokeErrorCallback() noexcept; - bool UpdateQueue(); - bool UpdateQueueChanges(); + bool UpdateQueue() noexcept; + bool UpdateQueueChanges() noexcept; void ClearStatus() noexcept; - void ScheduleEnterIdle() noexcept; + void ScheduleEnterIdle() noexcept { + enter_idle_timer.Schedule(std::chrono::milliseconds(10)); + } + void CancelEnterIdle() noexcept { - enter_idle_timer.cancel(); + enter_idle_timer.Cancel(); } - void OnEnterIdleTimer(const boost::system::error_code &error) noexcept; + + void OnEnterIdleTimer() noexcept; #ifdef ENABLE_ASYNC_CONNECT /* virtual methods from AsyncMpdConnectHandler */ void OnAsyncMpdConnect(struct mpd_connection *c) noexcept override; - void OnAsyncMpdConnectError(const char *message) noexcept override; + void OnAsyncMpdConnectError(std::exception_ptr e) noexcept override; #endif /* virtual methods from MpdIdleHandler */ @@ -329,22 +348,22 @@ /*** MPD Commands **********************************************************/ bool -mpdclient_cmd_crop(struct mpdclient *c); +mpdclient_cmd_crop(struct mpdclient *c) noexcept; bool -mpdclient_cmd_clear(struct mpdclient *c); +mpdclient_cmd_clear(struct mpdclient *c) noexcept; bool -mpdclient_cmd_add_path(struct mpdclient *c, const char *path); +mpdclient_cmd_add_path(struct mpdclient *c, const char *path) noexcept; bool -mpdclient_cmd_subscribe(struct mpdclient *c, const char *channel); +mpdclient_cmd_subscribe(struct mpdclient *c, const char *channel) noexcept; bool -mpdclient_cmd_unsubscribe(struct mpdclient *c, const char *channel); +mpdclient_cmd_unsubscribe(struct mpdclient *c, const char *channel) noexcept; bool mpdclient_cmd_send_message(struct mpdclient *c, const char *channel, - const char *text); + const char *text) noexcept; #endif
View file
ncmpc-0.36.tar.xz/src/ncmpc.hxx -> ncmpc-0.47.tar.xz/src/ncmpc.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,29 +19,31 @@ #ifndef NCMPC_H #define NCMPC_H -#include "AsioServiceFwd.hxx" - #ifdef HAVE_GETMOUSE #include <curses.h> #endif enum class Command : unsigned; struct Point; +class EventLoop; class ScreenManager; extern ScreenManager *screen; -void begin_input_event(); -void end_input_event(); +void +begin_input_event() noexcept; + +void +end_input_event() noexcept; /** * @return false if the application shall quit */ bool -do_input_event(boost::asio::io_service &io_service, Command cmd); +do_input_event(EventLoop &event_loop, Command cmd) noexcept; #ifdef HAVE_GETMOUSE void -do_mouse_event(Point p, mmask_t bstate); +do_mouse_event(Point p, mmask_t bstate) noexcept; #endif #endif /* NCMPC_H */
View file
ncmpc-0.36.tar.xz/src/ncu.cxx -> ncmpc-0.47.tar.xz/src/ncu.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -47,6 +46,9 @@ ApplyStyles(); #endif + /* Ctrl-C generates keycode 0x03 instead of SIGINT */ + raw(); + /* tell curses not to do NL->CR/NL on output */ nonl();
View file
ncmpc-0.36.tar.xz/src/ncu.hxx -> ncmpc-0.47.tar.xz/src/ncu.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.47.tar.xz/src/net/AddressInfo.cxx
Added
@@ -0,0 +1,82 @@ +/* + * Copyright 2016-2021 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "AddressInfo.hxx" +#include "Features.hxx" + +#include <array> +#include <cassert> + +static constexpr auto address_family_ranking = std::array { +#ifdef HAVE_UN + AF_LOCAL, +#endif + AF_INET6, +}; + +static constexpr bool +IsAddressFamilyBetter(int previous, int next) noexcept +{ + for (auto i : address_family_ranking) { + if (next == i) + return previous != i; + if (previous == i) + return false; + } + + return false; +} + +static constexpr bool +IsBetter(const AddressInfo &previous, const AddressInfo &next) noexcept +{ + return IsAddressFamilyBetter(previous.GetFamily(), + next.GetFamily()); +} + +static constexpr bool +IsBetter(const AddressInfo *previous, const AddressInfo &next) noexcept +{ + return previous == nullptr || IsBetter(*previous, next); +} + +const AddressInfo & +AddressInfoList::GetBest() const noexcept +{ + assert(!empty()); + + const AddressInfo *best = nullptr; + + for (const auto &i : *this) + if (IsBetter(best, i)) + best = &i; + + assert(best != nullptr); + return *best; +}
View file
ncmpc-0.47.tar.xz/src/net/AddressInfo.hxx
Added
@@ -0,0 +1,160 @@ +/* + * Copyright 2016-2021 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NET_ADDRESS_INFO_HXX +#define NET_ADDRESS_INFO_HXX + +#include "SocketAddress.hxx" + +#include <iterator> +#include <utility> + +#ifdef _WIN32 +#include <ws2tcpip.h> // IWYU pragma: export +#else +#include <netdb.h> // IWYU pragma: export +#endif + +constexpr struct addrinfo +MakeAddrInfo(int flags, int family, int socktype, int protocol=0) noexcept +{ + struct addrinfo ai{}; + ai.ai_flags = flags; + ai.ai_family = family; + ai.ai_socktype = socktype; + ai.ai_protocol = protocol; + return ai; +} + +class AddressInfo : addrinfo { + /* this class cannot be instantiated, it can only be cast from + a struct addrinfo pointer */ + AddressInfo() = delete; + ~AddressInfo() = delete; + +public: + constexpr int GetFamily() const noexcept { + return ai_family; + } + + constexpr int GetType() const noexcept { + return ai_socktype; + } + + constexpr int GetProtocol() const noexcept { + return ai_protocol; + } + + constexpr operator SocketAddress() const noexcept { + return {ai_addr, (SocketAddress::size_type)ai_addrlen}; + } +}; + +class AddressInfoList { + struct addrinfo *value = nullptr; + +public: + AddressInfoList() = default; + explicit AddressInfoList(struct addrinfo *_value) noexcept + :value(_value) {} + + AddressInfoList(AddressInfoList &&src) noexcept + :value(std::exchange(src.value, nullptr)) {} + + ~AddressInfoList() noexcept { + freeaddrinfo(value); + } + + AddressInfoList &operator=(AddressInfoList &&src) noexcept { + std::swap(value, src.value); + return *this; + } + + bool empty() const noexcept { + return value == nullptr; + } + + const AddressInfo &front() const noexcept { + return *(const AddressInfo *)value; + } + + /** + * Pick the best address from the list, e.g. prefer IPv6 over + * IPv4 (if both are available). We do this because binding + * to an IPv6 wildcard address also allows accepting IPv4 + * connections. + */ + gnu::pure + const AddressInfo &GetBest() const noexcept; + + class const_iterator { + struct addrinfo *cursor; + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = AddressInfo; + using difference_type = std::ptrdiff_t; + using pointer = const value_type *; + using reference = const value_type &; + + explicit constexpr const_iterator(struct addrinfo *_cursor) noexcept + :cursor(_cursor) {} + + constexpr bool operator==(const_iterator other) const noexcept { + return cursor == other.cursor; + } + + constexpr bool operator!=(const_iterator other) const noexcept { + return cursor != other.cursor; + } + + const_iterator &operator++() noexcept { + cursor = cursor->ai_next; + return *this; + } + + constexpr const AddressInfo &operator*() const noexcept { + return *(const AddressInfo *)cursor; + } + + constexpr const AddressInfo *operator->() const noexcept { + return (const AddressInfo *)cursor; + } + }; + + const_iterator begin() const noexcept { + return const_iterator(value); + } + + const_iterator end() const noexcept { + return const_iterator(nullptr); + } +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/net/AllocatedSocketAddress.cxx
Added
@@ -0,0 +1,120 @@ +/* + * Copyright 2012-2021 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "AllocatedSocketAddress.hxx" +#include "IPv4Address.hxx" +#include "IPv6Address.hxx" + +#include <string.h> + +#ifdef HAVE_UN +#include <sys/un.h> +#endif + +AllocatedSocketAddress & +AllocatedSocketAddress::operator=(SocketAddress src) noexcept +{ + if (src.IsNull()) { + Clear(); + } else { + SetSize(src.GetSize()); + memcpy(address, src.GetAddress(), size); + } + + return *this; +} + +void +AllocatedSocketAddress::SetSize(size_type new_size) noexcept +{ + if (size == new_size) + return; + + free(address); + size = new_size; + address = (struct sockaddr *)malloc(size); +} + +#ifdef HAVE_UN + +std::string_view +AllocatedSocketAddress::GetLocalRaw() const noexcept +{ + return SocketAddress(*this).GetLocalRaw(); +} + +void +AllocatedSocketAddress::SetLocal(const char *path) noexcept +{ + const bool is_abstract = *path == '@'; + + /* sun_path must be null-terminated unless it's an abstract + socket */ + const size_t path_length = strlen(path) + !is_abstract; + + struct sockaddr_un *sun; + SetSize(sizeof(*sun) - sizeof(sun->sun_path) + path_length); + sun = (struct sockaddr_un *)address; + sun->sun_family = AF_LOCAL; + memcpy(sun->sun_path, path, path_length); + + if (is_abstract) + sun->sun_path0 = 0; +} + +#endif + +#ifdef HAVE_TCP + +bool +AllocatedSocketAddress::SetPort(unsigned port) noexcept +{ + if (IsNull()) + return false; + + switch (GetFamily()) { + case AF_INET: + { + auto &a = *(IPv4Address *)(void *)address; + a.SetPort(port); + return true; + } + + case AF_INET6: + { + auto &a = *(IPv6Address *)(void *)address; + a.SetPort(port); + return true; + } + } + + return false; +} + +#endif
View file
ncmpc-0.47.tar.xz/src/net/AllocatedSocketAddress.hxx
Added
@@ -0,0 +1,208 @@ +/* + * Copyright 2012-2021 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ALLOCATED_SOCKET_ADDRESS_HXX +#define ALLOCATED_SOCKET_ADDRESS_HXX + +#include "SocketAddress.hxx" // IWYU pragma: export +#include "Features.hxx" + +#include <utility> + +#ifdef HAVE_UN +#include <string_view> +#endif + +#include <stdlib.h> + +struct sockaddr; + +class AllocatedSocketAddress { +public: + typedef SocketAddress::size_type size_type; + +private: + struct sockaddr *address = nullptr; + size_type size = 0; + + AllocatedSocketAddress(struct sockaddr *_address, + size_type _size) + :address(_address), size(_size) {} + +public: + AllocatedSocketAddress() = default; + + explicit AllocatedSocketAddress(SocketAddress src) noexcept { + *this = src; + } + + AllocatedSocketAddress(const AllocatedSocketAddress &src) noexcept + :AllocatedSocketAddress((SocketAddress)src) {} + + AllocatedSocketAddress(AllocatedSocketAddress &&src) noexcept + :address(src.address), size(src.size) { + src.address = nullptr; + src.size = 0; + } + + ~AllocatedSocketAddress() { + free(address); + } + + AllocatedSocketAddress &operator=(SocketAddress src) noexcept; + + AllocatedSocketAddress &operator=(const AllocatedSocketAddress &src) noexcept { + return *this = (SocketAddress)src; + } + + AllocatedSocketAddress &operator=(AllocatedSocketAddress &&src) noexcept { + using std::swap; + swap(address, src.address); + swap(size, src.size); + return *this; + } + + template<typename T> + gnu::pure + bool operator==(T &&other) const noexcept { + return (SocketAddress)*this == std::forward<T>(other); + } + + template<typename T> + gnu::pure + bool operator!=(T &&other) const noexcept { + return !(*this == std::forward<T>(other)); + } + + gnu::const + static AllocatedSocketAddress Null() noexcept { + return AllocatedSocketAddress(nullptr, 0); + } + + bool IsNull() const noexcept { + return address == nullptr; + } + + size_type GetSize() const noexcept { + return size; + } + + const struct sockaddr *GetAddress() const noexcept { + return address; + } + + operator SocketAddress() const noexcept { + return SocketAddress(address, size); + } + + operator const struct sockaddr *() const noexcept { + return address; + } + + int GetFamily() const noexcept { + return address->sa_family; + } + + /** + * Does the object have a well-defined address? Check !IsNull() + * before calling this method. + */ + bool IsDefined() const noexcept { + return GetFamily() != AF_UNSPEC; + } + + void Clear() noexcept { + free(address); + address = nullptr; + size = 0; + } + +#ifdef HAVE_UN + /** + * @see SocketAddress::GetLocalRaw() + */ + gnu::pure + std::string_view GetLocalRaw() const noexcept; + + /** + * @see SocketAddress::GetLocalPath() + */ + gnu::pure + const char *GetLocalPath() const noexcept { + return ((SocketAddress)*this).GetLocalPath(); + } + + /** + * Make this a "local" address (UNIX domain socket). If the path + * begins with a '@', then the rest specifies an "abstract" local + * address. + */ + void SetLocal(const char *path) noexcept; +#endif + +#ifdef HAVE_TCP + bool IsV6Any() const noexcept { + return ((SocketAddress)*this).IsV6Any(); + } + + bool IsV4Mapped() const noexcept { + return ((SocketAddress)*this).IsV4Mapped(); + } + + /** + * Extract the port number. Returns 0 if not applicable. + */ + gnu::pure + unsigned GetPort() const noexcept { + return ((SocketAddress)*this).GetPort(); + } + + /** + * @return true on success, false if this address cannot have + * a port number + */ + bool SetPort(unsigned port) noexcept; + + static AllocatedSocketAddress WithPort(SocketAddress src, + unsigned port) noexcept { + AllocatedSocketAddress result(src); + result.SetPort(port); + return result; + } + + AllocatedSocketAddress WithPort(unsigned port) const noexcept { + return WithPort(*this, port); + } +#endif + +private: + void SetSize(size_type new_size) noexcept; +}; + +#endif
View file
ncmpc-0.36.tar.xz/src/net/AsyncResolveConnect.cxx -> ncmpc-0.47.tar.xz/src/net/AsyncResolveConnect.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - (c) 2004-2019 The Music Player Daemon Project - Project homepage: http://musicpd.org + Copyright 2004-2021 The Music Player Daemon Project Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -27,66 +26,29 @@ */ #include "AsyncResolveConnect.hxx" -#include "AsyncConnect.hxx" -#include "AsyncHandler.hxx" +#include "AllocatedSocketAddress.hxx" +#include "AddressInfo.hxx" +#include "Resolver.hxx" -#ifndef _WIN32 -#include <boost/asio/local/stream_protocol.hpp> -#endif - -#include <string> - -void -AsyncResolveConnect::OnResolved(const boost::system::error_code &error, - boost::asio::ip::tcp::resolver::iterator i) noexcept -{ - if (error) { - if (error == boost::asio::error::operation_aborted) - /* this object has already been deleted; bail - out quickly without touching anything */ - return; - - handler.OnConnectError(error.message().c_str()); - return; - } - - connect.Start(*i); -} +#include <exception> void -AsyncResolveConnect::Start(boost::asio::io_service &io_service, - const char *host, unsigned port) noexcept +AsyncResolveConnect::Start(const char *host, unsigned port) noexcept { #ifndef _WIN32 if (host0 == '/' || host0 == '@') { - std::string s(host); - if (host0 == '@') - /* abstract socket */ - s.front() = 0; - - boost::asio::local::stream_protocol::endpoint ep(std::move(s)); - boost::asio::local::stream_protocol::socket socket(io_service); + AllocatedSocketAddress address; + address.SetLocal(host); - boost::system::error_code error; - socket.connect(ep, error); - if (error) { - handler.OnConnectError(error.message().c_str()); - return; - } - - handler.OnConnect(std::move(socket)); + connect.Connect(address, std::chrono::seconds(30)); return; } -#else - (void)io_service; #endif /* _WIN32 */ - char service20; - snprintf(service, sizeof(service), "%u", port); - - resolver.async_resolve({host, service}, - std::bind(&AsyncResolveConnect::OnResolved, - this, - std::placeholders::_1, - std::placeholders::_2)); + try { + connect.Connect(Resolve(host, port, AI_ADDRCONFIG, SOCK_STREAM).GetBest(), + std::chrono::seconds(30)); + } catch (...) { + handler.OnSocketConnectError(std::current_exception()); + } }
View file
ncmpc-0.36.tar.xz/src/net/AsyncResolveConnect.hxx -> ncmpc-0.47.tar.xz/src/net/AsyncResolveConnect.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - (c) 2004-2019 The Music Player Daemon Project - Project homepage: http://musicpd.org + Copyright 2004-2021 The Music Player Daemon Project Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -29,30 +28,23 @@ #ifndef NET_ASYNC_RESOLVE_CONNECT_HXX #define NET_ASYNC_RESOLVE_CONNECT_HXX -#include "AsyncConnect.hxx" +#include "event/net/ConnectSocket.hxx" class AsyncResolveConnect { - AsyncConnectHandler &handler; + ConnectSocketHandler &handler; - boost::asio::ip::tcp::resolver resolver; - - AsyncConnect connect; + ConnectSocket connect; public: - AsyncResolveConnect(boost::asio::io_service &io_service, - AsyncConnectHandler &_handler) noexcept - :handler(_handler), resolver(io_service), - connect(io_service, _handler) {} + AsyncResolveConnect(EventLoop &event_loop, + ConnectSocketHandler &_handler) noexcept + :handler(_handler), + connect(event_loop, _handler) {} /** * Resolve a host name and connect to it asynchronously. */ - void Start(boost::asio::io_service &io_service, - const char *host, unsigned port) noexcept; - -private: - void OnResolved(const boost::system::error_code &error, - boost::asio::ip::tcp::resolver::iterator i) noexcept; + void Start(const char *host, unsigned port) noexcept; }; #endif
View file
ncmpc-0.47.tar.xz/src/net/Features.hxx
Added
@@ -0,0 +1,38 @@ +/* ncmpc (Ncurses MPD Client) + Copyright 2004-2021 The Music Player Daemon Project + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef NET_FEATURES_HXX +#define NET_FEATURES_HXX + +#define HAVE_TCP + +#ifndef _WIN32 +#define HAVE_UN +#endif + +#endif +
View file
ncmpc-0.47.tar.xz/src/net/HostParser.cxx
Added
@@ -0,0 +1,151 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "HostParser.hxx" +#include "util/CharUtil.hxx" + +#include <cstring> + +static inline bool +IsValidHostnameChar(char ch) noexcept +{ + return IsAlphaNumericASCII(ch) || + ch == '-' || ch == '.' || + ch == '*'; /* for wildcards */ +} + +static inline bool +IsValidScopeChar(char ch) noexcept +{ + return IsAlphaNumericASCII(ch) || + ch == '-' || ch == '_'; +} + +static const char * +FindScopeEnd(const char *p) noexcept +{ + if (*p == '%' && IsValidScopeChar(p1)) { + p += 2; + while (IsValidScopeChar(*p)) + ++p; + } + + return p; +} + +static inline bool +IsValidIPv6Char(char ch) noexcept +{ + return IsDigitASCII(ch) || + (ch >= 'a' && ch <= 'f') || + (ch >= 'A' && ch <= 'F') || + ch == ':'; +} + +static const char * +FindIPv6End(const char *p) noexcept +{ + while (IsValidIPv6Char(*p)) + ++p; + + /* allow "%scope" after numeric IPv6 address */ + p = FindScopeEnd(p); + + return p; +} + +static constexpr std::string_view +SV(const char *begin, const char *end) noexcept +{ +#if __cplusplus >= 202002 && !defined(__clang__) + return {begin, end}; +#else + /* kludge for libc++ which does not yet implement the C++20 + iterator constructor */ + return {begin, std::size_t(end - begin)}; +#endif +} + +ExtractHostResult +ExtractHost(const char *src) noexcept +{ + ExtractHostResult result{{}, src}; + const char *hostname; + + if (IsValidHostnameChar(*src)) { + const char *colon = nullptr; + + hostname = src++; + + while (IsValidHostnameChar(*src) || *src == ':') { + if (*src == ':') { + if (colon != nullptr) { + /* found a second colon: assume it's an IPv6 + address */ + result.end = FindIPv6End(src + 1); + result.host = SV(hostname, result.end); + return result; + } else + /* remember the position of the first colon */ + colon = src; + } + + ++src; + } + + if (colon != nullptr) + /* hostname ends at colon */ + src = colon; + + result.end = src; + result.host = SV(hostname, result.end); + } else if (src0 == ':' && src1 == ':') { + /* IPv6 address beginning with "::" */ + result.end = FindIPv6End(src + 2); + result.host = SV(src, result.end); + } else if (src0 == '') { + /* "hostname:port" (IPv6?) */ + + hostname = ++src; + const char *end = std::strchr(hostname, ''); + if (end == nullptr || end == hostname) + /* failed, return nullptr */ + return result; + + result.host = SV(hostname, end); + result.end = end + 1; + } else { + /* failed, return nullptr */ + } + + return result; +}
View file
ncmpc-0.47.tar.xz/src/net/HostParser.hxx
Added
@@ -0,0 +1,72 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <string_view> + +/** + * Result type for ExtractHost(). + */ +struct ExtractHostResult { + /** + * The host part of the address. + * + * If nothing was parsed, then this is nullptr. + */ + std::string_view host; + + /** + * Pointer to the first character that was not parsed. On + * success, this is usually a pointer to the zero terminator or to + * a colon followed by a port number. + * + * If nothing was parsed, then this is a pointer to the given + * source string. + */ + const char *end; + + constexpr bool HasFailed() const noexcept { + return host.data() == nullptr; + } +}; + +/** + * Extract the host from a string in the form "IP:PORT" or + * "IPv6:PORT". Stops at the first invalid character (e.g. the + * colon). + * + * @param src the input string + */ +gnu::pure +ExtractHostResult +ExtractHost(const char *src) noexcept;
View file
ncmpc-0.47.tar.xz/src/net/IPv4Address.cxx
Added
@@ -0,0 +1,39 @@ +/* + * Copyright 2012-2020 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "IPv4Address.hxx" + +#include <cassert> + +IPv4Address::IPv4Address(SocketAddress src) noexcept + :address(src.CastTo<struct sockaddr_in>()) +{ + assert(!src.IsNull()); + assert(src.GetFamily() == AF_INET); +}
View file
ncmpc-0.47.tar.xz/src/net/IPv4Address.hxx
Added
@@ -0,0 +1,239 @@ +/* + * Copyright 2012-2020 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IPV4_ADDRESS_HXX +#define IPV4_ADDRESS_HXX + +#include "SocketAddress.hxx" +#include "util/ByteOrder.hxx" + +#include <cstdint> + +#ifdef _WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#else +#include <netinet/in.h> +#endif + +/** + * An OO wrapper for struct sockaddr_in. + */ +class IPv4Address { + struct sockaddr_in address; + +#ifdef _WIN32 + static constexpr struct in_addr ConstructInAddr(uint8_t a, uint8_t b, + uint8_t c, uint8_t d) noexcept { + struct in_addr result{}; + result.s_net = a; + result.s_host = b; + result.s_lh = c; + result.s_impno = d; + return result; + } +#else + +#ifdef __BIONIC__ + typedef uint32_t in_addr_t; +#endif + + static constexpr in_addr_t ConstructInAddrT(uint8_t a, uint8_t b, + uint8_t c, uint8_t d) noexcept { + return ToBE32((a << 24) | (b << 16) | (c << 8) | d); + } + + static constexpr struct in_addr ConstructInAddr(uint8_t a, uint8_t b, + uint8_t c, uint8_t d) noexcept { + return ConstructInAddrBE(ConstructInAddrT(a, b, c, d)); + } +#endif + + /** + * @param x the 32 bit IP address in network byte order + */ + static constexpr struct in_addr ConstructInAddrBE(uint32_t x) noexcept { + struct in_addr ia{}; + ia.s_addr = x; + return ia; + } + + /** + * @param x the 32 bit IP address in host byte order + */ + static constexpr struct in_addr ConstructInAddr(uint32_t x) noexcept { + return ConstructInAddrBE(ToBE32(x)); + } + + /** + * @param port the port number in host byte order + */ + static constexpr struct sockaddr_in Construct(struct in_addr address, + uint16_t port) noexcept { + struct sockaddr_in sin{}; + sin.sin_family = AF_INET; + sin.sin_port = ToBE16(port); + sin.sin_addr = address; + return sin; + } + + /** + * @param x the 32 bit IP address in host byte order + * @param port the port number in host byte order + */ + static constexpr struct sockaddr_in Construct(uint32_t address, + uint16_t port) noexcept { + return Construct(ConstructInAddr(address), port); + } + +public: + IPv4Address() = default; + + constexpr IPv4Address(const struct sockaddr_in &_address) noexcept + :address(_address) {} + + /** + * @param port the port number in host byte order + */ + constexpr IPv4Address(struct in_addr _address, uint16_t port) noexcept + :IPv4Address(Construct(_address, port)) {} + + /** + * @param port the port number in host byte order + */ + constexpr IPv4Address(uint8_t a, uint8_t b, uint8_t c, + uint8_t d, uint16_t port) noexcept + :IPv4Address(ConstructInAddr(a, b, c, d), port) {} + + /** + * @param port the port number in host byte order + */ + constexpr explicit IPv4Address(uint16_t port) noexcept + :IPv4Address(ConstructInAddr(INADDR_ANY), port) {} + + /** + * Construct with data copied from a #SocketAddress. Its + * address family must be AF_INET. + */ + explicit IPv4Address(SocketAddress src) noexcept; + + static constexpr struct in_addr Loopback() noexcept { + return ConstructInAddr(INADDR_LOOPBACK); + } + + /** + * Generate a (net-)mask with the specified prefix length. + */ + static constexpr IPv4Address MaskFromPrefix(unsigned prefix_length) noexcept { + return Construct(prefix_length == 0 + ? 0 + : (~uint32_t(0)) << (32 - prefix_length), + ~uint16_t(0)); + } + + /** + * Cast a #sockaddr_in6 reference to an IPv6Address reference. + */ + static constexpr const IPv4Address &Cast(const struct sockaddr_in &src) noexcept { + /* this reinterpret_cast works because this class is + just a wrapper for struct sockaddr_in6 */ + return *(const IPv4Address *)(const void *)&src; + } + + /** + * Return a downcasted reference to the address. This call is + * only legal after verifying SocketAddress::GetFamily(). + */ + static constexpr const IPv4Address &Cast(const SocketAddress src) noexcept { + return Cast(src.CastTo<struct sockaddr_in>()); + } + + constexpr operator SocketAddress() const noexcept { + return SocketAddress((const struct sockaddr *)(const void *)&address, + sizeof(address)); + } + + constexpr SocketAddress::size_type GetSize() const noexcept { + return sizeof(address); + } + + constexpr bool IsDefined() const noexcept { + return address.sin_family != AF_UNSPEC; + } + + /** + * @return the port number in network byte order + */ + constexpr uint16_t GetPortBE() const noexcept { + return address.sin_port; + } + + /** + * @return the port number in host byte order + */ + constexpr uint16_t GetPort() const noexcept { + return FromBE16(GetPortBE()); + } + + /** + * @param port the port number in host byte order + */ + void SetPort(uint16_t port) noexcept { + address.sin_port = ToBE16(port); + } + + constexpr const struct in_addr &GetAddress() const noexcept { + return address.sin_addr; + } + + /** + * @return the 32 bit IP address in network byte order + */ + constexpr uint32_t GetNumericAddressBE() const noexcept { + return GetAddress().s_addr; + } + + /** + * @return the 32 bit IP address in host byte order + */ + constexpr uint32_t GetNumericAddress() const noexcept { + return FromBE32(GetNumericAddressBE()); + } + + /** + * Bit-wise AND of two addresses. This is useful for netmask + * calculations. + */ + constexpr IPv4Address operator&(const IPv4Address &other) const noexcept { + return IPv4Address(ConstructInAddrBE(GetNumericAddressBE() & other.GetNumericAddressBE()), + GetPort() & other.GetPort()); + } +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/net/IPv6Address.cxx
Added
@@ -0,0 +1,93 @@ +/* + * Copyright 2012-2020 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "IPv6Address.hxx" +#include "IPv4Address.hxx" + +#include <cassert> + +#include <string.h> + +IPv6Address::IPv6Address(SocketAddress src) noexcept + :address(src.CastTo<struct sockaddr_in6>()) +{ + assert(!src.IsNull()); + assert(src.GetFamily() == AF_INET6); +} + +bool +IPv6Address::IsAny() const noexcept +{ + assert(IsValid()); + + return memcmp(&address.sin6_addr, + &in6addr_any, sizeof(in6addr_any)) == 0; +} + +IPv4Address +IPv6Address::UnmapV4() const noexcept +{ + assert(IsV4Mapped()); + + struct sockaddr_in buffer{}; + buffer.sin_family = AF_INET; + memcpy(&buffer.sin_addr, ((const char *)&address.sin6_addr) + 12, + sizeof(buffer.sin_addr)); + buffer.sin_port = address.sin6_port; + + return buffer; +} + +template<typename T> +static void +BitwiseAndT(T *dest, const T *a, const T *b, size_t n) +{ + while (n-- > 0) + *dest++ = *a++ & *b++; +} + +static void +BitwiseAnd32(void *dest, const void *a, const void *b, size_t n) +{ + using value_type = uint32_t; + using pointer = value_type *; + using const_pointer = const value_type *; + + BitwiseAndT(pointer(dest), const_pointer(a), const_pointer(b), + n / sizeof(value_type)); +} + +IPv6Address +IPv6Address::operator&(const IPv6Address &other) const +{ + IPv6Address result; + BitwiseAnd32(&result, this, &other, + sizeof(result)); + return result; +}
View file
ncmpc-0.47.tar.xz/src/net/IPv6Address.hxx
Added
@@ -0,0 +1,221 @@ +/* + * Copyright 2012-2020 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IPV6_ADDRESS_HXX +#define IPV6_ADDRESS_HXX + +#include "SocketAddress.hxx" +#include "util/ByteOrder.hxx" + +#include <cstdint> + +#ifdef _WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#else +#include <netinet/in.h> +#endif + +class IPv4Address; + +/** + * An OO wrapper for struct sockaddr_in. + */ +class IPv6Address { + struct sockaddr_in6 address; + + static constexpr struct in6_addr Construct(uint16_t a, uint16_t b, + uint16_t c, uint16_t d, + uint16_t e, uint16_t f, + uint16_t g, uint16_t h) noexcept { + struct in6_addr result{}; + result.s6_addr0 = a >> 8; + result.s6_addr1 = a; + result.s6_addr2 = b >> 8; + result.s6_addr3 = b; + result.s6_addr4 = c >> 8; + result.s6_addr5 = c; + result.s6_addr6 = d >> 8; + result.s6_addr7 = d; + result.s6_addr8 = e >> 8; + result.s6_addr9 = e; + result.s6_addr10 = f >> 8; + result.s6_addr11 = f; + result.s6_addr12 = g >> 8; + result.s6_addr13 = g; + result.s6_addr14 = h >> 8; + result.s6_addr15 = h; + return result; + } + + static constexpr struct sockaddr_in6 Construct(struct in6_addr address, + uint16_t port, + uint32_t scope_id) noexcept { + struct sockaddr_in6 sin{}; + sin.sin6_family = AF_INET6; + sin.sin6_port = ToBE16(port); + sin.sin6_addr = address; + sin.sin6_scope_id = scope_id; + return sin; + } + +public: + IPv6Address() = default; + + constexpr IPv6Address(struct in6_addr _address, uint16_t port, + uint32_t scope_id=0) noexcept + :address(Construct(_address, port, scope_id)) {} + + constexpr explicit IPv6Address(uint16_t port, + uint32_t scope_id=0) noexcept + :IPv6Address(IN6ADDR_ANY_INIT, port, scope_id) {} + + + constexpr IPv6Address(uint16_t a, uint16_t b, uint16_t c, uint16_t d, + uint16_t e, uint16_t f, uint16_t g, uint16_t h, + uint16_t port, uint32_t scope_id=0) noexcept + :IPv6Address(Construct(a, b, c, d, e, f, g, h), + port, scope_id) {} + + /** + * Construct with data copied from a #SocketAddress. Its + * address family must be AF_INET6. + */ + explicit IPv6Address(SocketAddress src) noexcept; + + /** + * Generate a (net-)mask with the specified prefix length. + */ + static constexpr IPv6Address MaskFromPrefix(unsigned prefix_length) noexcept { + return IPv6Address(MaskWord(prefix_length, 0), + MaskWord(prefix_length, 16), + MaskWord(prefix_length, 32), + MaskWord(prefix_length, 48), + MaskWord(prefix_length, 64), + MaskWord(prefix_length, 80), + MaskWord(prefix_length, 96), + MaskWord(prefix_length, 112), + ~uint16_t(0), + ~uint32_t(0)); + } + + /** + * Cast a #sockaddr_in6 reference to an IPv6Address reference. + */ + static constexpr const IPv6Address &Cast(const struct sockaddr_in6 &src) noexcept { + /* this reinterpret_cast works because this class is + just a wrapper for struct sockaddr_in6 */ + return *(const IPv6Address *)(const void *)&src; + } + + /** + * Return a downcasted reference to the address. This call is + * only legal after verifying SocketAddress::GetFamily(). + */ + static constexpr const IPv6Address &Cast(const SocketAddress src) noexcept { + return Cast(src.CastTo<struct sockaddr_in6>()); + } + + constexpr operator SocketAddress() const noexcept { + return SocketAddress((const struct sockaddr *)(const void *)&address, + sizeof(address)); + } + + constexpr SocketAddress::size_type GetSize() const noexcept { + return sizeof(address); + } + + constexpr bool IsDefined() const noexcept { + return address.sin6_family != AF_UNSPEC; + } + + constexpr bool IsValid() const noexcept { + return address.sin6_family == AF_INET6; + } + + constexpr uint16_t GetPort() const noexcept { + return FromBE16(address.sin6_port); + } + + void SetPort(uint16_t port) noexcept { + address.sin6_port = ToBE16(port); + } + + constexpr const struct in6_addr &GetAddress() const noexcept { + return address.sin6_addr; + } + + constexpr uint32_t GetScopeId() const noexcept { + return address.sin6_scope_id; + } + + /** + * Is this the IPv6 wildcard address (in6addr_any)? + */ + gnu::pure + bool IsAny() const noexcept; + + /** + * Is this an IPv4 address mapped inside struct sockaddr_in6? + */ +#if defined(__linux__) + constexpr +#endif + bool IsV4Mapped() const noexcept { + return IN6_IS_ADDR_V4MAPPED(&address.sin6_addr); + } + + /** + * Convert "::ffff:127.0.0.1" to "127.0.0.1". + */ + gnu::pure + IPv4Address UnmapV4() const noexcept; + + /** + * Bit-wise AND of two addresses. This is useful for netmask + * calculations. + */ + gnu::pure + IPv6Address operator&(const IPv6Address &other) const; + +private: + /** + * Helper function for MaskFromPrefix(). + */ + static constexpr uint16_t MaskWord(unsigned prefix_length, + unsigned offset) noexcept { + return prefix_length <= offset + ? 0 + : (prefix_length >= offset + 16 + ? 0xffff + : (0xffff << (offset + 16 - prefix_length))); + } +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/net/Resolver.cxx
Added
@@ -0,0 +1,148 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Resolver.hxx" +#include "AddressInfo.hxx" +#include "HostParser.hxx" +#include "util/RuntimeError.hxx" +#include "util/CharUtil.hxx" + +#ifdef _WIN32 +#include <ws2tcpip.h> +#else +#include <sys/socket.h> +#include <netdb.h> +#include <net/if.h> +#endif + +#include <cstring> + +#include <stdio.h> + +AddressInfoList +Resolve(const char *node, const char *service, + const struct addrinfo *hints) +{ + struct addrinfo *ai; + int error = getaddrinfo(node, service, hints, &ai); + if (error != 0) + throw FormatRuntimeError("Failed to resolve '%s':'%s': %s", + node == nullptr ? "" : node, + service == nullptr ? "" : service, + gai_strerror(error)); + + return AddressInfoList(ai); +} + +static inline bool +ai_is_passive(const struct addrinfo *ai) +{ + return ai == nullptr || (ai->ai_flags & AI_PASSIVE) != 0; +} + +#ifndef _WIN32 + +/** + * Check if there is an interface name after '%', and if so, replace + * it with the interface index, because getaddrinfo() understands only + * the index, not the name (tested on Linux/glibc). + */ +static void +FindAndResolveInterfaceName(char *host, size_t size) +{ + char *percent = std::strchr(host, '%'); + if (percent == nullptr || percent + 64 > host + size) + return; + + char *interface = percent + 1; + if (!IsAlphaASCII(*interface)) + return; + + const unsigned i = if_nametoindex(interface); + if (i == 0) + throw FormatRuntimeError("No such interface: %s", interface); + + sprintf(interface, "%u", i); +} + +#endif + +AddressInfoList +Resolve(const char *host_and_port, int default_port, + const struct addrinfo *hints) +{ + const char *host, *port; + char buffer256, port_string16; + + if (host_and_port != nullptr) { + const auto eh = ExtractHost(host_and_port); + if (eh.HasFailed()) + throw std::runtime_error("Failed to extract host name"); + + if (eh.host.size() >= sizeof(buffer)) + throw std::runtime_error("Host name too long"); + + *std::copy(eh.host.begin(), eh.host.end(), buffer) = 0; + host = buffer; + +#ifndef _WIN32 + FindAndResolveInterfaceName(buffer, sizeof(buffer)); +#endif + + port = eh.end; + if (*port == ':') { + /* port specified */ + ++port; + } else if (*port == 0) { + /* no port specified */ + snprintf(port_string, sizeof(port_string), "%d", default_port); + port = port_string; + } else + throw std::runtime_error("Garbage after host name"); + + if (ai_is_passive(hints) && strcmp(host, "*") == 0) + host = nullptr; + } else { + host = nullptr; + snprintf(port_string, sizeof(port_string), "%d", default_port); + port = port_string; + } + + return Resolve(host, port, hints); +} + +AddressInfoList +Resolve(const char *host_port, unsigned default_port, int flags, int socktype) +{ + const auto hints = MakeAddrInfo(flags, AF_UNSPEC, socktype); + return Resolve(host_port, default_port, &hints); +}
View file
ncmpc-0.47.tar.xz/src/net/Resolver.hxx
Added
@@ -0,0 +1,62 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NET_RESOLVER_HXX +#define NET_RESOLVER_HXX + +class AddressInfoList; + +/** + * Thin wrapper for getaddrinfo() which throws on error and returns a + * RAII object. + */ +AddressInfoList +Resolve(const char *node, const char *service, + const struct addrinfo *hints); + +/** + * Resolve the given host name (which may include a port), and fall + * back to the given default port. + * + * This is a wrapper for getaddrinfo() and it does not support local + * sockets. + * + * Throws on error. + */ +AddressInfoList +Resolve(const char *host_and_port, int default_port, + const struct addrinfo *hints); + +AddressInfoList +Resolve(const char *host_port, unsigned default_port, int flags, int socktype); + +#endif
View file
ncmpc-0.47.tar.xz/src/net/SocketAddress.cxx
Added
@@ -0,0 +1,183 @@ +/* + * Copyright 2012-2022 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "SocketAddress.hxx" +#include "IPv4Address.hxx" +#include "IPv6Address.hxx" + +#include <cassert> +#include <cstring> + +#ifdef HAVE_UN +#include <sys/un.h> +#endif + +#ifdef HAVE_TCP +#ifdef _WIN32 +#include <ws2tcpip.h> +#else +#include <netinet/in.h> +#endif +#endif + +bool +SocketAddress::operator==(SocketAddress other) const noexcept +{ + return size == other.size && memcmp(address, other.address, size) == 0; +} + +#ifdef HAVE_UN + +std::string_view +SocketAddress::GetLocalRaw() const noexcept +{ + if (IsNull() || GetFamily() != AF_LOCAL) + /* not applicable */ + return {}; + + const auto *sun = &CastTo<struct sockaddr_un>(); + const auto start = (const char *)sun; + const auto path = sun->sun_path; + const size_t header_size = path - start; + if (size < size_type(header_size)) + /* malformed address */ + return {}; + + return {path, size - header_size}; +} + +const char * +SocketAddress::GetLocalPath() const noexcept +{ + const auto raw = GetLocalRaw(); + return !raw.empty() && + /* must be an absolute path */ + raw.front() == '/' && + /* must be null-terminated */ + raw.back() == 0 && + /* there must not be any other null byte */ + std::memchr(raw.data(), 0, raw.size() - 1) == nullptr + ? raw.data() + : nullptr; +} + +#endif + +#ifdef HAVE_TCP + +bool +SocketAddress::IsV6Any() const noexcept +{ + return GetFamily() == AF_INET6 && IPv6Address::Cast(*this).IsAny(); +} + +bool +SocketAddress::IsV4Mapped() const noexcept +{ + return GetFamily() == AF_INET6 && IPv6Address::Cast(*this).IsV4Mapped(); +} + +IPv4Address +SocketAddress::UnmapV4() const noexcept +{ + assert(IsV4Mapped()); + + return IPv6Address::Cast(*this).UnmapV4(); +} + +unsigned +SocketAddress::GetPort() const noexcept +{ + if (IsNull()) + return 0; + + switch (GetFamily()) { + case AF_INET: + return IPv4Address::Cast(*this).GetPort(); + + case AF_INET6: + return IPv6Address::Cast(*this).GetPort(); + + default: + return 0; + } +} + +#ifdef __cpp_lib_span + +static std::span<const std::byte> +GetSteadyPart(const struct sockaddr_in &address) noexcept +{ + return { + reinterpret_cast<const std::byte *>(&address.sin_addr), + sizeof(address.sin_addr), + }; +} + +static std::span<const std::byte> +GetSteadyPart(const struct sockaddr_in6 &address) noexcept +{ + return { + reinterpret_cast<const std::byte *>(&address.sin6_addr), + sizeof(address.sin6_addr), + }; +} + +#endif // __cpp_lib_span + +#endif // HAVE_TCP + +#ifdef __cpp_lib_span + +std::span<const std::byte> +SocketAddress::GetSteadyPart() const noexcept +{ + if (IsNull()) + return {}; + + switch (GetFamily()) { +#ifdef HAVE_UN + case AF_LOCAL: + return std::as_bytes(std::span<const char>{GetLocalRaw()}); +#endif + +#ifdef HAVE_TCP + case AF_INET: + return ::GetSteadyPart(CastTo<struct sockaddr_in>()); + + case AF_INET6: + return ::GetSteadyPart(CastTo<struct sockaddr_in6>()); +#endif + + default: + return {}; + } +} + +#endif
View file
ncmpc-0.47.tar.xz/src/net/SocketAddress.hxx
Added
@@ -0,0 +1,201 @@ +/* + * Copyright 2012-2022 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SOCKET_ADDRESS_HXX +#define SOCKET_ADDRESS_HXX + +#include "Features.hxx" + +#ifdef _WIN32 +#include <winsock2.h> // IWYU pragma: export +#else +#include <sys/socket.h> // IWYU pragma: export +#endif + +#include <cstddef> + +#if __cplusplus >= 202002 || (defined(__GNUC__) && __GNUC__ >= 10) +#include <version> +#endif + +#ifdef __cpp_lib_span +#include <span> +#endif + +#ifdef HAVE_UN +#include <string_view> +#endif + +class IPv4Address; + +/** + * An OO wrapper for struct sockaddr. + */ +class SocketAddress { +public: +#ifdef _WIN32 + typedef int size_type; +#else + typedef socklen_t size_type; +#endif + +private: + const struct sockaddr *address; + size_type size; + +public: + SocketAddress() = default; + + constexpr SocketAddress(std::nullptr_t) noexcept + :address(nullptr), size(0) {} + + constexpr SocketAddress(const struct sockaddr *_address, + size_type _size) noexcept + :address(_address), size(_size) {} + +#ifdef __cpp_lib_span + explicit SocketAddress(std::span<const std::byte> src) noexcept + :address((const struct sockaddr *)(const void *)src.data()), + size(src.size()) {} +#endif + + static constexpr SocketAddress Null() noexcept { + return nullptr; + } + + constexpr bool IsNull() const noexcept { + return address == nullptr; + } + + constexpr const struct sockaddr *GetAddress() const noexcept { + return address; + } + + /** + * Cast the "sockaddr" pointer to a different address type, + * e.g. "sockaddr_in". This is only legal after checking + * !IsNull() and GetFamily(). + */ + template<typename T> + constexpr const T &CastTo() const noexcept { + /* cast through void to work around the bogus + alignment warning */ + const void *q = reinterpret_cast<const void *>(address); + return *reinterpret_cast<const T *>(q); + } + + constexpr size_type GetSize() const noexcept { + return size; + } + + constexpr int GetFamily() const noexcept { + return address->sa_family; + } + + /** + * Does the object have a well-defined address? Check !IsNull() + * before calling this method. + */ + constexpr bool IsDefined() const noexcept { + return GetFamily() != AF_UNSPEC; + } + +#ifdef HAVE_UN + /** + * Extract the local socket path (which may begin with a null + * byte, denoting an "abstract" socket). The return value's + * "size" attribute includes the null terminator. Returns + * nullptr if not applicable. + */ + gnu::pure + std::string_view GetLocalRaw() const noexcept; + + /** + * Returns the local socket path or nullptr if not applicable + * (or if the path is corrupt). + */ + gnu::pure + const char *GetLocalPath() const noexcept; +#endif + +#ifdef HAVE_TCP + /** + * Is this the IPv6 wildcard address (in6addr_any)? + */ + gnu::pure + bool IsV6Any() const noexcept; + + /** + * Is this an IPv4 address mapped inside struct sockaddr_in6? + */ + gnu::pure + bool IsV4Mapped() const noexcept; + + /** + * Convert "::ffff:127.0.0.1" to "127.0.0.1". + */ + gnu::pure + IPv4Address UnmapV4() const noexcept; + + /** + * Extract the port number. Returns 0 if not applicable. + */ + gnu::pure + unsigned GetPort() const noexcept; +#endif + +#ifdef __cpp_lib_span + operator std::span<const std::byte>() const noexcept { + const void *q = reinterpret_cast<const void *>(address); + return { + (const std::byte *)q, + (std::size_t)size, + }; + } + + /** + * Return a buffer pointing to the "steady" portion of the + * address, i.e. without volatile parts like the port number. + * This buffer is useful for hashing the address, but not so + * much for anything else. Returns nullptr if the address is + * not supported. + */ + gnu::pure + std::span<const std::byte> GetSteadyPart() const noexcept; +#endif + + gnu::pure + bool operator==(const SocketAddress other) const noexcept; + + bool operator!=(const SocketAddress other) const noexcept { + return !(*this == other); + } +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/net/SocketDescriptor.cxx
Added
@@ -0,0 +1,551 @@ +/* + * Copyright 2012-2019 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "SocketDescriptor.hxx" +#include "SocketAddress.hxx" +#include "StaticSocketAddress.hxx" +#include "IPv4Address.hxx" +#include "IPv6Address.hxx" + +#ifdef _WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#else +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#endif + +#include <cassert> +#include <cerrno> + +#include <string.h> + +int +SocketDescriptor::GetType() const noexcept +{ + assert(IsDefined()); + + int type; + socklen_t size = sizeof(type); + return getsockopt(fd, SOL_SOCKET, SO_TYPE, + (char *)&type, &size) == 0 + ? type + : -1; +} + +bool +SocketDescriptor::IsStream() const noexcept +{ + return GetType() == SOCK_STREAM; +} + +#ifdef _WIN32 + +void +SocketDescriptor::Close() noexcept +{ + if (IsDefined()) + ::closesocket(Steal()); +} + +#endif + +SocketDescriptor +SocketDescriptor::Accept() noexcept +{ +#ifdef __linux__ + int connection_fd = ::accept4(Get(), nullptr, nullptr, SOCK_CLOEXEC); +#else + int connection_fd = ::accept(Get(), nullptr, nullptr); +#endif + return connection_fd >= 0 + ? SocketDescriptor(connection_fd) + : Undefined(); +} + +SocketDescriptor +SocketDescriptor::AcceptNonBlock() const noexcept +{ +#ifdef __linux__ + int connection_fd = ::accept4(Get(), nullptr, nullptr, + SOCK_CLOEXEC|SOCK_NONBLOCK); +#else + int connection_fd = ::accept(Get(), nullptr, nullptr); + if (connection_fd >= 0) + SocketDescriptor(connection_fd).SetNonBlocking(); +#endif + return SocketDescriptor(connection_fd); +} + +SocketDescriptor +SocketDescriptor::AcceptNonBlock(StaticSocketAddress &address) const noexcept +{ + address.SetMaxSize(); +#ifdef __linux__ + int connection_fd = ::accept4(Get(), address, &address.size, + SOCK_CLOEXEC|SOCK_NONBLOCK); +#else + int connection_fd = ::accept(Get(), address, &address.size); + if (connection_fd >= 0) + SocketDescriptor(connection_fd).SetNonBlocking(); +#endif + return SocketDescriptor(connection_fd); +} + +bool +SocketDescriptor::Connect(SocketAddress address) noexcept +{ + assert(address.IsDefined()); + + return ::connect(Get(), address.GetAddress(), address.GetSize()) >= 0; +} + +bool +SocketDescriptor::Create(int domain, int type, int protocol) noexcept +{ +#ifdef _WIN32 + static bool initialised = false; + if (!initialised) { + WSADATA data; + WSAStartup(MAKEWORD(2,2), &data); + initialised = true; + } +#endif + +#ifdef SOCK_CLOEXEC + /* implemented since Linux 2.6.27 */ + type |= SOCK_CLOEXEC; +#endif + + int new_fd = socket(domain, type, protocol); + if (new_fd < 0) + return false; + + Set(new_fd); + return true; +} + +bool +SocketDescriptor::CreateNonBlock(int domain, int type, int protocol) noexcept +{ +#ifdef SOCK_NONBLOCK + type |= SOCK_NONBLOCK; +#endif + + if (!Create(domain, type, protocol)) + return false; + +#ifndef SOCK_NONBLOCK + SetNonBlocking(); +#endif + + return true; +} + +#ifndef _WIN32 + +bool +SocketDescriptor::CreateSocketPair(int domain, int type, int protocol, + SocketDescriptor &a, + SocketDescriptor &b) noexcept +{ +#ifdef SOCK_CLOEXEC + /* implemented since Linux 2.6.27 */ + type |= SOCK_CLOEXEC; +#endif + + int fds2; + if (socketpair(domain, type, protocol, fds) < 0) + return false; + + a = SocketDescriptor(fds0); + b = SocketDescriptor(fds1); + return true; +} + +bool +SocketDescriptor::CreateSocketPairNonBlock(int domain, int type, int protocol, + SocketDescriptor &a, + SocketDescriptor &b) noexcept +{ +#ifdef SOCK_NONBLOCK + type |= SOCK_NONBLOCK; +#endif + + if (!CreateSocketPair(domain, type, protocol, a, b)) + return false; + +#ifndef SOCK_NONBLOCK + a.SetNonBlocking(); + b.SetNonBlocking(); +#endif + + return true; +} + +#endif + +int +SocketDescriptor::GetError() noexcept +{ + assert(IsDefined()); + + int s_err = 0; + socklen_t s_err_size = sizeof(s_err); + return getsockopt(fd, SOL_SOCKET, SO_ERROR, + (char *)&s_err, &s_err_size) == 0 + ? s_err + : errno; +} + +std::size_t +SocketDescriptor::GetOption(int level, int name, + void *value, std::size_t size) const noexcept +{ + assert(IsDefined()); + + socklen_t size2 = size; + return getsockopt(fd, level, name, (char *)value, &size2) == 0 + ? size2 + : 0; +} + +#ifdef HAVE_STRUCT_UCRED + +struct ucred +SocketDescriptor::GetPeerCredentials() const noexcept +{ + struct ucred cred; + if (GetOption(SOL_SOCKET, SO_PEERCRED, + &cred, sizeof(cred)) < sizeof(cred)) + cred.pid = -1; + return cred; +} + +#endif + +#ifdef _WIN32 + +bool +SocketDescriptor::SetNonBlocking() noexcept +{ + u_long val = 1; + return ioctlsocket(fd, FIONBIO, &val) == 0; +} + +#endif + +bool +SocketDescriptor::SetOption(int level, int name, + const void *value, std::size_t size) noexcept +{ + assert(IsDefined()); + + /* on Windows, setsockopt() wants "const char *" */ + return setsockopt(fd, level, name, (const char *)value, size) == 0; +} + +bool +SocketDescriptor::SetKeepAlive(bool value) noexcept +{ + return SetBoolOption(SOL_SOCKET, SO_KEEPALIVE, value); +} + +bool +SocketDescriptor::SetReuseAddress(bool value) noexcept +{ + return SetBoolOption(SOL_SOCKET, SO_REUSEADDR, value); +} + +#ifdef __linux__ + +bool +SocketDescriptor::SetReusePort(bool value) noexcept +{ + return SetBoolOption(SOL_SOCKET, SO_REUSEPORT, value); +} + +bool +SocketDescriptor::SetFreeBind(bool value) noexcept +{ + return SetBoolOption(IPPROTO_IP, IP_FREEBIND, value); +} + +bool +SocketDescriptor::SetNoDelay(bool value) noexcept +{ + return SetBoolOption(IPPROTO_TCP, TCP_NODELAY, value); +} + +bool +SocketDescriptor::SetCork(bool value) noexcept +{ + return SetBoolOption(IPPROTO_TCP, TCP_CORK, value); +} + +bool +SocketDescriptor::SetTcpDeferAccept(const int &seconds) noexcept +{ + return SetOption(IPPROTO_TCP, TCP_DEFER_ACCEPT, &seconds, sizeof(seconds)); +} + +bool +SocketDescriptor::SetTcpUserTimeout(const unsigned &milliseconds) noexcept +{ + return SetOption(IPPROTO_TCP, TCP_USER_TIMEOUT, + &milliseconds, sizeof(milliseconds)); +} + +bool +SocketDescriptor::SetV6Only(bool value) noexcept +{ + return SetBoolOption(IPPROTO_IPV6, IPV6_V6ONLY, value); +} + +bool +SocketDescriptor::SetBindToDevice(const char *name) noexcept +{ + return SetOption(SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name)); +} + +#ifdef TCP_FASTOPEN + +bool +SocketDescriptor::SetTcpFastOpen(int qlen) noexcept +{ + return SetOption(SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)); +} + +#endif + +bool +SocketDescriptor::AddMembership(const IPv4Address &address) noexcept +{ + struct ip_mreq r{address.GetAddress(), IPv4Address(0).GetAddress()}; + return setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &r, sizeof(r)) == 0; +} + +bool +SocketDescriptor::AddMembership(const IPv6Address &address) noexcept +{ + struct ipv6_mreq r{address.GetAddress(), 0}; + r.ipv6mr_interface = address.GetScopeId(); + return setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, + &r, sizeof(r)) == 0; +} + +bool +SocketDescriptor::AddMembership(SocketAddress address) noexcept +{ + switch (address.GetFamily()) { + case AF_INET: + return AddMembership(IPv4Address(address)); + + case AF_INET6: + return AddMembership(IPv6Address(address)); + + default: + errno = EINVAL; + return false; + } +} + +#endif + +bool +SocketDescriptor::Bind(SocketAddress address) noexcept +{ + return bind(Get(), address.GetAddress(), address.GetSize()) == 0; +} + +#ifdef __linux__ + +bool +SocketDescriptor::AutoBind() noexcept +{ + static constexpr sa_family_t family = AF_LOCAL; + return Bind(SocketAddress((const struct sockaddr *)&family, + sizeof(family))); +} + +#endif + +bool +SocketDescriptor::Listen(int backlog) noexcept +{ + return listen(Get(), backlog) == 0; +} + +StaticSocketAddress +SocketDescriptor::GetLocalAddress() const noexcept +{ + assert(IsDefined()); + + StaticSocketAddress result; + result.size = result.GetCapacity(); + if (getsockname(fd, result, &result.size) < 0) + result.Clear(); + + return result; +} + +StaticSocketAddress +SocketDescriptor::GetPeerAddress() const noexcept +{ + assert(IsDefined()); + + StaticSocketAddress result; + result.size = result.GetCapacity(); + if (getpeername(fd, result, &result.size) < 0) + result.Clear(); + + return result; +} + +ssize_t +SocketDescriptor::Read(void *buffer, std::size_t length) noexcept +{ + int flags = 0; +#ifndef _WIN32 + flags |= MSG_DONTWAIT; +#endif + + return ::recv(Get(), (char *)buffer, length, flags); +} + +ssize_t +SocketDescriptor::Write(const void *buffer, std::size_t length) noexcept +{ + int flags = 0; +#ifdef __linux__ + flags |= MSG_NOSIGNAL; +#endif + + return ::send(Get(), (const char *)buffer, length, flags); +} + +#ifdef _WIN32 + +int +SocketDescriptor::WaitReadable(int timeout_ms) const noexcept +{ + assert(IsDefined()); + + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(Get(), &rfds); + + struct timeval timeout, *timeout_p = nullptr; + if (timeout_ms >= 0) { + timeout.tv_sec = unsigned(timeout_ms) / 1000; + timeout.tv_usec = (unsigned(timeout_ms) % 1000) * 1000; + timeout_p = &timeout; + } + + return select(Get() + 1, &rfds, nullptr, nullptr, timeout_p); +} + +int +SocketDescriptor::WaitWritable(int timeout_ms) const noexcept +{ + assert(IsDefined()); + + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(Get(), &wfds); + + struct timeval timeout, *timeout_p = nullptr; + if (timeout_ms >= 0) { + timeout.tv_sec = unsigned(timeout_ms) / 1000; + timeout.tv_usec = (unsigned(timeout_ms) % 1000) * 1000; + timeout_p = &timeout; + } + + return select(Get() + 1, nullptr, &wfds, nullptr, timeout_p); +} + +#endif + +ssize_t +SocketDescriptor::Read(void *buffer, std::size_t length, + StaticSocketAddress &address) noexcept +{ + int flags = 0; +#ifndef _WIN32 + flags |= MSG_DONTWAIT; +#endif + + socklen_t addrlen = address.GetCapacity(); + ssize_t nbytes = ::recvfrom(Get(), (char *)buffer, length, flags, + address, &addrlen); + if (nbytes > 0) + address.SetSize(addrlen); + + return nbytes; +} + +ssize_t +SocketDescriptor::Write(const void *buffer, std::size_t length, + SocketAddress address) noexcept +{ + int flags = 0; +#ifndef _WIN32 + flags |= MSG_DONTWAIT; +#endif +#ifdef __linux__ + flags |= MSG_NOSIGNAL; +#endif + + return ::sendto(Get(), (const char *)buffer, length, flags, + address.GetAddress(), address.GetSize()); +} + +#ifndef _WIN32 + +void +SocketDescriptor::Shutdown() noexcept +{ + shutdown(Get(), SHUT_RDWR); +} + +void +SocketDescriptor::ShutdownRead() noexcept +{ + shutdown(Get(), SHUT_RD); +} + +void +SocketDescriptor::ShutdownWrite() noexcept +{ + shutdown(Get(), SHUT_WR); +} + +#endif
View file
ncmpc-0.47.tar.xz/src/net/SocketDescriptor.hxx
Added
@@ -0,0 +1,271 @@ +/* + * Copyright 2012-2021 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SOCKET_DESCRIPTOR_HXX +#define SOCKET_DESCRIPTOR_HXX + +#include "Features.hxx" +#include "io/FileDescriptor.hxx" + +#include <type_traits> + +class SocketAddress; +class StaticSocketAddress; +class IPv4Address; +class IPv6Address; + +/** + * An OO wrapper for a UNIX socket descriptor. + */ +class SocketDescriptor : protected FileDescriptor { +protected: + explicit constexpr SocketDescriptor(FileDescriptor _fd) noexcept + :FileDescriptor(_fd) {} + +public: + SocketDescriptor() = default; + + explicit constexpr SocketDescriptor(int _fd) noexcept + :FileDescriptor(_fd) {} + + constexpr bool operator==(SocketDescriptor other) const noexcept { + return fd == other.fd; + } + +#ifndef _WIN32 + /** + * Convert a #FileDescriptor to a #SocketDescriptor. This is only + * possible on operating systems where socket descriptors are the + * same as file descriptors (i.e. not on Windows). Use this only + * when you know what you're doing. + */ + static constexpr SocketDescriptor FromFileDescriptor(FileDescriptor fd) noexcept { + return SocketDescriptor(fd); + } + + /** + * Convert this object to a #FileDescriptor instance. This is only + * possible on operating systems where socket descriptors are the + * same as file descriptors (i.e. not on Windows). Use this only + * when you know what you're doing. + */ + constexpr const FileDescriptor &ToFileDescriptor() const noexcept { + return *this; + } +#endif + + using FileDescriptor::IsDefined; +#ifndef _WIN32 + using FileDescriptor::IsValid; + using FileDescriptor::IsSocket; +#endif + + /** + * Determine the socket type, i.e. SOCK_STREAM, SOCK_DGRAM or + * SOCK_SEQPACKET. Returns -1 on error. + */ + gnu::pure + int GetType() const noexcept; + + /** + * Is this a stream socket? + */ + gnu::pure + bool IsStream() const noexcept; + + using FileDescriptor::Get; + using FileDescriptor::Set; + using FileDescriptor::Steal; + using FileDescriptor::SetUndefined; + + static constexpr SocketDescriptor Undefined() noexcept { + return SocketDescriptor(FileDescriptor::Undefined()); + } + + using FileDescriptor::EnableCloseOnExec; + using FileDescriptor::DisableCloseOnExec; + +#ifndef _WIN32 + using FileDescriptor::SetNonBlocking; + using FileDescriptor::SetBlocking; + using FileDescriptor::Duplicate; + using FileDescriptor::CheckDuplicate; + using FileDescriptor::Close; +#else + bool SetNonBlocking() noexcept; + + /** + * This method replaces FileDescriptor::Close(), using closesocket() + * on Windows. FileDescriptor::Close() is not virtual, so be + * careful when dealing with a FileDescriptor reference that is + * really a SocketDescriptor. + */ + void Close() noexcept; +#endif + + /** + * Create a socket. + * + * @param domain is the address domain + * @param type is the sochet type + * @param protocol is the protocol + * @return True on success, False on failure + * See man 2 socket for detailed information + */ + bool Create(int domain, int type, int protocol) noexcept; + + /** + * Like Create(), but enable non-blocking mode. + */ + bool CreateNonBlock(int domain, int type, int protocol) noexcept; + +#ifndef _WIN32 + static bool CreateSocketPair(int domain, int type, int protocol, + SocketDescriptor &a, + SocketDescriptor &b) noexcept; + static bool CreateSocketPairNonBlock(int domain, int type, int protocol, + SocketDescriptor &a, + SocketDescriptor &b) noexcept; +#endif + + int GetError() noexcept; + + /** + * @return the value size or 0 on error + */ + std::size_t GetOption(int level, int name, + void *value, std::size_t size) const noexcept; + +#ifdef HAVE_STRUCT_UCRED + /** + * Receive peer credentials (SO_PEERCRED). On error, the pid + * is -1. + */ + gnu::pure + struct ucred GetPeerCredentials() const noexcept; +#endif + + bool SetOption(int level, int name, + const void *value, std::size_t size) noexcept; + + bool SetIntOption(int level, int name, const int &value) noexcept { + return SetOption(level, name, &value, sizeof(value)); + } + + bool SetBoolOption(int level, int name, bool value) noexcept { + return SetIntOption(level, name, value); + } + + bool SetKeepAlive(bool value=true) noexcept; + bool SetReuseAddress(bool value=true) noexcept; + +#ifdef __linux__ + bool SetReusePort(bool value=true) noexcept; + bool SetFreeBind(bool value=true) noexcept; + bool SetNoDelay(bool value=true) noexcept; + bool SetCork(bool value=true) noexcept; + + bool SetTcpDeferAccept(const int &seconds) noexcept; + + /** + * Setter for TCP_USER_TIMEOUT. + */ + bool SetTcpUserTimeout(const unsigned &milliseconds) noexcept; + + bool SetV6Only(bool value) noexcept; + + /** + * Setter for SO_BINDTODEVICE. + */ + bool SetBindToDevice(const char *name) noexcept; + + bool SetTcpFastOpen(int qlen=16) noexcept; + + bool AddMembership(const IPv4Address &address) noexcept; + bool AddMembership(const IPv6Address &address) noexcept; + bool AddMembership(SocketAddress address) noexcept; +#endif + + bool Bind(SocketAddress address) noexcept; + +#ifdef __linux__ + /** + * Binds the socket to a unique abstract address. + */ + bool AutoBind() noexcept; +#endif + + bool Listen(int backlog) noexcept; + + SocketDescriptor Accept() noexcept; + SocketDescriptor AcceptNonBlock() const noexcept; + SocketDescriptor AcceptNonBlock(StaticSocketAddress &address) const noexcept; + + bool Connect(SocketAddress address) noexcept; + + gnu::pure + StaticSocketAddress GetLocalAddress() const noexcept; + + gnu::pure + StaticSocketAddress GetPeerAddress() const noexcept; + + ssize_t Read(void *buffer, std::size_t length) noexcept; + ssize_t Write(const void *buffer, std::size_t length) noexcept; + +#ifdef _WIN32 + int WaitReadable(int timeout_ms) const noexcept; + int WaitWritable(int timeout_ms) const noexcept; +#else + using FileDescriptor::WaitReadable; + using FileDescriptor::WaitWritable; + using FileDescriptor::IsReadyForWriting; +#endif + + /** + * Receive a datagram and return the source address. + */ + ssize_t Read(void *buffer, std::size_t length, + StaticSocketAddress &address) noexcept; + + /** + * Send a datagram to the specified address. + */ + ssize_t Write(const void *buffer, std::size_t length, + SocketAddress address) noexcept; + +#ifndef _WIN32 + void Shutdown() noexcept; + void ShutdownRead() noexcept; + void ShutdownWrite() noexcept; +#endif +}; + +static_assert(std::is_trivial<SocketDescriptor>::value, "type is not trivial"); + +#endif
View file
ncmpc-0.47.tar.xz/src/net/SocketError.cxx
Added
@@ -0,0 +1,72 @@ +/* + * Copyright 2015-2021 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "SocketError.hxx" + +#include <iterator> + +#include <string.h> + +#ifdef _WIN32 + +SocketErrorMessage::SocketErrorMessage(socket_error_t code) noexcept +{ +#ifdef _UNICODE + wchar_t buffermsg_size; +#else + auto *buffer = msg; +#endif + + DWORD nbytes = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_MAX_WIDTH_MASK, + nullptr, code, 0, + buffer, msg_size, nullptr); + if (nbytes == 0) { + strcpy(msg, "Unknown error"); + return; + } + +#ifdef _UNICODE + auto length = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, + msg, std::size(msg), + nullptr, nullptr); + if (length <= 0) { + strcpy(msg, "WideCharToMultiByte() error"); + return; + } +#endif +} + +#else + +SocketErrorMessage::SocketErrorMessage(socket_error_t code) noexcept + :msg(strerror(code)) {} + +#endif
View file
ncmpc-0.47.tar.xz/src/net/SocketError.hxx
Added
@@ -0,0 +1,218 @@ +/* + * Copyright 2015-2022 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "system/Error.hxx" + +#ifdef _WIN32 +#include <winsock2.h> +typedef DWORD socket_error_t; +#else +#include <cerrno> +typedef int socket_error_t; +#endif + +gnu::pure +static inline socket_error_t +GetSocketError() noexcept +{ +#ifdef _WIN32 + return WSAGetLastError(); +#else + return errno; +#endif +} + +constexpr bool +IsSocketErrorInProgress(socket_error_t code) noexcept +{ +#ifdef _WIN32 + return code == WSAEINPROGRESS; +#else + return code == EINPROGRESS; +#endif +} + +constexpr bool +IsSocketErrorWouldBlock(socket_error_t code) noexcept +{ +#ifdef _WIN32 + return code == WSAEWOULDBLOCK; +#else + return code == EWOULDBLOCK; +#endif +} + +constexpr bool +IsSocketErrorConnectWouldBlock(socket_error_t code) noexcept +{ +#if defined(_WIN32) || defined(__linux__) + /* on Windows, WSAEINPROGRESS is for blocking sockets and + WSAEWOULDBLOCK for non-blocking sockets */ + /* on Linux, EAGAIN==EWOULDBLOCK is for local sockets and + EINPROGRESS is for all other sockets */ + return IsSocketErrorInProgress(code) || IsSocketErrorWouldBlock(code); +#else + /* on all other operating systems, there's just EINPROGRESS */ + return IsSocketErrorInProgress(code); +#endif +} + +constexpr bool +IsSocketErrorSendWouldBlock(socket_error_t code) noexcept +{ +#ifdef _WIN32 + /* on Windows, WSAEINPROGRESS is for blocking sockets and + WSAEWOULDBLOCK for non-blocking sockets */ + return IsSocketErrorInProgress(code) || IsSocketErrorWouldBlock(code); +#else + /* on all other operating systems, there's just EAGAIN==EWOULDBLOCK */ + return IsSocketErrorWouldBlock(code); +#endif +} + +constexpr bool +IsSocketErrorReceiveWouldBlock(socket_error_t code) noexcept +{ +#ifdef _WIN32 + /* on Windows, WSAEINPROGRESS is for blocking sockets and + WSAEWOULDBLOCK for non-blocking sockets */ + return IsSocketErrorInProgress(code) || IsSocketErrorWouldBlock(code); +#else + /* on all other operating systems, there's just + EAGAIN==EWOULDBLOCK */ + return IsSocketErrorWouldBlock(code); +#endif +} + +constexpr bool +IsSocketErrorAcceptWouldBlock(socket_error_t code) noexcept +{ +#ifdef _WIN32 + /* on Windows, WSAEINPROGRESS is for blocking sockets and + WSAEWOULDBLOCK for non-blocking sockets */ + return IsSocketErrorInProgress(code) || IsSocketErrorWouldBlock(code); +#else + /* on all other operating systems, there's just + EAGAIN==EWOULDBLOCK */ + return IsSocketErrorWouldBlock(code); +#endif +} + +constexpr bool +IsSocketErrorInterruped(socket_error_t code) noexcept +{ +#ifdef _WIN32 + return code == WSAEINTR; +#else + return code == EINTR; +#endif +} + +constexpr bool +IsSocketErrorClosed(socket_error_t code) noexcept +{ +#ifdef _WIN32 + return code == WSAECONNRESET; +#else + return code == EPIPE || code == ECONNRESET; +#endif +} + +constexpr bool +IsSocketErrorTimeout(socket_error_t code) noexcept +{ +#ifdef _WIN32 + return code == WSAETIMEDOUT; +#else + return code == ETIMEDOUT; +#endif +} + +/** + * Helper class that formats a socket error message into a + * human-readable string. On Windows, a buffer is necessary for this, + * and this class hosts the buffer. + */ +class SocketErrorMessage { +#ifdef _WIN32 + static constexpr unsigned msg_size = 256; + char msgmsg_size; +#else + const char *const msg; +#endif + +public: + explicit SocketErrorMessage(socket_error_t code=GetSocketError()) noexcept; + + operator const char *() const { + return msg; + } +}; + +/** + * Returns the error_category to be used to wrap socket errors. + */ +gnu::const +static inline const std::error_category & +SocketErrorCategory() noexcept +{ +#ifdef _WIN32 + return LastErrorCategory(); +#else + return ErrnoCategory(); +#endif +} + +gnu::pure +static inline bool +IsSocketErrorReceiveWouldBlock(const std::system_error &e) noexcept +{ + return e.code().category() == SocketErrorCategory() && + IsSocketErrorReceiveWouldBlock(e.code().value()); +} + +gnu::pure +static inline auto +MakeSocketError(socket_error_t code, const char *msg) noexcept +{ +#ifdef _WIN32 + return MakeLastError(code, msg); +#else + return MakeErrno(code, msg); +#endif +} + +gnu::pure +static inline auto +MakeSocketError(const char *msg) noexcept +{ + return MakeSocketError(GetSocketError(), msg); +}
View file
ncmpc-0.47.tar.xz/src/net/StaticSocketAddress.cxx
Added
@@ -0,0 +1,80 @@ +/* + * Copyright 2012-2019 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "StaticSocketAddress.hxx" +#include "IPv4Address.hxx" +#include "IPv6Address.hxx" + +#include <algorithm> + +#include <string.h> + +StaticSocketAddress & +StaticSocketAddress::operator=(SocketAddress other) noexcept +{ + size = std::min(other.GetSize(), GetCapacity()); + memcpy(&address, other.GetAddress(), size); + return *this; +} + +#ifdef HAVE_UN + +std::string_view +StaticSocketAddress::GetLocalRaw() const noexcept +{ + return SocketAddress(*this).GetLocalRaw(); +} + +#endif + +#ifdef HAVE_TCP + +bool +StaticSocketAddress::SetPort(unsigned port) noexcept +{ + switch (GetFamily()) { + case AF_INET: + { + auto &a = *(IPv4Address *)(void *)&address; + a.SetPort(port); + return true; + } + + case AF_INET6: + { + auto &a = *(IPv6Address *)(void *)&address; + a.SetPort(port); + return true; + } + } + + return false; +} + +#endif
View file
ncmpc-0.47.tar.xz/src/net/StaticSocketAddress.hxx
Added
@@ -0,0 +1,151 @@ +/* + * Copyright 2012-2021 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STATIC_SOCKET_ADDRESS_HXX +#define STATIC_SOCKET_ADDRESS_HXX + +#include "SocketAddress.hxx" // IWYU pragma: export +#include "Features.hxx" + +#include <cassert> +#include <string_view> + +/** + * An OO wrapper for struct sockaddr_storage. + */ +class StaticSocketAddress { + friend class SocketDescriptor; + +public: + typedef SocketAddress::size_type size_type; + +private: + size_type size; + struct sockaddr_storage address; + +public: + StaticSocketAddress() = default; + + StaticSocketAddress &operator=(SocketAddress other) noexcept; + + constexpr operator SocketAddress() const noexcept { + return SocketAddress(*this, size); + } + + constexpr operator struct sockaddr *() noexcept { + return (struct sockaddr *)(void *)&address; + } + + constexpr operator const struct sockaddr *() const noexcept { + return (const struct sockaddr *)(const void *)&address; + } + + /** + * Cast the "sockaddr" pointer to a different address type, + * e.g. "sockaddr_in". This is only legal after checking + * GetFamily(). + */ + template<typename T> + constexpr const T &CastTo() const noexcept { + /* cast through void to work around the bogus + alignment warning */ + const void *q = reinterpret_cast<const void *>(&address); + return *reinterpret_cast<const T *>(q); + } + + constexpr size_type GetCapacity() const noexcept { + return sizeof(address); + } + + size_type GetSize() const noexcept { + return size; + } + + void SetSize(size_type _size) noexcept { + assert(_size > 0); + assert(size_t(_size) <= sizeof(address)); + + size = _size; + } + + /** + * Set the size to the maximum value for this class. + */ + void SetMaxSize() { + SetSize(GetCapacity()); + } + + int GetFamily() const noexcept { + return address.ss_family; + } + + bool IsDefined() const noexcept { + return GetFamily() != AF_UNSPEC; + } + + void Clear() noexcept { + size = sizeof(address.ss_family); + address.ss_family = AF_UNSPEC; + } + +#ifdef HAVE_UN + /** + * @see SocketAddress::GetLocalRaw() + */ + gnu::pure + std::string_view GetLocalRaw() const noexcept; +#endif + +#ifdef HAVE_TCP + /** + * Extract the port number. Returns 0 if not applicable. + */ + gnu::pure + unsigned GetPort() const noexcept { + return ((SocketAddress)*this).GetPort(); + } + + /** + * @return true on success, false if this address cannot have + * a port number + */ + bool SetPort(unsigned port) noexcept; +#endif + + gnu::pure + bool operator==(SocketAddress other) const noexcept { + return (SocketAddress)*this == other; + } + + bool operator!=(SocketAddress other) const noexcept { + return !(*this == other); + } +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/net/UniqueSocketDescriptor.hxx
Added
@@ -0,0 +1,113 @@ +/* + * Copyright 2012-2019 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UNIQUE_SOCKET_DESCRIPTOR_SOCKET_HXX +#define UNIQUE_SOCKET_DESCRIPTOR_SOCKET_HXX + +#include "SocketDescriptor.hxx" + +#include <utility> + +class StaticSocketAddress; + +/** + * Wrapper for a socket file descriptor. + */ +class UniqueSocketDescriptor : public SocketDescriptor { +public: + UniqueSocketDescriptor() noexcept + :SocketDescriptor(SocketDescriptor::Undefined()) {} + + explicit UniqueSocketDescriptor(SocketDescriptor _fd) noexcept + :SocketDescriptor(_fd) {} + explicit UniqueSocketDescriptor(FileDescriptor _fd) noexcept + :SocketDescriptor(_fd) {} + explicit UniqueSocketDescriptor(int _fd) noexcept + :SocketDescriptor(_fd) {} + + UniqueSocketDescriptor(UniqueSocketDescriptor &&other) noexcept + :SocketDescriptor(std::exchange(other.fd, -1)) {} + + ~UniqueSocketDescriptor() noexcept { + if (IsDefined()) + Close(); + } + + /** + * Release ownership and return the descriptor as an unmanaged + * #SocketDescriptor instance. + */ + SocketDescriptor Release() noexcept { + return std::exchange(*(SocketDescriptor *)this, Undefined()); + } + + UniqueSocketDescriptor &operator=(UniqueSocketDescriptor &&src) noexcept { + using std::swap; + swap(fd, src.fd); + return *this; + } + + bool operator==(const UniqueSocketDescriptor &other) const noexcept { + return fd == other.fd; + } + + /** + * @return an "undefined" instance on error + */ + UniqueSocketDescriptor AcceptNonBlock() const noexcept { + return UniqueSocketDescriptor(SocketDescriptor::AcceptNonBlock()); + } + + /** + * @return an "undefined" instance on error + */ + UniqueSocketDescriptor AcceptNonBlock(StaticSocketAddress &address) const noexcept { + return UniqueSocketDescriptor(SocketDescriptor::AcceptNonBlock(address)); + } + +#ifndef _WIN32 + static bool CreateSocketPair(int domain, int type, int protocol, + UniqueSocketDescriptor &a, + UniqueSocketDescriptor &b) noexcept { + return SocketDescriptor::CreateSocketPair(domain, type, + protocol, + a, b); + } + + static bool CreateSocketPairNonBlock(int domain, int type, int protocol, + UniqueSocketDescriptor &a, + UniqueSocketDescriptor &b) noexcept { + return SocketDescriptor::CreateSocketPairNonBlock(domain, type, + protocol, + a, b); + } +#endif +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/net/meson.build
Added
@@ -0,0 +1,19 @@ +net = static_library( + 'net', + 'HostParser.cxx', + 'Resolver.cxx', + 'AddressInfo.cxx', + 'AllocatedSocketAddress.cxx', + 'IPv4Address.cxx', + 'IPv6Address.cxx', + 'SocketAddress.cxx', + 'SocketDescriptor.cxx', + include_directories: inc, +) + +net_dep = declare_dependency( + link_with: net, + dependencies: + system_dep, + , +)
View file
ncmpc-0.36.tar.xz/src/paint.hxx -> ncmpc-0.47.tar.xz/src/paint.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/player_command.cxx -> ncmpc-0.47.tar.xz/src/player_command.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -35,27 +34,20 @@ seek.Cancel(); switch(cmd) { - struct mpd_connection *connection; - /* case Command::PLAY: mpdclient_cmd_play(c, MPD_PLAY_AT_BEGINNING); break; */ case Command::PAUSE: - connection = c.GetConnection(); - if (connection == nullptr) - break; - - if (!mpd_run_pause(connection, c.state != MPD_STATE_PAUSE)) + if (auto *connection = c.GetConnection(); + connection != nullptr && + !mpd_run_pause(connection, c.state != MPD_STATE_PAUSE)) c.HandleError(); break; case Command::STOP: - connection = c.GetConnection(); - if (connection == nullptr) - break; - - if (!mpd_run_stop(connection)) + if (auto *connection = c.GetConnection(); + connection != nullptr && !mpd_run_stop(connection)) c.HandleError(); break; case Command::CROP: @@ -66,11 +58,8 @@ break; case Command::TRACK_NEXT: - connection = c.GetConnection(); - if (connection == nullptr) - break; - - if (!mpd_run_next(connection)) + if (auto *connection = c.GetConnection(); + connection != nullptr && !mpd_run_next(connection)) c.HandleError(); break; case Command::SEEK_BACKWARD: @@ -78,69 +67,55 @@ break; case Command::TRACK_PREVIOUS: - connection = c.GetConnection(); - if (connection == nullptr) - break; - - if (!mpd_run_previous(connection)) + if (auto *connection = c.GetConnection(); + connection != nullptr && !mpd_run_previous(connection)) c.HandleError(); break; case Command::SHUFFLE: - connection = c.GetConnection(); - if (connection == nullptr) - break; + if (auto *connection = c.GetConnection()) { + if (mpd_run_shuffle(connection)) + screen_status_message(_("Shuffled queue")); + else + c.HandleError(); + } - if (mpd_run_shuffle(connection)) - screen_status_message(_("Shuffled queue")); - else - c.HandleError(); break; case Command::CLEAR: if (c.RunClearQueue()) screen_status_message(_("Cleared queue")); break; case Command::REPEAT: - connection = c.GetConnection(); - if (connection == nullptr) - break; - - if (!mpd_run_repeat(connection, + if (auto *connection = c.GetConnection(); + connection != nullptr && + !mpd_run_repeat(connection, !mpd_status_get_repeat(c.status))) c.HandleError(); break; case Command::RANDOM: - connection = c.GetConnection(); - if (connection == nullptr) - break; - - if (!mpd_run_random(connection, + if (auto *connection = c.GetConnection(); + connection != nullptr && + !mpd_run_random(connection, !mpd_status_get_random(c.status))) c.HandleError(); break; case Command::SINGLE: - connection = c.GetConnection(); - if (connection == nullptr) - break; - - if (!mpd_run_single(connection, + if (auto *connection = c.GetConnection(); + connection != nullptr && + !mpd_run_single(connection, !mpd_status_get_single(c.status))) c.HandleError(); break; case Command::CONSUME: - connection = c.GetConnection(); - if (connection == nullptr) - break; - - if (!mpd_run_consume(connection, + if (auto *connection = c.GetConnection(); + connection != nullptr && + !mpd_run_consume(connection, !mpd_status_get_consume(c.status))) c.HandleError(); break; case Command::CROSSFADE: - connection = c.GetConnection(); - if (connection == nullptr) - break; - - if (!mpd_run_crossfade(connection, + if (auto *connection = c.GetConnection(); + connection != nullptr && + !mpd_run_crossfade(connection, mpd_status_get_crossfade(c.status) > 0 ? 0 : options.crossfade_time)) c.HandleError();
View file
ncmpc-0.36.tar.xz/src/player_command.hxx -> ncmpc-0.47.tar.xz/src/player_command.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/plugin.cxx -> ncmpc-0.47.tar.xz/src/plugin.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -19,12 +18,12 @@ #include "plugin.hxx" #include "io/Path.hxx" +#include "io/UniqueFileDescriptor.hxx" +#include "event/PipeEvent.hxx" +#include "event/CoarseTimerEvent.hxx" #include "util/ScopeExit.hxx" #include "util/UriUtil.hxx" -#include <boost/asio/steady_timer.hpp> -#include <boost/asio/posix/stream_descriptor.hpp> - #include <algorithm> #include <memory> @@ -42,37 +41,32 @@ PluginCycle &cycle; /** the pipe to the plugin process */ - boost::asio::posix::stream_descriptor fd; + PipeEvent socket_event; /** the output of the current plugin */ std::string data; - std::array<char, 256> buffer; - public: - PluginPipe(boost::asio::io_service &io_service, + PluginPipe(EventLoop &event_loop, PluginCycle &_cycle) noexcept - :cycle(_cycle), fd(io_service) {} + :cycle(_cycle), + socket_event(event_loop, BIND_THIS_METHOD(OnRead)) {} ~PluginPipe() noexcept { - Close(); + socket_event.Close(); } - void Start(int _fd) noexcept { - fd.assign(_fd); - AsyncRead(); + void Start(UniqueFileDescriptor &&fd) noexcept { + socket_event.Open(fd.Release()); + socket_event.ScheduleRead(); } void Close() noexcept { - if (!fd.is_open()) - return; - - fd.cancel(); - fd.close(); + socket_event.Close(); } bool IsOpen() const noexcept { - return fd.is_open(); + return socket_event.IsDefined(); } bool IsEmpty() const noexcept { @@ -88,15 +82,7 @@ } private: - void AsyncRead() noexcept { - fd.async_read_some(boost::asio::buffer(buffer), - std::bind(&PluginPipe::OnRead, this, - std::placeholders::_1, - std::placeholders::_2)); - } - - void OnRead(const boost::system::error_code &error, - std::size_t bytes_transferred) noexcept; + void OnRead(unsigned events) noexcept; }; struct PluginCycle { @@ -125,28 +111,23 @@ /** list of all error messages from failed plugins */ std::string all_errors; - boost::asio::steady_timer delayed_fail_timer; + CoarseTimerEvent delayed_fail_timer; - PluginCycle(boost::asio::io_service &io_service, + PluginCycle(EventLoop &event_loop, const PluginList &_list, std::unique_ptr<char *> &&_argv, PluginResponseHandler &_handler) noexcept :list(_list), argv(std::move(_argv)), handler(_handler), - pipe_stdout(io_service, *this), - pipe_stderr(io_service, *this), - delayed_fail_timer(io_service) {} + pipe_stdout(event_loop, *this), + pipe_stderr(event_loop, *this), + delayed_fail_timer(event_loop, BIND_THIS_METHOD(OnDelayedFail)) {} void TryNextPlugin() noexcept; void Stop() noexcept; void ScheduleDelayedFail() noexcept { - boost::system::error_code error; - delayed_fail_timer.expires_from_now(std::chrono::seconds(0), - error); - delayed_fail_timer.async_wait(std::bind(&PluginCycle::OnDelayedFail, - this, - std::placeholders::_1)); + delayed_fail_timer.Schedule(std::chrono::seconds(0)); } void OnEof() noexcept; @@ -154,7 +135,7 @@ private: int LaunchPlugin(const char *plugin_path) noexcept; - void OnDelayedFail(const boost::system::error_code &error) noexcept; + void OnDelayedFail() noexcept; }; static bool @@ -231,22 +212,19 @@ } void -PluginPipe::OnRead(const boost::system::error_code &error, - std::size_t bytes_transferred) noexcept +PluginPipe::OnRead(unsigned) noexcept { - if (error) { - if (error == boost::asio::error::operation_aborted) - /* this object has already been deleted; bail out - quickly without touching anything */ - return; - - fd.close(); + char buffer256; + ssize_t nbytes = socket_event.GetFileDescriptor().Read(buffer, + sizeof(buffer)); + if (nbytes <= 0) { + socket_event.Close(); cycle.OnEof(); return; } - data.append(&buffer.front(), bytes_transferred); - AsyncRead(); + data.append(buffer, nbytes); + socket_event.ScheduleRead(); } /** @@ -257,11 +235,8 @@ * moment after. */ void -PluginCycle::OnDelayedFail(const boost::system::error_code &error) noexcept +PluginCycle::OnDelayedFail() noexcept { - if (error) - return; - assert(!pipe_stdout.IsOpen()); assert(!pipe_stderr.IsOpen()); assert(pid < 0); @@ -282,34 +257,25 @@ plugin */ argv0 = const_cast<char *>(GetUriFilename(plugin_path)); - int fds_stdout2; - if (pipe(fds_stdout) < 0) - return -1; - - int fds_stderr2; - if (pipe(fds_stderr) < 0) { - close(fds_stdout0); - close(fds_stdout1); + UniqueFileDescriptor stdout_r, stdout_w; + UniqueFileDescriptor stderr_r, stderr_w; + if (!UniqueFileDescriptor::CreatePipe(stdout_r, stdout_w) || + !UniqueFileDescriptor::CreatePipe(stderr_r, stderr_w)) return -1; - } pid = fork(); - if (pid < 0) { - close(fds_stdout0); - close(fds_stdout1); - close(fds_stderr0); - close(fds_stderr1); + if (pid < 0) return -1; - } if (pid == 0) { - dup2(fds_stdout1, 1); - dup2(fds_stderr1, 2); - close(fds_stdout0); - close(fds_stdout1); - close(fds_stderr0); - close(fds_stderr1); + stdout_w.Duplicate(FileDescriptor(STDOUT_FILENO)); + stderr_w.Duplicate(FileDescriptor(STDERR_FILENO)); + + stdout_r.Close(); + stdout_w.Close(); + stderr_r.Close(); + stderr_w.Close(); close(0); /* XXX close other fds? */ @@ -317,13 +283,10 @@ _exit(1); } - close(fds_stdout1); - close(fds_stderr1); - /* XXX CLOEXEC? */ - pipe_stdout.Start(fds_stdout0); - pipe_stderr.Start(fds_stderr0); + pipe_stdout.Start(std::move(stdout_r)); + pipe_stderr.Start(std::move(stderr_r)); return 0; } @@ -377,13 +340,13 @@ } PluginCycle * -plugin_run(boost::asio::io_service &io_service, - PluginList *list, const char *const*args, +plugin_run(EventLoop &event_loop, + const PluginList &list, const char *const*args, PluginResponseHandler &handler) noexcept { assert(args != nullptr); - auto *cycle = new PluginCycle(io_service, *list, make_argv(args), + auto *cycle = new PluginCycle(event_loop, list, make_argv(args), handler); cycle->TryNextPlugin(); @@ -409,7 +372,7 @@ } void -plugin_stop(PluginCycle *cycle) noexcept +plugin_stop(PluginCycle &cycle) noexcept { - cycle->Stop(); + cycle.Stop(); }
View file
ncmpc-0.36.tar.xz/src/plugin.hxx -> ncmpc-0.47.tar.xz/src/plugin.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,11 +19,11 @@ #ifndef PLUGIN_H #define PLUGIN_H -#include "AsioServiceFwd.hxx" - #include <vector> #include <string> +class EventLoop; + /** * When a plugin cycle is finished, one method of this class is called. In any * case, plugin_stop() has to be called to free all memory. @@ -71,8 +70,8 @@ * available */ PluginCycle * -plugin_run(boost::asio::io_service &io_service, - PluginList *list, const char *const*args, +plugin_run(EventLoop &event_loop, + const PluginList &list, const char *const*args, PluginResponseHandler &handler) noexcept; /** @@ -81,6 +80,6 @@ * invoked. */ void -plugin_stop(PluginCycle *invocation) noexcept; +plugin_stop(PluginCycle &invocation) noexcept; #endif
View file
ncmpc-0.36.tar.xz/src/save_playlist.cxx -> ncmpc-0.47.tar.xz/src/save_playlist.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -26,7 +25,6 @@ #include "mpdclient.hxx" #include "Completion.hxx" #include "screen_utils.hxx" -#include "util/Compiler.h" #include <mpd/client.h> @@ -48,7 +46,7 @@ }; void -PlaylistNameCompletion::Pre(gcc_unused const char *value) noexcept +PlaylistNameCompletion::Pre(maybe_unused const char *value) noexcept { if (empty()) { /* create completion list */ @@ -57,7 +55,7 @@ } void -PlaylistNameCompletion::Post(gcc_unused const char *value, +PlaylistNameCompletion::Post(maybe_unused const char *value, Range range) noexcept { if (range.begin() != range.end() &&
View file
ncmpc-0.36.tar.xz/src/save_playlist.hxx -> ncmpc-0.47.tar.xz/src/save_playlist.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/screen.cxx -> ncmpc-0.47.tar.xz/src/screen.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -96,7 +95,7 @@ Switch(*mode_fn_prev, c); } -gcc_pure +gnu::pure static int find_configured_screen(const char *name) noexcept { @@ -223,7 +222,7 @@ /* update the main window */ current_page->second->Update(c); - Paint(current_page->second->IsDirty()); + SchedulePaint(); } void
View file
ncmpc-0.36.tar.xz/src/screen.hxx -> ncmpc-0.47.tar.xz/src/screen.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -27,8 +26,7 @@ #include "StatusBar.hxx" #include "History.hxx" #include "Point.hxx" -#include "util/Compiler.h" -#include "AsioServiceFwd.hxx" +#include "event/IdleEvent.hxx" #include <curses.h> @@ -43,9 +41,14 @@ struct PageMeta; class Page; class DelayedSeek; +class EventLoop; class ScreenManager { - boost::asio::io_service &io_service; + /** + * This event defers Paint() calls until after the EventLoop + * has handled all other events. + */ + IdleEvent paint_event; struct Layout { Size size; @@ -102,11 +105,11 @@ std::string findbuf; History find_history; - explicit ScreenManager(boost::asio::io_service &io_service) noexcept; + explicit ScreenManager(EventLoop &_event_loop) noexcept; ~ScreenManager() noexcept; - auto &get_io_service() const noexcept { - return io_service; + auto &GetEventLoop() const noexcept { + return paint_event.GetEventLoop(); } void Init(struct mpdclient *c) noexcept; @@ -124,7 +127,7 @@ void OnResize() noexcept; - gcc_pure + gnu::pure bool IsVisible(const Page &page) const noexcept { return &page == current_page->second.get(); } @@ -133,7 +136,6 @@ void Swap(struct mpdclient &c, const struct mpd_song *song) noexcept; void PaintTopWindow() noexcept; - void Paint(bool main_dirty) noexcept; void Update(struct mpdclient &c, const DelayedSeek &seek) noexcept; void OnCommand(struct mpdclient &c, DelayedSeek &seek, Command cmd); @@ -143,8 +145,14 @@ Point p, mmask_t bstate); #endif + void SchedulePaint() noexcept { + paint_event.Schedule(); + } + private: void NextMode(struct mpdclient &c, int offset) noexcept; + + void Paint() noexcept; }; #endif
View file
ncmpc-0.36.tar.xz/src/screen_client.cxx -> ncmpc-0.47.tar.xz/src/screen_client.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/screen_client.hxx -> ncmpc-0.47.tar.xz/src/screen_client.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/screen_find.cxx -> ncmpc-0.47.tar.xz/src/screen_find.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -134,5 +133,5 @@ screen.findbuf = search_str; /* ncmpc should get the command */ - keyboard_unread(screen.get_io_service(), key); + keyboard_unread(screen.GetEventLoop(), key); }
View file
ncmpc-0.36.tar.xz/src/screen_find.hxx -> ncmpc-0.47.tar.xz/src/screen_find.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/screen_init.cxx -> ncmpc-0.47.tar.xz/src/screen_init.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -28,14 +27,14 @@ static const unsigned SCREEN_MIN_COLS = 14; static const unsigned SCREEN_MIN_ROWS = 5; -ScreenManager::ScreenManager(boost::asio::io_service &_io_service) noexcept - :io_service(_io_service), +ScreenManager::ScreenManager(EventLoop &event_loop) noexcept + :paint_event(event_loop, BIND_THIS_METHOD(Paint)), layout({std::max<unsigned>(COLS, SCREEN_MIN_COLS), std::max<unsigned>(LINES, SCREEN_MIN_ROWS)}), title_bar({layout.title_x, layout.title_y}, layout.size.width), main_window({layout.main_x, layout.main_y}, layout.GetMainSize()), progress_bar({layout.progress_x, layout.GetProgressY()}, layout.size.width), - status_bar(io_service, + status_bar(event_loop, {layout.status_x, layout.GetStatusY()}, layout.size.width), mode_fn_prev(&screen_queue) { @@ -50,8 +49,7 @@ #ifdef ENABLE_COLORS if (options.enable_colors) { /* set background attributes */ - wbkgd(stdscr, COLOR_PAIR(Style::LIST)); - wbkgd(main_window.w, COLOR_PAIR(Style::LIST)); + main_window.SetBackgroundStyle(Style::LIST); } #endif } @@ -105,7 +103,7 @@ curs_set(1); curs_set(0); - Paint(true); + SchedulePaint(); } void
View file
ncmpc-0.36.tar.xz/src/screen_list.cxx -> ncmpc-0.47.tar.xz/src/screen_list.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -26,12 +25,14 @@ #include "SearchPage.hxx" #include "SongPage.hxx" #include "KeyDefPage.hxx" +#include "EditPlaylistPage.hxx" #include "LyricsPage.hxx" #include "OutputsPage.hxx" #include "ChatPage.hxx" -#include "util/Macros.hxx" #include "config.h" +#include <iterator> + #include <string.h> static const PageMeta *const screens = { @@ -61,12 +62,15 @@ #ifdef ENABLE_KEYDEF_SCREEN &screen_keydef, #endif +#ifdef ENABLE_PLAYLIST_EDITOR + &edit_playlist_page, +#endif }; const PageMeta * GetPageMeta(unsigned i) noexcept { - return i < ARRAY_SIZE(screens) + return i < std::size(screens) ? screensi : nullptr; }
View file
ncmpc-0.36.tar.xz/src/screen_list.hxx -> ncmpc-0.47.tar.xz/src/screen_list.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,20 +19,18 @@ #ifndef SCREEN_LIST_H #define SCREEN_LIST_H -#include "util/Compiler.h" - enum class Command : unsigned; struct PageMeta; -gcc_const +gnu::const const PageMeta * GetPageMeta(unsigned i) noexcept; -gcc_pure +gnu::pure const PageMeta * screen_lookup_name(const char *name) noexcept; -gcc_const +gnu::const const PageMeta * PageByCommand(Command cmd) noexcept;
View file
ncmpc-0.36.tar.xz/src/screen_paint.cxx -> ncmpc-0.47.tar.xz/src/screen_paint.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -33,7 +32,7 @@ } void -ScreenManager::Paint(bool main_dirty) noexcept +ScreenManager::Paint() noexcept { /* update title/header window */ PaintTopWindow(); @@ -47,7 +46,7 @@ /* paint the main window */ - if (main_dirty) { + if (current_page->second->IsDirty()) { current_page->second->Paint(); current_page->second->SetDirty(false); }
View file
ncmpc-0.36.tar.xz/src/screen_status.cxx -> ncmpc-0.47.tar.xz/src/screen_status.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,6 +19,7 @@ #include "screen_status.hxx" #include "screen.hxx" #include "ncmpc.hxx" +#include "util/Exception.hxx" #include <stdarg.h> @@ -39,3 +39,9 @@ va_end(ap); screen_status_message(msg); } + +void +screen_status_error(std::exception_ptr e) noexcept +{ + screen_status_message(GetFullMessage(std::move(e)).c_str()); +}
View file
ncmpc-0.36.tar.xz/src/screen_status.hxx -> ncmpc-0.47.tar.xz/src/screen_status.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -22,6 +21,8 @@ #include "util/Compiler.h" +#include <exception> + void screen_status_message(const char *msg) noexcept; @@ -29,4 +30,7 @@ void screen_status_printf(const char *format, ...) noexcept; +void +screen_status_error(std::exception_ptr e) noexcept; + #endif
View file
ncmpc-0.36.tar.xz/src/screen_utils.cxx -> ncmpc-0.47.tar.xz/src/screen_utils.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -29,6 +28,7 @@ #ifndef _WIN32 #include "WaitUserInput.hxx" +#include <cerrno> #endif #include <string.h>
View file
ncmpc-0.36.tar.xz/src/screen_utils.hxx -> ncmpc-0.47.tar.xz/src/screen_utils.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/signals.cxx -> ncmpc-0.47.tar.xz/src/signals.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -17,10 +16,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include <signal.h> #include "Instance.hxx" void -Instance::OnSigwinch() +Instance::OnSigwinch() noexcept { endwin(); refresh(); @@ -28,22 +28,8 @@ } void -Instance::AsyncWaitSigwinch() -{ - sigwinch.async_wait(this(const auto &error, int){ - if (error) - return; - - this->OnSigwinch(); - this->AsyncWaitSigwinch(); - }); -} - -void Instance::InitSignals() { - AsyncWaitSigwinch(); - /* ignore SIGPIPE */ struct sigaction act;
View file
ncmpc-0.36.tar.xz/src/strfsong.cxx -> ncmpc-0.47.tar.xz/src/strfsong.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -29,7 +28,7 @@ #include <string.h> -gcc_pure +gnu::pure static const char * skip(const char *p) noexcept { @@ -195,6 +194,14 @@ tag = MPD_TAG_COMPOSER; else if (strncmp("%performer%", p, n) == 0) tag = MPD_TAG_PERFORMER; +#if LIBMPDCLIENT_CHECK_VERSION(2,17,0) + else if (strncmp("%conductor%", p, n) == 0) + tag = MPD_TAG_CONDUCTOR; + else if (strncmp("%work%", p, n) == 0) + tag = MPD_TAG_WORK; + else if (strncmp("%grouping%", p, n) == 0) + tag = MPD_TAG_GROUPING; +#endif else if (strncmp("%title%", p, n) == 0) tag = MPD_TAG_TITLE; else if (strncmp("%album%", p, n) == 0)
View file
ncmpc-0.36.tar.xz/src/strfsong.hxx -> ncmpc-0.47.tar.xz/src/strfsong.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,8 +19,6 @@ #ifndef STRFSONG_H #define STRFSONG_H -#include "util/Compiler.h" - #include <stddef.h> struct mpd_song; @@ -34,7 +31,7 @@ /** * Check which tags are referenced by the given song format. */ -gcc_pure +gnu::pure TagMask SongFormatToTagMask(const char *format) noexcept;
View file
ncmpc-0.47.tar.xz/src/system
Added
+(directory)
View file
ncmpc-0.47.tar.xz/src/system/EpollFD.cxx
Added
@@ -0,0 +1,38 @@ +/* + * Copyright 2013-2018 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "EpollFD.hxx" +#include "Error.hxx" + +EpollFD::EpollFD() + :fd(::epoll_create1(EPOLL_CLOEXEC)) +{ + if (!fd.IsDefined()) + throw MakeErrno("epoll_create1() failed"); +}
View file
ncmpc-0.47.tar.xz/src/system/EpollFD.hxx
Added
@@ -0,0 +1,83 @@ +/* + * Copyright 2013-2020 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EPOLL_FD_HXX +#define EPOLL_FD_HXX + +#include "io/UniqueFileDescriptor.hxx" + +#include <cstdint> + +#include <sys/epoll.h> + +/** + * A class that wraps Linux epoll. + */ +class EpollFD { + UniqueFileDescriptor fd; + +public: + /** + * Throws on error. + */ + EpollFD(); + + EpollFD(EpollFD &&) = default; + EpollFD &operator=(EpollFD &&) = default; + + int Wait(epoll_event *events, int maxevents, int timeout) noexcept { + return ::epoll_wait(fd.Get(), events, maxevents, timeout); + } + + bool Control(int op, int _fd, epoll_event *event) noexcept { + return ::epoll_ctl(fd.Get(), op, _fd, event) >= 0; + } + + bool Add(int _fd, uint32_t events, void *ptr) noexcept { + epoll_event e; + e.events = events; + e.data.ptr = ptr; + + return Control(EPOLL_CTL_ADD, _fd, &e); + } + + bool Modify(int _fd, uint32_t events, void *ptr) noexcept { + epoll_event e; + e.events = events; + e.data.ptr = ptr; + + return Control(EPOLL_CTL_MOD, _fd, &e); + } + + bool Remove(int _fd) noexcept { + return Control(EPOLL_CTL_DEL, _fd, nullptr); + } +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/system/Error.hxx
Added
@@ -0,0 +1,224 @@ +/* + * Copyright 2013-2022 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <system_error> // IWYU pragma: export +#include <utility> + +#include <stdio.h> + +template<typename... Args> +static inline std::system_error +FormatSystemError(std::error_code code, const char *fmt, + Args&&... args) noexcept +{ + char buffer1024; + snprintf(buffer, sizeof(buffer), fmt, std::forward<Args>(args)...); + return std::system_error(code, buffer); +} + +#ifdef _WIN32 + +#include <errhandlingapi.h> // for GetLastError() +#include <windef.h> // for HWND (needed by winbase.h) +#include <winbase.h> // for FormatMessageA() + +/** + * Returns the error_category to be used to wrap WIN32 GetLastError() + * values. The C++ standard does not define this well, and this value + * is mostly guessed. + * + * TODO: verify + */ +gnu::const +static inline const std::error_category & +LastErrorCategory() noexcept +{ + return std::system_category(); +} + +gnu::pure +inline bool +IsLastError(const std::system_error &e, DWORD code) noexcept +{ + return e.code().category() == LastErrorCategory() && + (DWORD)e.code().value() == code; +} + +static inline std::system_error +MakeLastError(DWORD code, const char *msg) noexcept +{ + return std::system_error(std::error_code(code, LastErrorCategory()), + msg); +} + +static inline std::system_error +MakeLastError(const char *msg) noexcept +{ + return MakeLastError(GetLastError(), msg); +} + +template<typename... Args> +static inline std::system_error +FormatLastError(DWORD code, const char *fmt, Args&&... args) noexcept +{ + char buffer512; + const auto end = buffer + sizeof(buffer); + size_t length = snprintf(buffer, sizeof(buffer) - 128, + fmt, std::forward<Args>(args)...); + char *p = buffer + length; + *p++ = ':'; + *p++ = ' '; + + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, code, 0, p, end - p, nullptr); + return MakeLastError(code, buffer); +} + +template<typename... Args> +static inline std::system_error +FormatLastError(const char *fmt, Args&&... args) noexcept +{ + return FormatLastError(GetLastError(), fmt, + std::forward<Args>(args)...); +} + +#endif /* _WIN32 */ + +#include <cerrno> // IWYU pragma: export + +#include <string.h> + +/** + * Returns the error_category to be used to wrap errno values. The + * C++ standard does not define this well, so this code is based on + * observations what C++ standard library implementations actually + * use. + * + * @see https://stackoverflow.com/questions/28746372/system-error-categories-and-standard-system-error-codes + */ +gnu::const +static inline const std::error_category & +ErrnoCategory() noexcept +{ +#ifdef _WIN32 + /* on Windows, the generic_category() is used for errno + values */ + return std::generic_category(); +#else + /* on POSIX, system_category() appears to be the best + choice */ + return std::system_category(); +#endif +} + +static inline std::system_error +MakeErrno(int code, const char *msg) noexcept +{ + return std::system_error(std::error_code(code, ErrnoCategory()), + msg); +} + +static inline std::system_error +MakeErrno(const char *msg) noexcept +{ + return MakeErrno(errno, msg); +} + +template<typename... Args> +static inline std::system_error +FormatErrno(int code, const char *fmt, Args&&... args) noexcept +{ + char buffer512; + snprintf(buffer, sizeof(buffer), + fmt, std::forward<Args>(args)...); + return MakeErrno(code, buffer); +} + +template<typename... Args> +static inline std::system_error +FormatErrno(const char *fmt, Args&&... args) noexcept +{ + return FormatErrno(errno, fmt, std::forward<Args>(args)...); +} + +template<typename... Args> +static inline std::system_error +FormatFileNotFound(const char *fmt, Args&&... args) noexcept +{ +#ifdef _WIN32 + return FormatLastError(ERROR_FILE_NOT_FOUND, fmt, + std::forward<Args>(args)...); +#else + return FormatErrno(ENOENT, fmt, std::forward<Args>(args)...); +#endif +} + +gnu::pure +inline bool +IsErrno(const std::system_error &e, int code) noexcept +{ + return e.code().category() == ErrnoCategory() && + e.code().value() == code; +} + +gnu::pure +static inline bool +IsFileNotFound(const std::system_error &e) noexcept +{ +#ifdef _WIN32 + return IsLastError(e, ERROR_FILE_NOT_FOUND); +#else + return IsErrno(e, ENOENT); +#endif +} + +gnu::pure +static inline bool +IsPathNotFound(const std::system_error &e) noexcept +{ +#ifdef _WIN32 + return IsLastError(e, ERROR_PATH_NOT_FOUND); +#else + return IsErrno(e, ENOTDIR); +#endif +} + +gnu::pure +static inline bool +IsAccessDenied(const std::system_error &e) noexcept +{ +#ifdef _WIN32 + return IsLastError(e, ERROR_ACCESS_DENIED); +#else + return IsErrno(e, EACCES); +#endif +}
View file
ncmpc-0.47.tar.xz/src/system/EventFD.cxx
Added
@@ -0,0 +1,60 @@ +/* + * Copyright 2013-2018 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "EventFD.hxx" +#include "system/Error.hxx" + +#include <cassert> + +#include <sys/eventfd.h> + +EventFD::EventFD() +{ + if (!fd.CreateEventFD(0)) + throw MakeErrno("eventfd() failed"); +} + +bool +EventFD::Read() noexcept +{ + assert(fd.IsDefined()); + + eventfd_t value; + return fd.Read(&value, sizeof(value)) == (ssize_t)sizeof(value); +} + +void +EventFD::Write() noexcept +{ + assert(fd.IsDefined()); + + static constexpr eventfd_t value = 1; + maybe_unused ssize_t nbytes = + fd.Write(&value, sizeof(value)); +}
View file
ncmpc-0.47.tar.xz/src/system/EventFD.hxx
Added
@@ -0,0 +1,64 @@ +/* + * Copyright 2013-2018 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EVENT_FD_HXX +#define EVENT_FD_HXX + +#include "io/UniqueFileDescriptor.hxx" + +/** + * A class that wraps eventfd(). + */ +class EventFD { + UniqueFileDescriptor fd; + +public: + /** + * Throws on error. + */ + EventFD(); + + FileDescriptor Get() const noexcept { + return fd; + } + + /** + * Checks if Write() was called at least once since the last + * Read() call. + */ + bool Read() noexcept; + + /** + * Wakes up the reader. Multiple calls to this function will + * be combined to one wakeup. + */ + void Write() noexcept; +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/system/EventPipe.cxx
Added
@@ -0,0 +1,102 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "EventPipe.hxx" +#include "io/FileDescriptor.hxx" +#include "system/Error.hxx" + +#include <cassert> + +#ifdef _WIN32 +#include "net/IPv4Address.hxx" +#include "net/StaticSocketAddress.hxx" +#include "net/UniqueSocketDescriptor.hxx" +#include "net/SocketError.hxx" +#endif + +#ifdef _WIN32 +static void PoorSocketPair(UniqueSocketDescriptor &socket0, + UniqueSocketDescriptor &socket01); +#endif + +EventPipe::EventPipe() +{ +#ifdef _WIN32 + PoorSocketPair(r, w); +#else + if (!UniqueFileDescriptor::CreatePipeNonBlock(r, w)) + throw MakeErrno("pipe() has failed"); +#endif +} + +EventPipe::~EventPipe() noexcept = default; + +bool +EventPipe::Read() noexcept +{ + assert(r.IsDefined()); + assert(w.IsDefined()); + + char buffer256; + return r.Read(buffer, sizeof(buffer)) > 0; +} + +void +EventPipe::Write() noexcept +{ + assert(r.IsDefined()); + assert(w.IsDefined()); + + w.Write("", 1); +} + +#ifdef _WIN32 + +/* Our poor man's socketpair() implementation + * Due to limited protocol/address family support + * it's better to keep this as a private implementation detail of EventPipe + * rather than wide-available API. + */ +static void +PoorSocketPair(UniqueSocketDescriptor &socket0, UniqueSocketDescriptor &socket1) +{ + UniqueSocketDescriptor listen_socket; + if (!listen_socket.Create(AF_INET, SOCK_STREAM, IPPROTO_TCP)) + throw MakeSocketError("Failed to create socket"); + + if (!listen_socket.Bind(IPv4Address(IPv4Address::Loopback(), 0))) + throw MakeSocketError("Failed to create socket"); + + if (!listen_socket.Listen(1)) + throw MakeSocketError("Failed to listen on socket"); + + if (!socket0.Create(AF_INET, SOCK_STREAM, IPPROTO_TCP)) + throw MakeSocketError("Failed to create socket"); + + if (!socket0.Connect(listen_socket.GetLocalAddress())) + throw MakeSocketError("Failed to connect socket"); + + socket0.SetNonBlocking(); + + socket1 = listen_socket.AcceptNonBlock(); + if (!socket1.IsDefined()) + throw MakeSocketError("Failed to accept connection"); +} + +#endif
View file
ncmpc-0.47.tar.xz/src/system/EventPipe.hxx
Added
@@ -0,0 +1,75 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_EVENT_PIPE_HXX +#define MPD_EVENT_PIPE_HXX + +#ifdef _WIN32 +#include "net/UniqueSocketDescriptor.hxx" +#else +#include "io/UniqueFileDescriptor.hxx" +#endif + +/** + * A pipe that can be used to trigger an event to the read side. + * + * Errors in the constructor are fatal. + */ +class EventPipe { +#ifdef _WIN32 + UniqueSocketDescriptor r, w; +#else + UniqueFileDescriptor r, w; +#endif + +public: + /** + * Throws on error. + */ + EventPipe(); + + ~EventPipe() noexcept; + + EventPipe(const EventPipe &other) = delete; + EventPipe &operator=(const EventPipe &other) = delete; + +#ifdef _WIN32 + SocketDescriptor Get() const noexcept { + return r; + } +#else + FileDescriptor Get() const noexcept { + return r; + } +#endif + + /** + * Checks if Write() was called at least once since the last + * Read() call. + */ + bool Read() noexcept; + + /** + * Wakes up the reader. Multiple calls to this function will + * be combined to one wakeup. + */ + void Write() noexcept; +}; + +#endif /* MAIN_NOTIFY_H */
View file
ncmpc-0.47.tar.xz/src/system/SignalFD.cxx
Added
@@ -0,0 +1,53 @@ +/* + * Copyright 2013-2018 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "SignalFD.hxx" +#include "Error.hxx" + +#include <cassert> + +#include <sys/signalfd.h> + +void +SignalFD::Create(const sigset_t &mask) +{ + if (!fd.CreateSignalFD(&mask)) + throw MakeErrno("signalfd() failed"); +} + +int +SignalFD::Read() noexcept +{ + assert(fd.IsDefined()); + + signalfd_siginfo info; + return fd.Read(&info, sizeof(info)) > 0 + ? info.ssi_signo + : -1; +}
View file
ncmpc-0.47.tar.xz/src/system/SignalFD.hxx
Added
@@ -0,0 +1,67 @@ +/* + * Copyright 2013-2018 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SIGNAL_FD_HXX +#define SIGNAL_FD_HXX + +#include "io/UniqueFileDescriptor.hxx" + +#include <csignal> + +/** + * A class that wraps signalfd(). + */ +class SignalFD { + UniqueFileDescriptor fd; + +public: + /** + * Create the signalfd or update its mask. + * + * Throws on error. + */ + void Create(const sigset_t &mask); + + void Close() noexcept { + fd.Close(); + } + + int Get() const noexcept { + return fd.Get(); + } + + /** + * Read the next signal from the file descriptor. Returns the + * signal number on success or -1 if there are no more + * signals. + */ + int Read() noexcept; +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/system/meson.build
Added
@@ -0,0 +1,31 @@ +system_sources = + 'EventPipe.cxx', + + +if host_machine.system() == 'linux' + system_sources += + 'EventFD.cxx', + 'SignalFD.cxx', + 'EpollFD.cxx', + +endif + +system = static_library( + 'system', + system_sources, + include_directories: inc, +) + +if is_windows + winsock_dep = c_compiler.find_library('ws2_32') +else + winsock_dep = dependency('', required: false) +endif + +system_dep = declare_dependency( + link_with: system, + dependencies: + io_dep, + winsock_dep, + , +)
View file
ncmpc-0.47.tar.xz/src/time
Added
+(directory)
View file
ncmpc-0.47.tar.xz/src/time/ClockCache.hxx
Added
@@ -0,0 +1,67 @@ +/* + * Copyright 2007-2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <chrono> + +/** + * Cache the now() method of a clock. + */ +template<typename Clock> +class ClockCache { + using value_type = typename Clock::time_point; + mutable value_type value; + +public: + ClockCache() = default; + ClockCache(const ClockCache &) = delete; + ClockCache &operator=(const ClockCache &) = delete; + + gnu::pure + const auto &now() const noexcept { + if (value <= value_type()) + value = Clock::now(); + return value; + } + + void flush() noexcept { + value = {}; + } + + /** + * Inject a fake value. This can be helpful for unit tests. + */ + void Mock(value_type _value) noexcept { + value = _value; + } +};
View file
ncmpc-0.36.tar.xz/src/time_format.cxx -> ncmpc-0.47.tar.xz/src/time_format.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/time_format.hxx -> ncmpc-0.47.tar.xz/src/time_format.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.47.tar.xz/src/util/BindMethod.hxx
Added
@@ -0,0 +1,203 @@ +/* + * Copyright 2016-2021 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <type_traits> +#include <utility> + +/** + * This object stores a function pointer wrapping a method, and a + * reference to an instance of the method's class. It can be used to + * wrap instance methods as callback functions. + * + * @param S the plain function signature type + */ +template<typename S=void()> +class BoundMethod; + +template<typename R, + bool NoExcept, + typename... Args> +class BoundMethod<R(Args...) noexcept(NoExcept)> { + typedef R (*function_pointer)(void *instance, Args... args) noexcept(NoExcept); + + void *instance_; + function_pointer function; + +public: + /** + * Non-initializing trivial constructor + */ + BoundMethod() = default; + + constexpr + BoundMethod(void *_instance, function_pointer _function) noexcept + :instance_(_instance), function(_function) {} + + /** + * Construct an "undefined" object. It must not be called, + * and its "bool" operator returns false. + */ + BoundMethod(std::nullptr_t) noexcept:function(nullptr) {} + + /** + * Was this object initialized with a valid function pointer? + */ + operator bool() const noexcept { + return function != nullptr; + } + + R operator()(Args... args) const { + return function(instance_, std::forward<Args>(args)...); + } +}; + +namespace BindMethodDetail { + +/** + * Helper class which introspects a method/function pointer type. + * + * @param M the method/function pointer type + */ +template<typename M> +struct SignatureHelper; + +template<typename R, bool NoExcept, typename T, typename... Args> +struct SignatureHelper<R (T::*)(Args...) noexcept(NoExcept)> { + /** + * The class which contains the given method (signature). + */ + typedef T class_type; + + /** + * A function type which describes the "plain" function + * signature. + */ + typedef R plain_signature(Args...) noexcept(NoExcept); + + typedef R (*function_pointer)(void *instance, + Args...) noexcept(NoExcept); +}; + +template<typename R, bool NoExcept, typename... Args> +struct SignatureHelper<R (*)(Args...) noexcept(NoExcept)> { + typedef R plain_signature(Args...) noexcept(NoExcept); + + typedef R (*function_pointer)(void *instance, + Args...) noexcept(NoExcept); +}; + +/** + * Generate a wrapper function. + * + * @param method the method/function pointer + */ +template<typename M, auto method> +struct WrapperGenerator; + +template<typename T, bool NoExcept, + auto method, typename R, typename... Args> +struct WrapperGenerator<R (T::*)(Args...) noexcept(NoExcept), method> { + static R Invoke(void *_instance, Args... args) noexcept(NoExcept) { + auto &t = *(T *)_instance; + return (t.*method)(std::forward<Args>(args)...); + } +}; + +template<auto function, bool NoExcept, typename R, typename... Args> +struct WrapperGenerator<R (*)(Args...) noexcept(NoExcept), function> { + static R Invoke(void *, Args... args) noexcept(NoExcept) { + return function(std::forward<Args>(args)...); + } +}; + +template<auto method> +typename SignatureHelper<decltype(method)>::function_pointer +MakeWrapperFunction() noexcept +{ + return WrapperGenerator<decltype(method), method>::Invoke; +} + +} /* namespace BindMethodDetail */ + +/** + * Construct a #BoundMethod instance. + * + * @param method the method pointer + * @param instance the instance of #T to be bound + */ +template<auto method> +constexpr auto +BindMethod(typename BindMethodDetail::SignatureHelper<decltype(method)>::class_type &instance) noexcept +{ + using H = BindMethodDetail::SignatureHelper<decltype(method)>; + using plain_signature = typename H::plain_signature; + return BoundMethod<plain_signature>{ + &instance, + BindMethodDetail::MakeWrapperFunction<method>(), + }; +} + +/** + * Shortcut macro which takes an instance and a method pointer and + * constructs a #BoundMethod instance. + */ +#define BIND_METHOD(instance, method) \ + BindMethod<method>(instance) + +/** + * Shortcut wrapper for BIND_METHOD() which assumes "*this" is the + * instance to be bound. + */ +#define BIND_THIS_METHOD(method) BIND_METHOD(*this, &std::remove_reference_t<decltype(*this)>::method) + +/** + * Construct a #BoundMethod instance for a plain function. + * + * @param function the function pointer + */ +template<auto function> +constexpr auto +BindFunction() noexcept +{ + using H = BindMethodDetail::SignatureHelper<decltype(function)>; + using plain_signature = typename H::plain_signature; + return BoundMethod<plain_signature>{ + nullptr, + BindMethodDetail::MakeWrapperFunction<function>(), + }; +} + +/** + * Shortcut macro which takes a function pointer and constructs a + * #BoundMethod instance. + */ +#define BIND_FUNCTION(function) \ + BindFunction<&function>()
View file
ncmpc-0.47.tar.xz/src/util/ByteOrder.hxx
Added
@@ -0,0 +1,509 @@ +/* + * Copyright 2011-2021 Max Kellermann <max.kellermann@gmail.com>, + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BYTE_ORDER_HXX +#define BYTE_ORDER_HXX + +#include "Compiler.h" + +#include <cstdint> + +#if defined(__i386__) || defined(__x86_64__) || defined(__ARMEL__) +/* well-known little-endian */ +# define IS_LITTLE_ENDIAN true +# define IS_BIG_ENDIAN false +#elif defined(__MIPSEB__) +/* well-known big-endian */ +# define IS_LITTLE_ENDIAN false +# define IS_BIG_ENDIAN true +#elif defined(__APPLE__) || defined(__NetBSD__) +/* compile-time check for MacOS */ +# include <machine/endian.h> +# if BYTE_ORDER == LITTLE_ENDIAN +# define IS_LITTLE_ENDIAN true +# define IS_BIG_ENDIAN false +# else +# define IS_LITTLE_ENDIAN false +# define IS_BIG_ENDIAN true +# endif +#elif defined(__BYTE_ORDER__) +/* GCC-specific macros */ +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define IS_LITTLE_ENDIAN true +# define IS_BIG_ENDIAN false +# else +# define IS_LITTLE_ENDIAN false +# define IS_BIG_ENDIAN true +# endif +#else +/* generic compile-time check */ +# include <endian.h> +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define IS_LITTLE_ENDIAN true +# define IS_BIG_ENDIAN false +# else +# define IS_LITTLE_ENDIAN false +# define IS_BIG_ENDIAN true +# endif +#endif + +constexpr bool +IsLittleEndian() noexcept +{ + return IS_LITTLE_ENDIAN; +} + +constexpr bool +IsBigEndian() noexcept +{ + return IS_BIG_ENDIAN; +} + +constexpr uint16_t +GenericByteSwap16(uint16_t value) noexcept +{ + return (value >> 8) | (value << 8); +} + +constexpr uint32_t +GenericByteSwap32(uint32_t value) noexcept +{ + return (value >> 24) | ((value >> 8) & 0x0000ff00) | + ((value << 8) & 0x00ff0000) | (value << 24); +} + +constexpr uint64_t +GenericByteSwap64(uint64_t value) noexcept +{ + return uint64_t(GenericByteSwap32(uint32_t(value >> 32))) + | (uint64_t(GenericByteSwap32(value)) << 32); +} + +constexpr uint16_t +ByteSwap16(uint16_t value) noexcept +{ +#if CLANG_OR_GCC_VERSION(4,8) + return __builtin_bswap16(value); +#else + return GenericByteSwap16(value); +#endif +} + +constexpr uint32_t +ByteSwap32(uint32_t value) noexcept +{ +#if CLANG_OR_GCC_VERSION(4,3) + return __builtin_bswap32(value); +#else + return GenericByteSwap32(value); +#endif +} + +constexpr uint64_t +ByteSwap64(uint64_t value) noexcept +{ +#if CLANG_OR_GCC_VERSION(4,3) + return __builtin_bswap64(value); +#else + return GenericByteSwap64(value); +#endif +} + +/** + * Converts a 16bit value from big endian to the system's byte order + */ +constexpr uint16_t +FromBE16(uint16_t value) noexcept +{ + return IsBigEndian() ? value : ByteSwap16(value); +} + +/** + * Converts a 32bit value from big endian to the system's byte order + */ +constexpr uint32_t +FromBE32(uint32_t value) noexcept +{ + return IsBigEndian() ? value : ByteSwap32(value); +} + +/** + * Converts a 64bit value from big endian to the system's byte order + */ +constexpr uint64_t +FromBE64(uint64_t value) noexcept +{ + return IsBigEndian() ? value : ByteSwap64(value); +} + +/** + * Converts a 16bit value from little endian to the system's byte order + */ +constexpr uint16_t +FromLE16(uint16_t value) noexcept +{ + return IsLittleEndian() ? value : ByteSwap16(value); +} + +/** + * Converts a 32bit value from little endian to the system's byte order + */ +constexpr uint32_t +FromLE32(uint32_t value) noexcept +{ + return IsLittleEndian() ? value : ByteSwap32(value); +} + +/** + * Converts a 64bit value from little endian to the system's byte order + */ +constexpr uint64_t +FromLE64(uint64_t value) noexcept +{ + return IsLittleEndian() ? value : ByteSwap64(value); +} + +/** + * Converts a 16bit value from the system's byte order to big endian + */ +constexpr uint16_t +ToBE16(uint16_t value) noexcept +{ + return IsBigEndian() ? value : ByteSwap16(value); +} + +/** + * Converts a 32bit value from the system's byte order to big endian + */ +constexpr uint32_t +ToBE32(uint32_t value) noexcept +{ + return IsBigEndian() ? value : ByteSwap32(value); +} + +/** + * Converts a 64bit value from the system's byte order to big endian + */ +constexpr uint64_t +ToBE64(uint64_t value) noexcept +{ + return IsBigEndian() ? value : ByteSwap64(value); +} + +/** + * Converts a 16bit value from the system's byte order to little endian + */ +constexpr uint16_t +ToLE16(uint16_t value) noexcept +{ + return IsLittleEndian() ? value : ByteSwap16(value); +} + +/** + * Converts a 32bit value from the system's byte order to little endian + */ +constexpr uint32_t +ToLE32(uint32_t value) noexcept +{ + return IsLittleEndian() ? value : ByteSwap32(value); +} + +/** + * Converts a 64bit value from the system's byte order to little endian + */ +constexpr uint64_t +ToLE64(uint64_t value) noexcept +{ + return IsLittleEndian() ? value : ByteSwap64(value); +} + +/** + * Converts a 16 bit integer from little endian to the host byte order + * and returns it as a signed integer. + */ +constexpr int16_t +FromLE16S(uint16_t value) noexcept +{ + /* assuming two's complement representation */ + return static_cast<int16_t>(FromLE16(value)); +} + +/** + * A packed big-endian 16 bit integer. + */ +class PackedBE16 { + uint8_t hi, lo; + +public: + PackedBE16() = default; + + constexpr PackedBE16(uint16_t src) noexcept + :hi(uint8_t(src >> 8)), + lo(uint8_t(src)) {} + + /** + * Construct an instance from an integer which is already + * big-endian. + */ + static constexpr auto FromBE(uint16_t src) noexcept { + union { + uint16_t in; + PackedBE16 out; + } u{src}; + return u.out; + } + + constexpr operator uint16_t() const noexcept { + return (uint16_t(hi) << 8) | uint16_t(lo); + } + + /** + * Reads the raw, big-endian value. + */ + constexpr uint16_t raw() const noexcept { + uint16_t x = *this; + if (IsLittleEndian()) + x = ByteSwap16(x); + return x; + } +}; + +static_assert(sizeof(PackedBE16) == sizeof(uint16_t), "Wrong size"); +static_assert(alignof(PackedBE16) == 1, "Wrong alignment"); + +/** + * A packed big-endian 32 bit integer. + */ +class PackedBE32 { + uint8_t a, b, c, d; + +public: + PackedBE32() = default; + + constexpr PackedBE32(uint32_t src) noexcept + :a(uint8_t(src >> 24)), + b(uint8_t(src >> 16)), + c(uint8_t(src >> 8)), + d(uint8_t(src)) {} + + /** + * Construct an instance from an integer which is already + * big-endian. + */ + static constexpr auto FromBE(uint32_t src) noexcept { + union { + uint32_t in; + PackedBE32 out; + } u{src}; + return u.out; + } + + constexpr operator uint32_t() const noexcept { + return (uint32_t(a) << 24) | (uint32_t(b) << 16) | + (uint32_t(c) << 8) | uint32_t(d); + } + + PackedBE32 &operator=(uint32_t new_value) noexcept { + d = uint8_t(new_value); + c = uint8_t(new_value >> 8); + b = uint8_t(new_value >> 16); + a = uint8_t(new_value >> 24); + return *this; + } + + /** + * Reads the raw, big-endian value. + */ + constexpr uint32_t raw() const noexcept { + uint32_t x = *this; + if (IsLittleEndian()) + x = ByteSwap32(x); + return x; + } +}; + +static_assert(sizeof(PackedBE32) == sizeof(uint32_t), "Wrong size"); +static_assert(alignof(PackedBE32) == 1, "Wrong alignment"); + +/** + * A packed big-endian 64 bit integer. + */ +class PackedBE64 { + uint8_t a, b, c, d, e, f, g, h; + +public: + PackedBE64() = default; + + constexpr PackedBE64(uint64_t src) noexcept + :a(uint8_t(src >> 56)), + b(uint8_t(src >> 48)), + c(uint8_t(src >> 40)), + d(uint8_t(src >> 32)), + e(uint8_t(src >> 24)), + f(uint8_t(src >> 16)), + g(uint8_t(src >> 8)), + h(uint8_t(src)) {} + + /** + * Construct an instance from an integer which is already + * big-endian. + */ + static constexpr auto FromBE(uint64_t src) noexcept { + union { + uint64_t in; + PackedBE64 out; + } u{src}; + return u.out; + } + + constexpr operator uint64_t() const noexcept { + return (uint64_t(a) << 56) | (uint64_t(b) << 48) | + (uint64_t(c) << 40) | (uint64_t(d) << 32) | + (uint64_t(e) << 24) | (uint64_t(f) << 16) | + (uint64_t(g) << 8) | uint64_t(h); + } + + /** + * Reads the raw, big-endian value. + */ + constexpr uint64_t raw() const noexcept { + uint64_t x = *this; + if (IsLittleEndian()) + x = ByteSwap64(x); + return x; + } +}; + +static_assert(sizeof(PackedBE64) == sizeof(uint64_t), "Wrong size"); +static_assert(alignof(PackedBE64) == 1, "Wrong alignment"); + +/** + * A packed little-endian 16 bit integer. + */ +class PackedLE16 { + uint8_t lo, hi; + +public: + PackedLE16() = default; + + constexpr PackedLE16(uint16_t src) noexcept + :lo(uint8_t(src)), + hi(uint8_t(src >> 8)) {} + + /** + * Construct an instance from an integer which is already + * little-endian. + */ + static constexpr auto FromLE(uint16_t src) noexcept { + union { + uint16_t in; + PackedLE16 out; + } u{src}; + return u.out; + } + + constexpr operator uint16_t() const noexcept { + return (uint16_t(hi) << 8) | uint16_t(lo); + } + + PackedLE16 &operator=(uint16_t new_value) noexcept { + lo = uint8_t(new_value); + hi = uint8_t(new_value >> 8); + return *this; + } + + /** + * Reads the raw, little-endian value. + */ + constexpr uint16_t raw() const noexcept { + uint16_t x = *this; + if (IsBigEndian()) + x = ByteSwap16(x); + return x; + } +}; + +static_assert(sizeof(PackedLE16) == sizeof(uint16_t), "Wrong size"); +static_assert(alignof(PackedLE16) == 1, "Wrong alignment"); + +/** + * A packed little-endian 32 bit integer. + */ +class PackedLE32 { + uint8_t a, b, c, d; + +public: + PackedLE32() = default; + + constexpr PackedLE32(uint32_t src) noexcept + :a(uint8_t(src)), + b(uint8_t(src >> 8)), + c(uint8_t(src >> 16)), + d(uint8_t(src >> 24)) {} + + /** + * Construct an instance from an integer which is already + * little-endian. + */ + static constexpr auto FromLE(uint32_t src) noexcept { + union { + uint32_t in; + PackedLE32 out; + } u{src}; + return u.out; + } + + constexpr operator uint32_t() const noexcept { + return uint32_t(a) | (uint32_t(b) << 8) | + (uint32_t(c) << 16) | (uint32_t(d) << 24); + } + + PackedLE32 &operator=(uint32_t new_value) noexcept { + a = uint8_t(new_value); + b = uint8_t(new_value >> 8); + c = uint8_t(new_value >> 16); + d = uint8_t(new_value >> 24); + return *this; + } + + /** + * Reads the raw, little-endian value. + */ + constexpr uint32_t raw() const noexcept { + uint32_t x = *this; + if (IsBigEndian()) + x = ByteSwap32(x); + return x; + } +}; + +static_assert(sizeof(PackedLE32) == sizeof(uint32_t), "Wrong size"); +static_assert(alignof(PackedLE32) == 1, "Wrong alignment"); + +#endif
View file
ncmpc-0.47.tar.xz/src/util/Cancellable.hxx
Added
@@ -0,0 +1,87 @@ +/* + * Copyright 2016-2019 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CANCELLABLE_HXX +#define CANCELLABLE_HXX + +#include <utility> + +/** + * An asynchronous operation that can be cancelled. Upon + * cancellation, the operation's handler must not be invoked. + */ +class Cancellable { +public: + virtual void Cancel() noexcept = 0; +}; + +class CancellablePointer { + Cancellable *cancellable = nullptr; + +public: + constexpr CancellablePointer() = default; + + constexpr CancellablePointer(std::nullptr_t n) noexcept + :cancellable(n) {} + + CancellablePointer(CancellablePointer &&src) noexcept + :cancellable(std::exchange(src.cancellable, nullptr)) {} + + CancellablePointer &operator=(CancellablePointer &&src) noexcept { + using std::swap; + swap(cancellable, src.cancellable); + return *this; + } + + CancellablePointer &operator=(std::nullptr_t n) noexcept { + cancellable = n; + return *this; + } + + CancellablePointer &operator=(Cancellable &_cancellable) noexcept { + cancellable = &_cancellable; + return *this; + } + + constexpr operator bool() const noexcept { + return cancellable != nullptr; + } + + void Cancel() noexcept { + cancellable->Cancel(); + } + + void CancelAndClear() noexcept { + auto *c = cancellable; + cancellable = nullptr; + c->Cancel(); + } +}; + +#endif
View file
ncmpc-0.47.tar.xz/src/util/Cast.hxx
Added
@@ -0,0 +1,85 @@ +/* + * Copyright (C) 2013-2014 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CAST_HXX +#define CAST_HXX + +#include "OffsetPointer.hxx" + +#include <cstddef> + +template<typename T, typename U> +constexpr T * +OffsetCast(U *p, std::ptrdiff_t offset) +{ + return reinterpret_cast<T *>(OffsetPointer(p, offset)); +} + +template<typename T, typename U> +constexpr T * +OffsetCast(const U *p, std::ptrdiff_t offset) +{ + return reinterpret_cast<const T *>(OffsetPointer(p, offset)); +} + +template<class C, class A> +constexpr std::ptrdiff_t +ContainerAttributeOffset(const C *null_c, const A C::*p) +{ + return std::ptrdiff_t((const char *)&(null_c->*p) - (const char *)null_c); +} + +template<class C, class A> +constexpr std::ptrdiff_t +ContainerAttributeOffset(const A C::*p) +{ + return ContainerAttributeOffset<C, A>(nullptr, p); +} + +/** + * Cast the given pointer to a struct member to its parent structure. + */ +template<class C, class A> +constexpr C & +ContainerCast(A &a, const A C::*member) +{ + return *OffsetCast<C, A>(&a, -ContainerAttributeOffset<C, A>(member)); +} + +/** + * Cast the given pointer to a struct member to its parent structure. + */ +template<class C, class A> +constexpr const C & +ContainerCast(const A &a, const A C::*member) +{ + return *OffsetCast<const C, const A>(&a, -ContainerAttributeOffset<C, A>(member)); +} + +#endif
View file
ncmpc-0.36.tar.xz/src/util/CharUtil.hxx -> ncmpc-0.47.tar.xz/src/util/CharUtil.hxx
Changed
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2017 Max Kellermann <max.kellermann@gmail.com> + * Copyright 2011-2020 Max Kellermann <max.kellermann@gmail.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -70,12 +70,29 @@ return IsWhitespaceOrNull(ch); } +/** + * Is this a non-printable ASCII character? Returns false for + * non-ASCII characters. + * + * Note that this is not the opposite of IsNonPrintableASCII(). + */ constexpr bool IsPrintableASCII(char ch) noexcept { return (signed char)ch >= 0x20; } +/** + * Is this a non-printable character? Returns false for non-ASCII characters. + * + * Note that this is not the opposite of IsPrintableASCII() + */ +constexpr bool +IsNonPrintableASCII(char ch) noexcept +{ + return (unsigned char)ch < 0x20; +} + constexpr bool IsDigitASCII(char ch) noexcept { @@ -130,4 +147,12 @@ : ch; } +constexpr bool +IsHexDigit(char ch) noexcept +{ + return IsDigitASCII(ch) || + (ch >= 'a' && ch <= 'f') || + (ch >= 'A' && ch <= 'F'); +} + #endif
View file
ncmpc-0.36.tar.xz/src/util/Compiler.h -> ncmpc-0.47.tar.xz/src/util/Compiler.h
Changed
@@ -152,18 +152,6 @@ #if defined(__cplusplus) -/* support for C++11 "override" was added in gcc 4.7 */ -#if GCC_OLDER_THAN(4,7) -#define override -#define final -#endif - -#if CLANG_OR_GCC_VERSION(4,8) -#define gcc_alignas(T, fallback) alignas(T) -#else -#define gcc_alignas(T, fallback) gcc_aligned(fallback) -#endif - #endif #ifndef __has_feature
View file
ncmpc-0.47.tar.xz/src/util/Exception.cxx
Added
@@ -0,0 +1,80 @@ +/* + * Copyright 2016-2018 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Exception.hxx" + +#include <utility> + +template<typename T> +static void +AppendNestedMessage(std::string &result, T &&e, + const char *fallback, const char *separator) noexcept +{ + try { + std::rethrow_if_nested(std::forward<T>(e)); + } catch (const std::exception &nested) { + result += separator; + result += nested.what(); + AppendNestedMessage(result, nested, fallback, separator); + } catch (const std::nested_exception &ne) { + AppendNestedMessage(result, ne, fallback, separator); + } catch (const char *s) { + result += separator; + result += s; + } catch (...) { + result += separator; + result += fallback; + } +} + +std::string +GetFullMessage(const std::exception &e, + const char *fallback, const char *separator) noexcept +{ + std::string result = e.what(); + AppendNestedMessage(result, e, fallback, separator); + return result; +} + +std::string +GetFullMessage(std::exception_ptr ep, + const char *fallback, const char *separator) noexcept +{ + try { + std::rethrow_exception(std::move(ep)); + } catch (const std::exception &e) { + return GetFullMessage(e, fallback, separator); + } catch (const std::nested_exception &ne) { + return GetFullMessage(ne.nested_ptr(), fallback, separator); + } catch (const char *s) { + return s; + } catch (...) { + return fallback; + } +}
View file
ncmpc-0.47.tar.xz/src/util/Exception.hxx
Added
@@ -0,0 +1,143 @@ +/* + * Copyright 2016-2021 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EXCEPTION_HXX +#define EXCEPTION_HXX + +#include <exception> +#include <string> +#include <utility> + +/** + * Throws the specified exception. There is an overload for + * std::exception_ptr which throws the contained exception instead of + * the std::exception_ptr itself. + */ +template<typename T> +noreturn +inline void +ThrowException(T &&t) +{ + throw std::forward<T>(t); +} + +noreturn +inline void +ThrowException(std::exception_ptr ep) +{ + std::rethrow_exception(ep); +} + +/** + * Create a nested exception, wrapping #ep inside the + * std::current_exception(). + */ +template<typename T> +inline std::exception_ptr +NestCurrentException(T &&t) noexcept +{ + try { + std::throw_with_nested(std::forward<T>(t)); + } catch (...) { + return std::current_exception(); + } +} + +/** + * Create a nested exception, wrapping #ep inside (a copy of) #t. + */ +template<typename T> +inline std::exception_ptr +NestException(std::exception_ptr ep, T &&t) noexcept +{ + try { + std::rethrow_exception(ep); + } catch (...) { + return NestCurrentException(std::forward<T>(t)); + } +} + +/** + * Find an instance of #T in the nested exception chain, and return a + * pointer. Returns nullptr if no such instance was found. + */ +template<typename T> +gnu::pure +inline const T * +FindNested(std::exception_ptr ep) noexcept +{ + try { + std::rethrow_exception(ep); + } catch (const T &t) { + return &t; + } catch (const std::nested_exception &ne) { + return FindNested<T>(ne.nested_ptr()); + } catch (...) { + } + + return nullptr; +} + +/** + * Find an instance of #T in the nested exception chain, and rethrow + * it. Does nothing if no such instance was found. + */ +template<typename T> +inline void +FindRetrowNested(std::exception_ptr ep) +{ + try { + std::rethrow_exception(ep); + } catch (const T &t) { + throw; + } catch (const std::nested_exception &ne) { + FindRetrowNested<T>(ne.nested_ptr()); + } catch (...) { + } +} + +/** + * Obtain the full concatenated message of an exception and its nested + * chain. + */ +std::string +GetFullMessage(const std::exception &e, + const char *fallback="Unknown exception", + const char *separator="; ") noexcept; + +/** + * Obtain the full concatenated message of an exception and its nested + * chain. + */ +std::string +GetFullMessage(std::exception_ptr ep, + const char *fallback="Unknown exception", + const char *separator="; ") noexcept; + +#endif
View file
ncmpc-0.47.tar.xz/src/util/FNVHash.hxx
Added
@@ -0,0 +1,116 @@ +/* + * Copyright 2017 Content Management AG + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Implementation of the Fowler-Noll-Vo hash function. + */ + +#ifndef FNV_HASH_HXX +#define FNV_HASH_HXX + +#include <stddef.h> +#include <stdint.h> + +template<typename T> +struct FNVTraits {}; + +template<> +struct FNVTraits<uint32_t> { + typedef uint32_t value_type; + typedef uint_fast32_t fast_type; + + static constexpr value_type OFFSET_BASIS = 2166136261u; + static constexpr value_type PRIME = 16777619u; +}; + +template<> +struct FNVTraits<uint64_t> { + typedef uint64_t value_type; + typedef uint_fast64_t fast_type; + + static constexpr value_type OFFSET_BASIS = 14695981039346656037u; + static constexpr value_type PRIME = 1099511628211u; +}; + +template<typename Traits> +struct FNV1aAlgorithm { + typedef typename Traits::value_type value_type; + typedef typename Traits::fast_type fast_type; + + gnu::hot + static constexpr fast_type Update(fast_type hash, uint8_t b) noexcept { + return (hash ^ b) * Traits::PRIME; + } + + gnu::pure gnu::hot + static value_type StringHash(const char *s) noexcept { + using Algorithm = FNV1aAlgorithm<Traits>; + + fast_type hash = Traits::OFFSET_BASIS; + while (*s) + hash = Algorithm::Update(hash, *s++); + + return hash; + } +}; + +gnu::pure gnu::hot +inline uint32_t +FNV1aHash32(const char *s) noexcept +{ + using Traits = FNVTraits<uint32_t>; + using Algorithm = FNV1aAlgorithm<Traits>; + return Algorithm::StringHash(s); +} + +gnu::pure gnu::hot +inline uint64_t +FNV1aHash64(const char *s) noexcept +{ + using Traits = FNVTraits<uint64_t>; + using Algorithm = FNV1aAlgorithm<Traits>; + return Algorithm::StringHash(s); +} + +gnu::pure gnu::hot +inline uint32_t +FNV1aHashFold32(const char *s) noexcept +{ + const uint64_t h64 = FNV1aHash64(s); + + /* XOR folding */ + const uint_fast32_t lo(h64); + const uint_fast32_t hi(h64 >> 32); + return lo ^ hi; +} + +#endif
View file
ncmpc-0.47.tar.xz/src/util/IntrusiveList.hxx
Added
@@ -0,0 +1,503 @@ +/* + * Copyright 2020 Max Kellermann <max.kellermann@gmail.com> + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "Cast.hxx" +#include "MemberPointer.hxx" +#include "OptionalCounter.hxx" + +#include <iterator> +#include <type_traits> +#include <utility> + +struct IntrusiveListNode { + IntrusiveListNode *next, *prev; +}; + +class IntrusiveListHook { + template<typename T> friend struct IntrusiveListBaseHookTraits; + template<auto member> friend struct IntrusiveListMemberHookTraits; + template<typename T, typename HookTraits, bool> friend class IntrusiveList; + +protected: + IntrusiveListNode siblings; + +public: + IntrusiveListHook() noexcept = default; + + IntrusiveListHook(const IntrusiveListHook &) = delete; + IntrusiveListHook &operator=(const IntrusiveListHook &) = delete; + + void unlink() noexcept { + siblings.next->prev = siblings.prev; + siblings.prev->next = siblings.next; + } + +private: + static constexpr auto &Cast(IntrusiveListNode &node) noexcept { + return ContainerCast(node, &IntrusiveListHook::siblings); + } + + static constexpr const auto &Cast(const IntrusiveListNode &node) noexcept { + return ContainerCast(node, &IntrusiveListHook::siblings); + } +}; + +/** + * A variant of #IntrusiveListHook which keeps track of whether it is + * currently in a list. + */ +class SafeLinkIntrusiveListHook : public IntrusiveListHook { +public: + SafeLinkIntrusiveListHook() noexcept { + siblings.next = nullptr; + } + + void unlink() noexcept { + IntrusiveListHook::unlink(); + siblings.next = nullptr; + } + + bool is_linked() const noexcept { + return siblings.next != nullptr; + } +}; + +/** + * A variant of #IntrusiveListHook which auto-unlinks itself from the + * list upon destruction. As a side effect, it has an is_linked() + * method. + */ +class AutoUnlinkIntrusiveListHook : public SafeLinkIntrusiveListHook { +public: + ~AutoUnlinkIntrusiveListHook() noexcept { + if (is_linked()) + unlink(); + } +}; + +/** + * Detect the hook type; this is important because + * SafeLinkIntrusiveListHook::unlink() needs to clear the "next" + * pointer. This is a template to postpone the type checks, to allow + * forward-declared types. + */ +template<typename U> +struct IntrusiveListHookDetection { + static_assert(std::is_base_of_v<IntrusiveListHook, U>); + + using type = std::conditional_t<std::is_base_of_v<SafeLinkIntrusiveListHook, U>, + SafeLinkIntrusiveListHook, + IntrusiveListHook>; +}; + +/** + * For classes which embed #IntrusiveListHook as base class. + */ +template<typename T> +struct IntrusiveListBaseHookTraits { + template<typename U> + using Hook = typename IntrusiveListHookDetection<U>::type; + + static constexpr bool IsAutoUnlink() noexcept { + return std::is_base_of_v<AutoUnlinkIntrusiveListHook, T>; + } + + static constexpr T *Cast(IntrusiveListNode *node) noexcept { + auto *hook = &Hook<T>::Cast(*node); + return static_cast<T *>(hook); + } + + static constexpr const T *Cast(const IntrusiveListNode *node) noexcept { + const auto *hook = &Hook<T>::Cast(*node); + return static_cast<const T *>(hook); + } + + static constexpr auto &ToHook(T &t) noexcept { + return static_cast<Hook<T> &>(t); + } + + static constexpr const auto &ToHook(const T &t) noexcept { + return static_cast<const Hook<T> &>(t); + } +}; + +/** + * For classes which embed #IntrusiveListHook as member. + */ +template<auto member> +struct IntrusiveListMemberHookTraits { + using T = MemberPointerContainerType<decltype(member)>; + using _Hook = MemberPointerType<decltype(member)>; + using Hook = typename IntrusiveListHookDetection<_Hook>::type; + + static constexpr bool IsAutoUnlink() noexcept { + return std::is_base_of_v<AutoUnlinkIntrusiveListHook, _Hook>; + } + + static constexpr T *Cast(IntrusiveListNode *node) noexcept { + auto &hook = Hook::Cast(*node); + return &ContainerCast(hook, member); + } + + static constexpr const T *Cast(const IntrusiveListNode *node) noexcept { + const auto &hook = Hook::Cast(*node); + return &ContainerCast(hook, member); + } + + static constexpr auto &ToHook(T &t) noexcept { + return t.*member; + } + + static constexpr const auto &ToHook(const T &t) noexcept { + return t.*member; + } +}; + +/** + * @param constant_time_size make size() constant-time by caching the + * number of items in a field? + */ +template<typename T, + typename HookTraits=IntrusiveListBaseHookTraits<T>, + bool constant_time_size=false> +class IntrusiveList { + template<typename U> + using Hook = typename IntrusiveListHookDetection<U>::type; + + IntrusiveListNode head{&head, &head}; + + no_unique_address + OptionalCounter<constant_time_size> counter; + + static constexpr T *Cast(IntrusiveListNode *node) noexcept { + return HookTraits::Cast(node); + } + + static constexpr const T *Cast(const IntrusiveListNode *node) noexcept { + return HookTraits::Cast(node); + } + + static constexpr auto &ToHook(T &t) noexcept { + return HookTraits::ToHook(t); + } + + static constexpr const auto &ToHook(const T &t) noexcept { + return HookTraits::ToHook(t); + } + + static constexpr IntrusiveListNode &ToNode(T &t) noexcept { + return ToHook(t).siblings; + } + + static constexpr const IntrusiveListNode &ToNode(const T &t) noexcept { + return ToHook(t).siblings; + } + +public: + using size_type = std::size_t; + + constexpr IntrusiveList() noexcept = default; + + IntrusiveList(IntrusiveList &&src) noexcept { + if (src.empty()) + return; + + head = src.head; + head.next->prev = &head; + head.prev->next = &head; + + src.head.next = &src.head; + src.head.prev = &src.head; + + using std::swap; + swap(counter, src.counter); + } + + ~IntrusiveList() noexcept { + if constexpr (std::is_base_of_v<SafeLinkIntrusiveListHook, T>) + clear(); + } + + IntrusiveList &operator=(IntrusiveList &&) = delete; + + friend void swap(IntrusiveList &a, IntrusiveList &b) noexcept { + using std::swap; + + if (a.empty()) { + if (b.empty()) + return; + + a.head = b.head; + a.head.next->prev = &a.head; + a.head.prev->next = &a.head; + + b.head = {&b.head, &b.head}; + } else { + swap(a.head, b.head); + + a.head.next->prev = &a.head; + a.head.prev->next = &a.head; + + b.head.next->prev = &b.head; + b.head.prev->next = &b.head; + } + + swap(a.counter, b.counter); + } + + constexpr bool empty() const noexcept { + return head.next == &head; + } + + constexpr size_type size() const noexcept { + if constexpr (constant_time_size) + return counter; + else + return std::distance(begin(), end()); + } + + void clear() noexcept { + if constexpr (std::is_base_of_v<SafeLinkIntrusiveListHook, T>) { + /* for SafeLinkIntrusiveListHook, we need to + remove each item manually, or else its + is_linked() method will not work */ + while (!empty()) + pop_front(); + } else { + head = {&head, &head}; + counter.reset(); + } + } + + template<typename D> + void clear_and_dispose(D &&disposer) noexcept { + while (!empty()) { + auto *item = &front(); + pop_front(); + disposer(item); + } + } + + template<typename P, typename D> + void remove_and_dispose_if(P &&pred, D &&dispose) noexcept { + auto *n = head.next; + + while (n != &head) { + auto *i = Cast(n); + n = n->next; + + if (pred(*i)) { + ToHook(*i).unlink(); + --counter; + dispose(i); + } + } + } + + const T &front() const noexcept { + return *Cast(head.next); + } + + T &front() noexcept { + return *Cast(head.next); + } + + void pop_front() noexcept { + ToHook(front()).unlink(); + --counter; + } + + template<typename D> + void pop_front_and_dispose(D &&disposer) noexcept { + auto &i = front(); + ToHook(i).unlink(); + --counter; + disposer(&i); + } + + T &back() noexcept { + return *Cast(head.prev); + } + + void pop_back() noexcept { + ToHook(back()).unlink(); + --counter; + } + + class const_iterator; + + class iterator final { + friend IntrusiveList; + friend const_iterator; + + IntrusiveListNode *cursor; + + constexpr iterator(IntrusiveListNode *_cursor) noexcept + :cursor(_cursor) {} + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = value_type *; + using reference = value_type &; + + iterator() noexcept = default; + + constexpr bool operator==(const iterator &other) const noexcept { + return cursor == other.cursor; + } + + constexpr bool operator!=(const iterator &other) const noexcept { + return !(*this == other); + } + + constexpr T &operator*() const noexcept { + return *Cast(cursor); + } + + constexpr T *operator->() const noexcept { + return Cast(cursor); + } + + iterator &operator++() noexcept { + cursor = cursor->next; + return *this; + } + }; + + constexpr iterator begin() noexcept { + return {head.next}; + } + + constexpr iterator end() noexcept { + return {&head}; + } + + static constexpr iterator iterator_to(T &t) noexcept { + return {&ToNode(t)}; + } + + class const_iterator final { + friend IntrusiveList; + + const IntrusiveListNode *cursor; + + constexpr const_iterator(const IntrusiveListNode *_cursor) noexcept + :cursor(_cursor) {} + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = const T; + using difference_type = std::ptrdiff_t; + using pointer = value_type *; + using reference = value_type &; + + const_iterator() noexcept = default; + + const_iterator(iterator src) noexcept + :cursor(src.cursor) {} + + constexpr bool operator==(const const_iterator &other) const noexcept { + return cursor == other.cursor; + } + + constexpr bool operator!=(const const_iterator &other) const noexcept { + return !(*this == other); + } + + constexpr const T &operator*() const noexcept { + return *Cast(cursor); + } + + constexpr const T *operator->() const noexcept { + return Cast(cursor); + } + + const_iterator &operator++() noexcept { + cursor = cursor->next; + return *this; + } + }; + + constexpr const_iterator begin() const noexcept { + return {head.next}; + } + + constexpr const_iterator end() const noexcept { + return {&head}; + } + + static constexpr iterator iterator_to(const T &t) noexcept { + return {&ToNode(t)}; + } + + iterator erase(iterator i) noexcept { + auto result = std::next(i); + ToHook(*i).unlink(); + --counter; + return result; + } + + template<typename D> + iterator erase_and_dispose(iterator i, D &&disposer) noexcept { + auto result = erase(i); + disposer(&*i); + return result; + } + + void push_front(T &t) noexcept { + insert(begin(), t); + } + + void push_back(T &t) noexcept { + insert(end(), t); + } + + void insert(iterator p, T &t) noexcept { + static_assert(!constant_time_size || + !HookTraits::IsAutoUnlink(), + "Can't use auto-unlink hooks with constant_time_size"); + + auto &existing_node = ToNode(*p); + auto &new_node = ToNode(t); + + existing_node.prev->next = &new_node; + new_node.prev = existing_node.prev; + existing_node.prev = &new_node; + new_node.next = &existing_node; + + ++counter; + } +};
View file
ncmpc-0.36.tar.xz/src/util/LocaleString.hxx -> ncmpc-0.47.tar.xz/src/util/LocaleString.hxx
Changed
@@ -30,14 +30,12 @@ #ifndef LOCALE_STRING_HXX #define LOCALE_STRING_HXX -#include "Compiler.h" - #include <cstddef> /** * Is the given character incomplete? */ -gcc_pure +gnu::pure bool IsIncompleteCharMB(const char *s, size_t n) noexcept; @@ -45,7 +43,7 @@ * Returns the length of the given locale (multi-byte) string in * characters. */ -gcc_pure +gnu::pure std::size_t StringLengthMB(const char *s, size_t n) noexcept; @@ -53,7 +51,7 @@ * Wrapper for std::mbrlen() which attempts to recover with a best * effort from invalid or incomplete sequences. */ -gcc_pure +gnu::pure std::size_t CharSizeMB(const char *s, size_t n) noexcept; @@ -62,7 +60,7 @@ * * @param s the start of the string */ -gcc_pure +gnu::pure const char * PrevCharMB(const char *start, const char *reference) noexcept; @@ -72,7 +70,7 @@ * * @param s the start of the string */ -gcc_pure +gnu::pure const char * AtCharMB(const char *s, size_t length, size_t i) noexcept; @@ -80,11 +78,11 @@ * Returns the number of terminal cells occupied by this multi-byte * string. */ -gcc_pure +gnu::pure size_t StringWidthMB(const char *s, size_t length) noexcept; -gcc_pure +gnu::pure size_t StringWidthMB(const char *s) noexcept; @@ -93,7 +91,7 @@ * * @param s the start of the string */ -gcc_pure +gnu::pure const char * AtWidthMB(const char *s, size_t length, size_t width) noexcept;
View file
ncmpc-0.47.tar.xz/src/util/Manual.hxx
Added
@@ -0,0 +1,122 @@ +/* + * Copyright 2013-2022 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <cassert> +#include <new> +#include <type_traits> +#include <utility> + +/** + * Container for an object that gets constructed and destructed + * manually. The object is constructed in-place, and therefore + * without allocation overhead. It can be constructed and destructed + * repeatedly. + */ +template<class T> +class Manual { + using Storage = std::aligned_storage_t<sizeof(T), alignof(T)>; + + Storage storage; + +#ifndef NDEBUG + bool initialized = false; +#endif + +public: + using value_type = T; + using reference = T &; + using const_reference = const T &; + using pointer = T *; + using const_pointer = const T *; + +#ifndef NDEBUG + ~Manual() noexcept { + assert(!initialized); + } +#endif + + /** + * Cast a value reference to the containing Manual instance. + */ + static constexpr Manual<T> &Cast(reference value) noexcept { + return reinterpret_cast<Manual<T> &>(value); + } + + template<typename... Args> + void Construct(Args&&... args) { + assert(!initialized); + + ::new(&storage) T(std::forward<Args>(args)...); + +#ifndef NDEBUG + initialized = true; +#endif + } + + void Destruct() noexcept { + assert(initialized); + + reference t = Get(); + t.T::~T(); + +#ifndef NDEBUG + initialized = false; +#endif + } + + reference Get() noexcept { + assert(initialized); + + return *std::launder(reinterpret_cast<pointer>(&storage)); + } + + const_reference Get() const noexcept { + assert(initialized); + + return *std::launder(reinterpret_cast<const_pointer>(&storage)); + } + + operator reference() noexcept { + return Get(); + } + + operator const_reference() const noexcept { + return Get(); + } + + pointer operator->() noexcept { + return &Get(); + } + + const_pointer operator->() const noexcept { + return &Get(); + } +};
View file
ncmpc-0.47.tar.xz/src/util/MemberPointer.hxx
Added
@@ -0,0 +1,56 @@ +/* + * Copyright 2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +template<typename T> +struct MemberPointerHelper; + +template<typename C, typename M> +struct MemberPointerHelper<M C::*> { + using ContainerType = C; + using MemberType = M; +}; + +/** + * Given a member pointer, this determines the member type. + */ +template<typename T> +using MemberPointerType = + typename MemberPointerHelper<T>::MemberType; + +/** + * Given a member pointer, this determines the container type. + */ +template<typename T> +using MemberPointerContainerType = + typename MemberPointerHelper<T>::ContainerType;
View file
ncmpc-0.47.tar.xz/src/util/OffsetPointer.hxx
Added
@@ -0,0 +1,50 @@ +/* + * Copyright 2013-2022 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <cstddef> + +/** + * Offset the given pointer by the specified number of bytes. + */ +constexpr void * +OffsetPointer(void *p, std::ptrdiff_t offset) noexcept +{ + return static_cast<std::byte *>(p) + offset; +} + +/** + * Offset the given pointer by the specified number of bytes. + */ +constexpr const void * +OffsetPointer(const void *p, std::ptrdiff_t offset) noexcept +{ + return static_cast<const std::byte *>(p) + offset; +}
View file
ncmpc-0.47.tar.xz/src/util/OptionalCounter.hxx
Added
@@ -0,0 +1,74 @@ +/* + * Copyright 2022 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <cassert> +#include <cstddef> + +template<bool enable> class OptionalCounter; + +template<> +class OptionalCounter<false> +{ +public: + constexpr void reset() noexcept {} + constexpr auto &operator++() noexcept { return *this; } + constexpr auto &operator--() noexcept { return *this; } +}; + +template<> +class OptionalCounter<true> +{ + std::size_t value = 0; + +public: + constexpr operator std::size_t() const noexcept { + return value; + } + + constexpr void reset() noexcept { + value = 0; + } + + constexpr auto &operator++() noexcept { + ++value; + return *this; + } + + constexpr auto &operator--() noexcept { + assert(value > 0); + + --value; + return *this; + } +};
View file
ncmpc-0.36.tar.xz/src/util/PrintException.cxx -> ncmpc-0.47.tar.xz/src/util/PrintException.cxx
Changed
@@ -1,5 +1,5 @@ /* - * Copyright 2007-2019 Content Management AG + * Copyright 2007-2022 CM4all GmbH * All rights reserved. * * author: Max Kellermann <mk@cm4all.com>
View file
ncmpc-0.36.tar.xz/src/util/PrintException.hxx -> ncmpc-0.47.tar.xz/src/util/PrintException.hxx
Changed
@@ -1,5 +1,5 @@ /* - * Copyright 2007-2019 Content Management AG + * Copyright 2009-2022 CM4all GmbH * All rights reserved. * * author: Max Kellermann <mk@cm4all.com>
View file
ncmpc-0.36.tar.xz/src/util/RuntimeError.hxx -> ncmpc-0.47.tar.xz/src/util/RuntimeError.hxx
Changed
@@ -1,5 +1,5 @@ /* - * Copyright 2013-2017 Max Kellermann <max.kellermann@gmail.com> + * Copyright 2013-2020 Max Kellermann <max.kellermann@gmail.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,11 +30,17 @@ #ifndef RUNTIME_ERROR_HXX #define RUNTIME_ERROR_HXX -#include <stdexcept> +#include <stdexcept> // IWYU pragma: export #include <utility> #include <stdio.h> +#if defined(__clang__) || defined(__GNUC__) +#pragma GCC diagnostic push +// TODO: fix this warning properly +#pragma GCC diagnostic ignored "-Wformat-security" +#endif + template<typename... Args> static inline std::runtime_error FormatRuntimeError(const char *fmt, Args&&... args) noexcept @@ -53,4 +59,8 @@ return std::invalid_argument(buffer); } +#if defined(__clang__) || defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + #endif
View file
ncmpc-0.36.tar.xz/src/util/StringAPI.hxx -> ncmpc-0.47.tar.xz/src/util/StringAPI.hxx
Changed
@@ -1,5 +1,5 @@ /* - * Copyright 2010-2019 Max Kellermann <max.kellermann@gmail.com> + * Copyright 2010-2021 Max Kellermann <max.kellermann@gmail.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,71 +30,69 @@ #ifndef STRING_API_HXX #define STRING_API_HXX -#include "Compiler.h" - -#include <string.h> +#include <cstring> #ifdef _UNICODE #include "WStringAPI.hxx" #endif -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline size_t StringLength(const char *p) noexcept { return strlen(p); } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline const char * StringFind(const char *haystack, const char *needle) noexcept { return strstr(haystack, needle); } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline char * StringFind(char *haystack, char needle, size_t size) noexcept { - return (char *)memchr(haystack, needle, size); + return (char *)std::memchr(haystack, needle, size); } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline const char * StringFind(const char *haystack, char needle, size_t size) noexcept { - return (const char *)memchr(haystack, needle, size); + return (const char *)std::memchr(haystack, needle, size); } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline const char * StringFind(const char *haystack, char needle) noexcept { - return strchr(haystack, needle); + return std::strchr(haystack, needle); } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline char * StringFind(char *haystack, char needle) noexcept { - return strchr(haystack, needle); + return std::strchr(haystack, needle); } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline const char * StringFindLast(const char *haystack, char needle) noexcept { - return strrchr(haystack, needle); + return std::strrchr(haystack, needle); } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline char * StringFindLast(char *haystack, char needle) noexcept { - return strrchr(haystack, needle); + return std::strrchr(haystack, needle); } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline const char * StringFindLast(const char *haystack, char needle, size_t size) noexcept { @@ -115,7 +113,7 @@ #endif } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline const char * StringFindAny(const char *haystack, const char *accept) noexcept { @@ -128,14 +126,14 @@ return strtok(str, delim); } -gcc_nonnull_all +gnu::nonnull static inline void UnsafeCopyString(char *dest, const char *src) noexcept { strcpy(dest, src); } -gcc_returns_nonnull gcc_nonnull_all +gnu::returns_nonnull gnu::nonnull static inline char * UnsafeCopyStringP(char *dest, const char *src) noexcept { @@ -148,14 +146,14 @@ #endif } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline int StringCompare(const char *a, const char *b) noexcept { return strcmp(a, b); } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline int StringCompare(const char *a, const char *b, size_t n) noexcept { @@ -165,7 +163,7 @@ /** * Checks whether #a and #b are equal. */ -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline bool StringIsEqual(const char *a, const char *b) noexcept { @@ -175,28 +173,36 @@ /** * Checks whether #a and #b are equal. */ -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline bool StringIsEqual(const char *a, const char *b, size_t length) noexcept { return strncmp(a, b, length) == 0; } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline bool StringIsEqualIgnoreCase(const char *a, const char *b) noexcept { +#ifdef _MSC_VER + return _stricmp(a, b) == 0; +#else return strcasecmp(a, b) == 0; +#endif } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline bool StringIsEqualIgnoreCase(const char *a, const char *b, size_t size) noexcept { +#ifdef _MSC_VER + return _strnicmp(a, b, size) == 0; +#else return strncasecmp(a, b, size) == 0; +#endif } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline int StringCollate(const char *a, const char *b) noexcept { @@ -207,7 +213,7 @@ * Copy the string to a new allocation. The return value must be * freed with free(). */ -gcc_malloc gcc_returns_nonnull gcc_nonnull_all +gnu::malloc gnu::returns_nonnull gnu::nonnull static inline char * DuplicateString(const char *p) noexcept {
View file
ncmpc-0.36.tar.xz/src/util/StringCompare.cxx -> ncmpc-0.47.tar.xz/src/util/StringCompare.cxx
Changed
@@ -1,5 +1,5 @@ /* - * Copyright 2013-2018 Max Kellermann <max.kellermann@gmail.com> + * Copyright 2013-2022 Max Kellermann <max.kellermann@gmail.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,6 +29,8 @@ #include "StringCompare.hxx" +#include <cstring> + bool StringEndsWith(const char *haystack, const char *needle) noexcept { @@ -36,8 +38,8 @@ const size_t needle_length = StringLength(needle); return haystack_length >= needle_length && - memcmp(haystack + haystack_length - needle_length, - needle, needle_length) == 0; + std::memcmp(haystack + haystack_length - needle_length, + needle, needle_length) == 0; } bool @@ -61,7 +63,7 @@ return nullptr; const char *q = p + p_length - suffix_length; - return memcmp(q, suffix, suffix_length) == 0 + return std::memcmp(q, suffix, suffix_length) == 0 ? q : nullptr; }
View file
ncmpc-0.36.tar.xz/src/util/StringCompare.hxx -> ncmpc-0.47.tar.xz/src/util/StringCompare.hxx
Changed
@@ -1,5 +1,5 @@ /* - * Copyright 2013-2018 Max Kellermann <max.kellermann@gmail.com> + * Copyright 2013-2022 Max Kellermann <max.kellermann@gmail.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,33 +30,49 @@ #ifndef STRING_COMPARE_HXX #define STRING_COMPARE_HXX -#include "StringView.hxx" #include "StringAPI.hxx" -#include "Compiler.h" #ifdef _UNICODE #include "WStringCompare.hxx" #endif -gcc_pure gcc_nonnull_all +#include <string_view> + +gnu::pure gnu::nonnull static inline bool StringIsEmpty(const char *string) noexcept { return *string == 0; } -gcc_pure gcc_nonnull_all +gnu::pure +static inline bool +StringIsEqual(std::string_view a, std::string_view b) noexcept +{ + return a.size() == b.size() && + StringIsEqual(a.data(), b.data(), b.size()); +} + +gnu::pure static inline bool -StringStartsWith(const char *haystack, StringView needle) noexcept +StringIsEqualIgnoreCase(std::string_view a, std::string_view b) noexcept { - return StringIsEqual(haystack, needle.data, needle.size); + return a.size() == b.size() && + StringIsEqualIgnoreCase(a.data(), b.data(), b.size()); } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull +static inline bool +StringStartsWith(const char *haystack, std::string_view needle) noexcept +{ + return StringIsEqual(haystack, needle.data(), needle.size()); +} + +gnu::pure gnu::nonnull bool StringEndsWith(const char *haystack, const char *needle) noexcept; -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull bool StringEndsWithIgnoreCase(const char *haystack, const char *needle) noexcept; @@ -65,36 +81,61 @@ * does not begin with the specified prefix, this function returns * nullptr. */ -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull static inline const char * -StringAfterPrefix(const char *haystack, StringView needle) noexcept +StringAfterPrefix(const char *haystack, std::string_view needle) noexcept { return StringStartsWith(haystack, needle) - ? haystack + needle.size + ? haystack + needle.size() : nullptr; } -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull +static inline bool +StringStartsWithIgnoreCase(const char *haystack, std::string_view needle) noexcept +{ + return StringIsEqualIgnoreCase(haystack, needle.data(), needle.size()); +} + +gnu::pure static inline bool -StringStartsWithIgnoreCase(const char *haystack, StringView needle) noexcept +StringStartsWithIgnoreCase(std::string_view haystack, std::string_view needle) noexcept { - return StringIsEqualIgnoreCase(haystack, needle.data, needle.size); + return haystack.size() >= needle.size() && + StringIsEqualIgnoreCase(haystack.data(), + needle.data(), needle.size()); } -gcc_pure gcc_nonnull_all +/** + * Returns the portion of the string after a prefix. If the string + * does not begin with the specified prefix, this function returns + * nullptr. + * This function is case-independent. + */ +gnu::pure gnu::nonnull static inline const char * -StringAfterPrefixIgnoreCase(const char *haystack, StringView needle) noexcept +StringAfterPrefixIgnoreCase(const char *haystack, std::string_view needle) noexcept { return StringStartsWithIgnoreCase(haystack, needle) - ? haystack + needle.size + ? haystack + needle.size() : nullptr; } +gnu::pure +static inline std::string_view +StringAfterPrefixIgnoreCase(std::string_view haystack, + std::string_view needle) noexcept +{ + return StringStartsWithIgnoreCase(haystack, needle) + ? haystack.substr(needle.size()) + : std::string_view{}; +} + /** * Check if the given string ends with the specified suffix. If yes, * returns the position of the suffix, and nullptr otherwise. */ -gcc_pure gcc_nonnull_all +gnu::pure gnu::nonnull const char * FindStringSuffix(const char *p, const char *suffix) noexcept;
View file
ncmpc-0.36.tar.xz/src/util/StringStrip.cxx -> ncmpc-0.47.tar.xz/src/util/StringStrip.cxx
Changed
@@ -1,5 +1,5 @@ /* - * Copyright 2009-2018 Max Kellermann <max.kellermann@gmail.com> + * Copyright 2009-2020 Max Kellermann <max.kellermann@gmail.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,7 +30,7 @@ #include "StringStrip.hxx" #include "CharUtil.hxx" -#include <string.h> +#include <cstring> const char * StripLeft(const char *p) noexcept @@ -59,8 +59,8 @@ return end; } -size_t -StripRight(const char *p, size_t length) noexcept +std::size_t +StripRight(const char *p, std::size_t length) noexcept { while (length > 0 && IsWhitespaceOrNull(plength - 1)) --length; @@ -71,8 +71,8 @@ void StripRight(char *p) noexcept { - size_t old_length = strlen(p); - size_t new_length = StripRight(p, old_length); + std::size_t old_length = std::strlen(p); + std::size_t new_length = StripRight(p, old_length); pnew_length = 0; }
View file
ncmpc-0.36.tar.xz/src/util/StringStrip.hxx -> ncmpc-0.47.tar.xz/src/util/StringStrip.hxx
Changed
@@ -1,5 +1,5 @@ /* - * Copyright 2009-2018 Max Kellermann <max.kellermann@gmail.com> + * Copyright 2009-2020 Max Kellermann <max.kellermann@gmail.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,9 +30,7 @@ #ifndef STRING_STRIP_HXX #define STRING_STRIP_HXX -#include "Compiler.h" - -#include <stddef.h> +#include <cstddef> /** * Skips whitespace at the beginning of the string, and returns the @@ -40,11 +38,11 @@ * non-whitespace characters, then a pointer to the NULL terminator is * returned. */ -gcc_pure gcc_returns_nonnull gcc_nonnull_all +gnu::pure gnu::returns_nonnull gnu::nonnull const char * StripLeft(const char *p) noexcept; -gcc_pure gcc_returns_nonnull gcc_nonnull_all +gnu::pure gnu::returns_nonnull gnu::nonnull static inline char * StripLeft(char *p) noexcept { @@ -55,21 +53,21 @@ * Skips whitespace at the beginning of the string, and returns the * first non-whitespace character or the end pointer. */ -gcc_pure gcc_returns_nonnull gcc_nonnull_all +gnu::pure gnu::returns_nonnull gnu::nonnull const char * StripLeft(const char *p, const char *end) noexcept; /** * Determine the string's end as if it was stripped on the right side. */ -gcc_pure gcc_returns_nonnull gcc_nonnull_all +gnu::pure gnu::returns_nonnull gnu::nonnull const char * StripRight(const char *p, const char *end) noexcept; /** * Determine the string's end as if it was stripped on the right side. */ -gcc_pure gcc_returns_nonnull gcc_nonnull_all +gnu::pure gnu::returns_nonnull gnu::nonnull static inline char * StripRight(char *p, char *end) noexcept { @@ -81,14 +79,14 @@ * Determine the string's length as if it was stripped on the right * side. */ -gcc_pure gcc_nonnull_all -size_t -StripRight(const char *p, size_t length) noexcept; +gnu::pure gnu::nonnull +std::size_t +StripRight(const char *p, std::size_t length) noexcept; /** * Strip trailing whitespace by null-terminating the string. */ -gcc_nonnull_all +gnu::nonnull void StripRight(char *p) noexcept; @@ -96,7 +94,7 @@ * Skip whitespace at the beginning and terminate the string after the * last non-whitespace character. */ -gcc_returns_nonnull gcc_nonnull_all +gnu::returns_nonnull gnu::nonnull char * Strip(char *p) noexcept;
View file
ncmpc-0.36.tar.xz/src/util/StringUTF8.cxx -> ncmpc-0.47.tar.xz/src/util/StringUTF8.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -58,7 +57,7 @@ #endif -gcc_pure +gnu::pure int CollateUTF8(const char *a, const char *b) {
View file
ncmpc-0.36.tar.xz/src/util/StringUTF8.hxx -> ncmpc-0.47.tar.xz/src/util/StringUTF8.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -21,7 +20,6 @@ #define STRING_UTF8_HXX #include "config.h" -#include "Compiler.h" class ScopeInitUTF8 { #ifdef HAVE_LOCALE_T @@ -34,7 +32,7 @@ #endif }; -gcc_pure +gnu::pure int CollateUTF8(const char *a, const char *b);
View file
ncmpc-0.36.tar.xz/src/util/UriUtil.cxx -> ncmpc-0.47.tar.xz/src/util/UriUtil.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -22,17 +21,18 @@ #include <string.h> const char * -GetUriFilename(const char *uri) +GetUriFilename(const char *uri) noexcept { const char *slash = strrchr(uri, '/'); return slash != nullptr ? slash + 1 : uri; } -std::string -GetParentUri(const char *uri) +std::string_view +GetParentUri(std::string_view uri) noexcept { - const char *slash = strrchr(uri, '/'); - if (slash == nullptr) - slash = uri; - return std::string(uri, slash); + const auto slash = uri.rfind('/'); + if (slash == uri.npos) + return {}; + + return uri.substr(0, slash); }
View file
ncmpc-0.36.tar.xz/src/util/UriUtil.hxx -> ncmpc-0.47.tar.xz/src/util/UriUtil.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -20,8 +19,6 @@ #ifndef URI_UTIL_HXX #define URI_UTIL_HXX -#include "Compiler.h" - #include <string> /** @@ -29,17 +26,17 @@ * after the last slash. May return an empty string if the URI ends * with a slash. */ -gcc_pure +gnu::pure const char * -GetUriFilename(const char *uri); +GetUriFilename(const char *uri) noexcept; /** * Return the "parent directory" of the given URI path, i.e. the * portion up to the last (forward) slash. Returns an empty string if * there is no parent. */ -gcc_pure -std::string -GetParentUri(const char *uri); +gnu::pure +std::string_view +GetParentUri(std::string_view uri) noexcept; #endif
View file
ncmpc-0.36.tar.xz/src/wreadln.cxx -> ncmpc-0.47.tar.xz/src/wreadln.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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 @@ -81,7 +80,7 @@ void Paint() const noexcept; /** returns the screen column where the cursor is located */ - gcc_pure + gnu::pure unsigned GetCursorColumn() const noexcept; /** move the cursor one step to the right */ @@ -104,7 +103,7 @@ static constexpr std::size_t wrln_max_history_length = 32; /** converts a byte position to a screen column */ -gcc_pure +gnu::pure static unsigned byte_to_screen(const char *data, size_t x) noexcept { @@ -120,7 +119,7 @@ } /** finds the first character which doesn't fit on the screen */ -gcc_pure +gnu::pure static size_t screen_to_bytes(const char *data, unsigned width) noexcept { @@ -149,7 +148,7 @@ /** returns the offset in the string to align it at the right border of the screen */ -gcc_pure +gnu::pure static inline size_t right_align_bytes(const char *data, size_t right, unsigned width) noexcept { @@ -365,6 +364,7 @@ #endif break; + case KEY_CTRL_C: case KEY_CTRL_G: screen_bell(); if (history) {
View file
ncmpc-0.36.tar.xz/src/wreadln.hxx -> ncmpc-0.47.tar.xz/src/wreadln.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/xterm_title.cxx -> ncmpc-0.47.tar.xz/src/xterm_title.cxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
View file
ncmpc-0.36.tar.xz/src/xterm_title.hxx -> ncmpc-0.47.tar.xz/src/xterm_title.hxx
Changed
@@ -1,6 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2019 The Music Player Daemon Project - * Project homepage: http://musicpd.org + * Copyright 2004-2021 The Music Player Daemon Project * * 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
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.