From 636ca1120972dc7a02c99ff92fd0d7d97f3c4512 Mon Sep 17 00:00:00 2001 From: darrell-k Date: Fri, 17 Oct 2025 22:43:24 +0100 Subject: [PATCH 001/140] initial commit Signed-off-by: darrell-k --- Slim/Control/Queries.pm | 100 ++++++++++++++++++++++++++++++------- Slim/Control/XMLBrowser.pm | 8 +-- Slim/Schema.pm | 10 ++-- Slim/Schema/RemoteTrack.pm | 15 +++++- 4 files changed, 106 insertions(+), 27 deletions(-) diff --git a/Slim/Control/Queries.pm b/Slim/Control/Queries.pm index 96e74bc55bd..d3790e2b846 100644 --- a/Slim/Control/Queries.pm +++ b/Slim/Control/Queries.pm @@ -4740,6 +4740,8 @@ sub titlesQuery { my $ignoreWorkTracks = $request->getParam('ignore_work_tracks'); my $performance = $request->getParam('performance'); my $onlyAlbumYears = $request->getParam('only_album_years'); + my $remoteAlbumId = $request->getParam('remote_album_id'); + my $onlineService = $request->getParam('service'); # did we have override on the defaults? # note that this is not equivalent to @@ -4795,6 +4797,8 @@ sub titlesQuery { workId => $workID, libraryId => $libraryID, onlyAlbumYears=> $onlyAlbumYears, + remoteAlbumId => $remoteAlbumId, + onlineService => $onlineService, limit => sub { $count = shift; @@ -4813,26 +4817,62 @@ sub titlesQuery { $count += 0; - my $loopname = 'titles_loop'; - # this is the count of items in this part of the request (e.g., menu 100 200) - # not to be confused with $count, which is the count of the entire list - my $chunkCount = 0; + # is it a remote album that's not in the database? + my $handler; + if ( !scalar @{$itemOrder} && $remoteAlbumId && $onlineService ) { + my $url = $onlineService . ':album:' . $remoteAlbumId; + $handler = Slim::Player::ProtocolHandlers->handlerForURL($url); + } + if ( $handler && $handler->can('getAlbumTracks') ) { + + $request->setStatusProcessing(); + $handler->getAlbumTracks(sub{ + ($items, $itemOrder, $totalCount) = @_; - if ( scalar @{$itemOrder} ) { + my $loopname = 'titles_loop'; + my $chunkCount = 0; - for my $trackId ( @{$itemOrder} ) { - my $item = $items->{$trackId}; + if ( scalar @{$itemOrder} ) { - _addSong($request, $loopname, $chunkCount, $item, $tags); + for my $trackId ( @{$itemOrder} ) { + my $item = $items->{$trackId}; - $chunkCount++; - } + _addSong($request, $loopname, $chunkCount, $item, $tags); + + $chunkCount++; + } + + } + + $request->addResult('count', $totalCount); + + $request->setStatusDone(); + }, $request->client, $remoteAlbumId); } + else { - $request->addResult('count', $totalCount); + my $loopname = 'titles_loop'; + # this is the count of items in this part of the request (e.g., menu 100 200) + # not to be confused with $count, which is the count of the entire list + my $chunkCount = 0; - $request->setStatusDone(); + if ( scalar @{$itemOrder} ) { + + for my $trackId ( @{$itemOrder} ) { + my $item = $items->{$trackId}; + + _addSong($request, $loopname, $chunkCount, $item, $tags); + + $chunkCount++; + } + + } + + $request->addResult('count', $totalCount); + + $request->setStatusDone(); + } } @@ -5823,17 +5863,28 @@ sub _songData { $song = $client->currentSongForUrl($url); } + my $service; if ( $isRemote ) { my $handler = Slim::Player::ProtocolHandlers->handlerForURL($url); if ( $handler && $handler->can('getMetadataFor') ) { + $service = (split(/:/, $url))[0]; # Don't modify source data $remoteMeta = Storable::dclone( $handler->getMetadataFor( $request->client, $url ) ); + my @extArtistIds = split /,/, $remoteMeta->{artistId}; + my @artistIds; + foreach (@extArtistIds) { + my $artistObj = Slim::Schema->rs("Contributor")->search( extid => "$service:artist:$_" )->single; + push @artistIds, $artistObj ? $artistObj->id : $_ * -1; + } + $remoteMeta->{artistId} = join ',', @artistIds; + $remoteMeta->{a} = $remoteMeta->{artist}; $remoteMeta->{A} = $remoteMeta->{artist}; + $remoteMeta->{e} = $remoteMeta->{albumId}; $remoteMeta->{E} = $remoteMeta->{extid}; $remoteMeta->{l} = $remoteMeta->{album}; $remoteMeta->{i} = $remoteMeta->{disc}; @@ -5877,6 +5928,7 @@ sub _songData { $returnHash{'id'} = $track->id; $returnHash{'title'} = $remoteMeta->{title} || $track->title; + $returnHash{'service_id'} = $service if $service; my %seen; # loop so that stuff is returned in the order given... @@ -5906,6 +5958,10 @@ sub _songData { elsif ($tag eq 'b') { $returnHash{work} = $remoteMeta->{$tag}; $returnHash{composer} = $remoteMeta->{composer} if $remoteMeta->{composer}; + if ( $remoteMeta->{composerId} ) { + my $composerObj = Slim::Schema->rs("Contributor")->search( extid => "$service:artist:" . $remoteMeta->{composerId} )->single; + $returnHash{composer_ids} = $composerObj ? $composerObj->id . "" : $remoteMeta->{composerId} * -1 . ""; + } } # Special case for 2: at track level, triggers addition of the play queue context $addedFromWork @@ -5917,6 +5973,7 @@ sub _songData { elsif ($tag eq 'A' || $tag eq 'S') { if ( my $meta = $remoteMeta->{$tag} ) { $returnHash{artist} = $meta; + $returnHash{artist_ids} = $remoteMeta->{artistId} if $remoteMeta->{artistId}; next; } elsif ( $track->isa('Slim::Schema::RemoteTrack')) { @@ -6005,6 +6062,7 @@ sub _songData { } # we might need to proxy the image request to resize it elsif ($tag eq 'K' && $value) { + $returnHash{baseImage} = URI::Escape::uri_escape_utf8($value); $value = proxiedImage($value); } @@ -6289,12 +6347,6 @@ sub _getTagDataForTracks { } } - if ( my $libraryId = Slim::Music::VirtualLibraries->getRealId($args->{libraryId}) ) { - $sql .= 'JOIN library_track ON library_track.track = tracks.id '; - push @{$w}, 'library_track.library = ?'; - push @{$p}, $libraryId; - } - # Some helper functions to setup joins with less code my $join_genre_track = sub { if ( $sql !~ /JOIN genre_track/ ) { @@ -6336,6 +6388,18 @@ sub _getTagDataForTracks { } }; + if ( $args->{remoteAlbumId} && $args->{onlineService} ) { + my $remoteAlbumId = $args->{remoteAlbumId}; + my $onlineService = $args->{onlineService}; + $join_albums->(); + push @{$w}, 'albums.extid = ?'; + push @{$p}, $onlineService . ':album:' . $remoteAlbumId; + } elsif ( my $libraryId = Slim::Music::VirtualLibraries->getRealId($args->{libraryId}) ) { + $sql .= 'JOIN library_track ON library_track.track = tracks.id '; + push @{$w}, 'library_track.library = ?'; + push @{$p}, $libraryId; + } + if ( my $year = $args->{year} ) { push @{$w}, 'tracks.year = ?'; push @{$p}, $year; diff --git a/Slim/Control/XMLBrowser.pm b/Slim/Control/XMLBrowser.pm index 40a0c20a474..0c037d999ed 100644 --- a/Slim/Control/XMLBrowser.pm +++ b/Slim/Control/XMLBrowser.pm @@ -50,11 +50,11 @@ my %colMap = ( G => 'genres', i => 'discnum', k => 'description', - l => ['album','version'], + l => ['album','version','remoteAlbumId'], q => 'disccount', t => ['tracknum','title','titleFlags'], # "date" is being used in Podcast episodes - y => ['year','date'], + 'y' => ['year','date'], ); sub cliQuery { @@ -695,7 +695,7 @@ sub _cliQuery_done { && (defined $subFeed->{'name'} || defined $subFeed->{'title'}) && ($method !~ /all/)) { - my $title = $subFeed->{'name'} || $subFeed->{'title'}; + my $title = $subFeed->{'album'} && $subFeed->{'artist'} ? $subFeed->{'title'} : $subFeed->{'name'}; my $url = $subFeed->{'url'}; # Podcast enclosures @@ -721,6 +721,8 @@ sub _cliQuery_done { bitrate => $subFeed->{'bitrate'}, cover => $subFeed->{'cover'} || $subFeed->{'image'} || $subFeed->{'icon'} || $request->getParam('icon'), year => $subFeed->{'year'}, + album => $subFeed->{'album'}, + artist => $subFeed->{'artist'}, } ); $client->execute([ 'playlist', $method, $url ]); diff --git a/Slim/Schema.pm b/Slim/Schema.pm index b7a57d6827e..2c656d15e59 100644 --- a/Slim/Schema.pm +++ b/Slim/Schema.pm @@ -2824,13 +2824,15 @@ sub _preCheckAttributes { # since the tag may need to be split. See bugs #295 and #4584. # # Push these back until we have a Track object. - for my $tag (Slim::Schema::Contributor->contributorRoles, (map { $_ . 'SORT' } Slim::Schema::Contributor->contributorRoles()), + for my $tag (Slim::Schema::Contributor->contributorRoles, + (map { $_ . 'SORT' } Slim::Schema::Contributor->contributorRoles()), + (map { $_ . '_EXTID' } Slim::Schema::Contributor->contributorRoles()), qw( COMMENT GENRE PIC APIC ALBUM ALBUMSORT DISCC COMPILATION REPLAYGAIN_ALBUM_PEAK REPLAYGAIN_ALBUM_GAIN MUSICBRAINZ_ARTIST_ID MUSICBRAINZ_ALBUMARTIST_ID MUSICBRAINZ_ALBUM_ID MUSICBRAINZ_ALBUM_TYPE MUSICBRAINZ_ALBUM_STATUS RELEASETYPE - ALBUM_EXTID ARTIST_EXTID WORK WORKSORT + ALBUM_EXTID WORK WORKSORT )) { @@ -3114,6 +3116,7 @@ sub _mergeAndCreateContributors { # Bug: 6507 - use any ARTISTSORT tag for this contributor $attributes->{'TRACKARTISTSORT'} = delete $attributes->{'ARTISTSORT'}; $attributes->{'MUSICBRAINZ_TRACKARTIST_ID'} = delete $attributes->{'MUSICBRAINZ_ARTIST_ID'} if $attributes->{'MUSICBRAINZ_ARTIST_ID'}; + $attributes->{'TRACKARTIST_EXTID'} = delete $attributes->{'ARTIST_EXTID'}; main::DEBUGLOG && $isDebug && $log->debug(sprintf("-- Contributor '%s' of role 'ARTIST' transformed to role 'TRACKARTIST'", $attributes->{'TRACKARTIST'}, @@ -3138,8 +3141,7 @@ sub _mergeAndCreateContributors { 'artist' => $contributor, 'brainzID' => $attributes->{"MUSICBRAINZ_${tag}_ID"}, 'sortBy' => $attributes->{$tag.'SORT'}, - # only store EXTID for track artist, as we don't have it for other roles - 'extid' => $tag eq 'ARTIST' && $attributes->{'ARTIST_EXTID'}, + 'extid' => $attributes->{"${tag}_EXTID"}, }); main::DEBUGLOG && $isDebug && $log->is_debug && $log->debug(sprintf("-- Track has contributor '$contributor' of role '$tag'")); diff --git a/Slim/Schema/RemoteTrack.pm b/Slim/Schema/RemoteTrack.pm index d3cb989f5f6..ec70a4717cd 100644 --- a/Slim/Schema/RemoteTrack.pm +++ b/Slim/Schema/RemoteTrack.pm @@ -13,6 +13,7 @@ use strict; use base qw(Slim::Utils::Accessor); use Scalar::Util qw(blessed); +use Digest::MD5 qw(md5_hex); use Tie::Cache::LRU; use Slim::Utils::Cache; @@ -63,6 +64,7 @@ my @allAttributes = (qw( performance discsubtitle added_from_work + artistid )); { @@ -110,7 +112,7 @@ sub init { # Emulate absent methods - hopefully these can be retired at some time sub artists {return ();} -sub artistid {} +#sub artistid {} sub genres {return ();} sub genrename {} sub genreid {} @@ -348,6 +350,15 @@ my $separator; sub setAttributes { my ($self, $attributes) = @_; + my $url = $self->_url; + if ( $url !~ "^http" && Slim::Music::Info::isRemoteURL($url) ) { + my $handler = Slim::Player::ProtocolHandlers->handlerForURL( $url ); + if ( $handler && $handler->can('getMetadataFor') ) { + if ( my $meta = $handler->getMetadataFor( undef, $url ) ) {; + $attributes = $meta; + } + } + } %availableTags = map { $_ => 1 } @allAttributes unless keys %availableTags; @@ -375,7 +386,7 @@ sub setAttributes { main::DEBUGLOG && $log->is_debug && defined $self->$key() && $self->$key() ne $value && $log->debug("$key: ", $self->$key(), "=>$value"); - $self->$key($value); + $self->$key($value) if !$self->$key || $value; } } From 945f60118a2b11bdb950da32711b4a5bf7082250 Mon Sep 17 00:00:00 2001 From: darrell-k Date: Fri, 7 Nov 2025 14:57:49 +0000 Subject: [PATCH 002/140] further WIP Signed-off-by: darrell-k --- Slim/Control/Queries.pm | 16 ++++++++++++++++ Slim/Schema/RemoteTrack.pm | 24 +++++++++++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/Slim/Control/Queries.pm b/Slim/Control/Queries.pm index 5eaacf2591c..5623b55029f 100644 --- a/Slim/Control/Queries.pm +++ b/Slim/Control/Queries.pm @@ -4823,7 +4823,11 @@ sub titlesQuery { my $url = $onlineService . ':album:' . $remoteAlbumId; $handler = Slim::Player::ProtocolHandlers->handlerForURL($url); } + #--- + # this change gets rendered by git diff in a very confusing way. All we're doing is adding this "if" and indenting + # the existing code in an "else". if ( $handler && $handler->can('getAlbumTracks') ) { + # we have an online service handler that can return album tracks in the expected format $request->setStatusProcessing(); $handler->getAlbumTracks(sub{ @@ -4850,6 +4854,7 @@ sub titlesQuery { }, $request->client, $remoteAlbumId); } + #--- else { my $loopname = 'titles_loop'; @@ -5874,6 +5879,11 @@ sub _songData { $handler->getMetadataFor( $request->client, $url ) ); + # if the artist is in the database, use their local id. If not, use the remote service id multiplied by -1 + # so clients can distinguish between the two possibilities. + #------------------------------------------------------------------------------------- + ### !!! Needs extra thought here: what if the remote service artist id is not numeric? + #------------------------------------------------------------------------------------- my @extArtistIds = split /,/, $remoteMeta->{artistId}; my @artistIds; foreach (@extArtistIds) { @@ -5958,6 +5968,11 @@ sub _songData { elsif ($tag eq 'b') { $returnHash{work} = $remoteMeta->{$tag}; $returnHash{composer} = $remoteMeta->{composer} if $remoteMeta->{composer}; + # if the composer is in the database, use their local id. If not, use the remote service id multiplied by -1 + # so clients can distinguish between the two possibilities. + #------------------------------------------------------------------------------------- + ### !!! Needs extra thought here: what if the remote service composer id is not numeric? + #------------------------------------------------------------------------------------- if ( $remoteMeta->{composerId} ) { my $composerObj = Slim::Schema->rs("Contributor")->search( extid => "$service:artist:" . $remoteMeta->{composerId} )->single; $returnHash{composer_ids} = $composerObj ? $composerObj->id . "" : $remoteMeta->{composerId} * -1 . ""; @@ -6389,6 +6404,7 @@ sub _getTagDataForTracks { }; if ( $args->{remoteAlbumId} && $args->{onlineService} ) { + # allow retrieval of track by remote album id. my $remoteAlbumId = $args->{remoteAlbumId}; my $onlineService = $args->{onlineService}; $join_albums->(); diff --git a/Slim/Schema/RemoteTrack.pm b/Slim/Schema/RemoteTrack.pm index ec70a4717cd..e9819007808 100644 --- a/Slim/Schema/RemoteTrack.pm +++ b/Slim/Schema/RemoteTrack.pm @@ -350,15 +350,21 @@ my $separator; sub setAttributes { my ($self, $attributes) = @_; - my $url = $self->_url; - if ( $url !~ "^http" && Slim::Music::Info::isRemoteURL($url) ) { - my $handler = Slim::Player::ProtocolHandlers->handlerForURL( $url ); - if ( $handler && $handler->can('getMetadataFor') ) { - if ( my $meta = $handler->getMetadataFor( undef, $url ) ) {; - $attributes = $meta; - } - } - } + +#-------------- +# leaving this here as a reminder, commented out for now, because something like this is required to make sure that the play queue +# is formatted correctly after a restart in default/classic skins. But it needs amendment because it causes problems +# for plugins (eg BBC Sounds) where getMetadataFor fails without a client. +#-------------- +# my $url = $self->_url; +# if ( $url !~ "^http" && Slim::Music::Info::isRemoteURL($url) ) { +# my $handler = Slim::Player::ProtocolHandlers->handlerForURL( $url ); +# if ( $handler && $handler->can('getMetadataFor') ) { +# if ( my $meta = $handler->getMetadataFor( undef, $url ) ) {; +# $attributes = $meta; +# } +# } +# } %availableTags = map { $_ => 1 } @allAttributes unless keys %availableTags; From b12ab2a83f95a5cc530e93ca4a38d4cec8f782eb Mon Sep 17 00:00:00 2001 From: Michael Herger Date: Fri, 7 Nov 2025 16:41:12 +0100 Subject: [PATCH 003/140] Tweak build pipeline: cache results, don't run unnecessary steps for the Docker build Signed-off-by: Michael Herger --- .github/actions/build/action.yaml | 2 ++ .github/workflows/00_build.yaml | 7 ++++--- .github/workflows/00_smoketest.yaml | 12 +++++++++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.github/actions/build/action.yaml b/.github/actions/build/action.yaml index e74a8112e0e..f2c6d23fa30 100644 --- a/.github/actions/build/action.yaml +++ b/.github/actions/build/action.yaml @@ -120,12 +120,14 @@ runs: fi - name: Cache s5cmd + if: ${{ !startsWith(inputs.build-params, 'docker') }} uses: actions/cache@v4 with: key: s5cmd-${{ runner.os }} path: ${{ runner.temp }}/s5cmd-bin - name: Check if s5cmd is installed + if: ${{ !startsWith(inputs.build-params, 'docker') }} id: check-s5cmd continue-on-error: true shell: bash diff --git a/.github/workflows/00_build.yaml b/.github/workflows/00_build.yaml index b91059f0952..5479fc6a1b0 100644 --- a/.github/workflows/00_build.yaml +++ b/.github/workflows/00_build.yaml @@ -96,9 +96,10 @@ jobs: - name: Prepare build environment if: ${{ matrix.flavour[0] != 'tarball' && matrix.flavour[0] != 'pcp' }} - run: | - sudo apt update - sudo apt install -y apt-transport-https debhelper devscripts + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: apt-transport-https debhelper devscripts + version: 1 - name: Launch build process uses: ./server/.github/actions/build diff --git a/.github/workflows/00_smoketest.yaml b/.github/workflows/00_smoketest.yaml index c86d6b82ee6..3c08c4c9446 100644 --- a/.github/workflows/00_smoketest.yaml +++ b/.github/workflows/00_smoketest.yaml @@ -21,10 +21,16 @@ jobs: - uses: actions/checkout@v4 - name: Install dependencies + if: ${{ !env.ACT }} + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: libio-socket-ssl-perl libnet-ssleay-perl netcat-traditional + version: 1 + + - name: Install dependencies (ACT fallback) + if: ${{ env.ACT }} run: | - if [ "$ACT" == "true" ]; then - sudo apt-get update - fi + sudo apt-get update sudo apt-get install -y libio-socket-ssl-perl libnet-ssleay-perl netcat-traditional - name: Test Strings File From 24862ec65f4d6b4d2dcc2bf42392cddf7a9a2047 Mon Sep 17 00:00:00 2001 From: Michael Herger Date: Sun, 9 Nov 2025 12:05:16 +0100 Subject: [PATCH 004/140] Tweak the Issue template Signed-off-by: Michael Herger --- .github/ISSUE_TEMPLATE/bug_report.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b186efb9571..87ad15a79e9 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -25,10 +25,12 @@ If applicable, add screenshots to help explain your problem. **System Information (please complete the following information):** - OS on which you're running LMS: [e.g. pCP 10] + - Hardware on which you're running LMS (x86_64, aarch64, ARM, ...) - Web skin used: [e.g. Material, Default] - - Browser [e.g. chrome, safari] - - LMS Version [e.g. 22] + - Browser [e.g. Chrome, Safari] + - LMS Version - Player(s) involved + - Addition information from the Settings/Information header section **Additional context** Add any other context about the problem here. E.g. a `server.log` or `scanner.log` snippet (see Settings/Information in your LMS) From 0bf641cb2291c6d193779d5b73856b4ec8a0c936 Mon Sep 17 00:00:00 2001 From: mipa87 <62723159+mipa87@users.noreply.github.com> Date: Mon, 10 Nov 2025 00:51:04 +0100 Subject: [PATCH 005/140] Update Czech translations --- HTML/EN/settings/wizard.json | 11 ++ Slim/Plugin/Analytics/strings.txt | 2 +- Slim/Plugin/ExtendedBrowseModes/strings.txt | 5 +- Slim/Plugin/Favorites/strings.txt | 4 +- Slim/Plugin/FullTextSearch/strings.txt | 2 +- Slim/Plugin/Podcast/strings.txt | 4 +- Slim/Plugin/PresetsEditor/strings.txt | 2 +- Slim/Plugin/Sounds/strings.txt | 18 ++- Slim/Plugin/ViewTags/strings.txt | 4 +- Slim/Plugin/iTunes/strings.txt | 4 +- strings.txt | 161 +++++++++++++------- 11 files changed, 145 insertions(+), 72 deletions(-) diff --git a/HTML/EN/settings/wizard.json b/HTML/EN/settings/wizard.json index 09fc00cb340..d7bced9f707 100644 --- a/HTML/EN/settings/wizard.json +++ b/HTML/EN/settings/wizard.json @@ -6,6 +6,7 @@ "EN": "Material Skin" }, "desc": { + "CS": "Material Skin poskytuje moderní, bohaté a responzivní uživatelské rozhraní pro vaši hudební sbírku.", "DA": "Material Skin er en moderne, omfangsrig og responsive brugergrænseflade til din musiksamling.", "DE": "Der Material Skin bietet eine moderne, reichhaltige und für Desktop wie Mobilbrowser anpassungsfähige Benutzeroberfläche für Ihre Musiksammlung.", "EN": "The Material Skin provides a modern, rich, and responsive user interface to your music collection.", @@ -18,12 +19,14 @@ { "id": "MusicArtistInfo", "label": { + "CS": "Informace o hudbě a interpretovi", "DA": "Musik- og kunstnerinformation", "DE": "Musik- und Interpreteninformation", "EN": "Music and Artist Information", "FR": "Informations sur la Musique et les Artistes" }, "desc": { + "CS": "Zásuvný modul Informace o hudbě a interpretovi poskytuje další informace o vaší hudbě: biografie, recenze alb, texty písní a další. Je to perfektní doplněk k Material Skin.", "DA": "Musik- og kunsterinformation udvidelsesmodul (plugin) tilbyder mere information om din musik: biografier, anmeldelser, sangtekster og mere. Det er en perfekt tilføjelse til Material Skin.", "DE": "Das Musik- und Interpreteninformationen-Plugin bietet zusätzliche Informationen zu Ihrer Musik: Biografien, Albumkritiken, Songtexte und mehr. Es ist eine perfekte Ergänzung zum Material Skin.", "EN": "The Music and Artist Information plugin provides additional information about your music: biographies, album reviews, lyrics and more. It's a perfect addition to the Material Skin.", @@ -36,12 +39,14 @@ { "id": "Spotty", "label": { + "CS": "Spotty - integrace Spotify pro LMS", "DA": "Spotty - Spotify integration for LMS", "DE": "Spotty Spotify Integration für LMS", "EN": "Spotty Spotify implementation for LMS", "FR": "Intégration Spotty Spotify pour LMS" }, "desc": { + "CS": "Spotty je implementace Spotify pro LMS, která se integruje se všemi uživatelskými rozhraními LMS pro ovládání přehrávání Spotify na účtu Spotify Premium.", "DA": "Spotty er en Spotify implementation for LMS, som fungerer med alle LMS brugergrænseflader til at kontrollere afspilning fra en Spotify Premium konto.", "DE": "Spotty ist eine Spotify Anwendung für LMS. Sie Zugriff auf ihr Spotify Premium Konto über die Squeezebox und all kompatiblen Geräte.", "EN": "Spotty is a Spotify implementation for LMS that integrates with all LMS user interfaces to control Spotify playback on a Spotify Premium account.", @@ -57,6 +62,7 @@ "EN": "TIDAL" }, "desc": { + "CS": "TIDAL je globální platforma pro streamování hudby, která přibližuje fanoušky interpretům prostřednictvím jedinečných zážitků a nejvyšší kvality zvuku.", "DA": "TIDAL er en verdensomspændende musik streaming platform, som bringer brugerne tættere på kunstnere gennem unikke oplevelser og den højest opnåelige lydkvalitet.", "DE": "TIDAL ist eine globale Musik-Streaming-Plattform, die Künstler und Fans durch einzigartige Erlebnisse und die höchste Soundqualität näher zusammenbringt.", "EN": "TIDAL is a global music streaming platform bringing fans closer to artists through unique experiences and the highest sound quality.", @@ -72,6 +78,7 @@ "EN": "Qobuz" }, "desc": { + "CS": "Qobuz je platforma pro streamování hudby s přístupem k více než 100 milionům skladeb, které jsou všechny dostupné ve formátu hi-res FLAC (Free Lossless Audio Codec).", "DA": "Qobuz er en musik streaming platform med adgang til over 100 millioner sange, alle er tilgængelige i high-res FLAC (Free Lossless Audio Codec) formatet.", "DE": "Qobuz ist eine Musik-Streaming-Plattform mit Zugriff auf über 100 Millionen Songs, die alle im Hi-Res FLAC (Free Lossless Audio Codec) Format verfügbar sind.", "EN": "Qobuz is a music-streaming platform with access to over 100 million songs, all of which are available in the hi-res FLAC (Free Lossless Audio Codec) format.", @@ -88,6 +95,7 @@ }, "icon": "https://raw.githubusercontent.com/philippe44/lms-deezer/197b69be9e8054f6cb2653502c3aa180d7ca49bd/HTML/EN/plugins/Deezer/html/deezer.png", "desc": { + "CS": "Deezer je služba pro streamování hudby, která vám poskytuje přístup k více než 120 milionům skladeb a také k dalšímu audio obsahu, jako jsou podcasty nebo audioknihy z celého světa.", "DA": "Deezer er en musik streaming tjeneste, som giver adgang til over 120 millioner sange, samt andet audio indhold så som podcasts eller audiobøger fra hele verden.", "DE": "Deezer ist ein Musikstreamingdienst, mit der du Zugang zu über 120 Millionen Songs, sowie anderen Audioinhalten wie Podcasts oder Hörbüchern aus aller Welt erhältst.", "EN": "Deezer is a music streaming service that gives you access to over 120 million songs, as well as other audio content such as podcasts or audiobooks from all over the world.", @@ -102,6 +110,7 @@ }, "icon": "http://dabdig.co.uk/slimserver-rep/images/RadioNowPlaying.svg", "desc": { + "CS": "Informace o skladbě, obalu alba a občas také o programu pro více než 4200 rozhlasových stanic.", "DA": "Titel, album cover art og sommetider med program-information for mere end 4200 radiostationer.", "DE": "Titel, Cover und gelegentlich Programm-Informationen für mehr als 4200 Radiosender.", "EN": "Track, cover art and, occasionally, programme information for more than 4200 radio stations.", @@ -130,6 +139,7 @@ { "id": "Analytics", "label": { + "CS": "Reportování analytických údajů", "DA": "Rapportéer analysedata", "DE": "Analytikdaten teilen", "EN": "Report Analytics Data", @@ -137,6 +147,7 @@ "NL": "Rapport Analytics-gegevens" }, "desc": { + "CS": "Poskytnutím některých anonymních analytických dat nám pomůžete s dalším vývojem Lyrion Music Serveru.", "DA": "Ved at bidrage med nogle anonyme analytiske data hjælper du os med videre udvikling af Lyrion Music Server.", "DE": "Durch die Bereitstellung anonymer analytischer Daten helfen Sie uns, den Lyrion Music Server weiterzuentwickeln.", "EN": "By providing some anonymous analytical data you help us further develop Lyrion Music Server.", diff --git a/Slim/Plugin/Analytics/strings.txt b/Slim/Plugin/Analytics/strings.txt index f8dcdb21f46..5764d42f5e9 100644 --- a/Slim/Plugin/Analytics/strings.txt +++ b/Slim/Plugin/Analytics/strings.txt @@ -1,5 +1,5 @@ PLUGIN_ANALYTICS_MODULE_NAME - CS Poskytování analytických údajů + CS Reportování analytických údajů DA Afrapportér analysedata DE Analytikdaten teilen EN Report Analytics Data diff --git a/Slim/Plugin/ExtendedBrowseModes/strings.txt b/Slim/Plugin/ExtendedBrowseModes/strings.txt index 8cd4ae8f9bd..260e8cf1e98 100644 --- a/Slim/Plugin/ExtendedBrowseModes/strings.txt +++ b/Slim/Plugin/ExtendedBrowseModes/strings.txt @@ -219,6 +219,7 @@ PLUGIN_EXTENDED_BROWSEMODES_RANDOM_ALBUMS SV Slumpmässigt valda album PLUGIN_EXTENDED_BROWSEMODES_RECENTLY_CHANGED + CS Nedávno aktualizovaná alba DA Nyligt opdaterede albums DE Zuletzt aktualisierte Alben EN Recently Updated Albums @@ -255,7 +256,7 @@ PLUGIN_EXTENDED_BROWSEMODES_FLOP_TRACKS SV Floppspår PLUGIN_EXTENDED_BROWSEMODES_USE_X - CS Použít "%s" + CS Použít „%s" DA Benyt '%s' DE '%s' verwenden EN Use '%s' @@ -267,7 +268,7 @@ PLUGIN_EXTENDED_BROWSEMODES_USE_X SV Använd '%s' PLUGIN_EXTENDED_BROWSEMODES_USING_X - CS Nyní používáte "%s" + CS Nyní používáte „%s" DA Bruger nu '%s' DE Verwende nun '%s' EN Now using '%s' diff --git a/Slim/Plugin/Favorites/strings.txt b/Slim/Plugin/Favorites/strings.txt index 38e039dd828..4c5b35320bf 100644 --- a/Slim/Plugin/Favorites/strings.txt +++ b/Slim/Plugin/Favorites/strings.txt @@ -206,7 +206,7 @@ PLUGIN_FAVORITES_USE_DSTM NL Don't Stop The Music PLUGIN_FAVORITES_USE_DSTM_DESC - CS Zaregistrujte si oblíbené položky jako možnosti pro "Nezastavuj přehrávání hudby". + CS Zaregistrujte si oblíbené položky jako možnosti pro „Nezastavuj přehrávání hudby". DA Benyt favoritter som valg for "Don't Stop The Music". DE Favoriten als Option für "Musikwiedergabe nie anhalten" verwenden. EN Register favorites as options for "Don't Stop The Music". @@ -233,7 +233,7 @@ PLUGIN_FAVORITES_PLAYLIST_EDITOR SV Bläddring och redigering för opml-spellistor PLUGIN_FAVORITES_PLAYLIST_EDITOR_DESC - CS Zásuvný modul oblíbené položky vám také umožňuje procházet seznamy skladeb založené na opml, uložené na vašem serveru. K přidání tohoto režimu do složky "Doplňky" domovské stránky vašeho serveru zvolte níže uvedenou možnost. + CS Zásuvný modul Oblíbené položky vám také umožňuje procházet seznamy skladeb založené na OPML, které jsou uložené na vašem serveru. K přidání tohoto režimu do složky „Doplňky" domovské stránky vašeho serveru zvolte níže uvedenou možnost. DA Med udvidelsesmodulet Favoritter kan du gennemse og redigere opml-baserede afspilningslister som er gemt på din server. Marker denne mulighed hvis du vil føje den til menuen Ekstra i den webbaserede brugerflade. DE Das Favoriten Plugin erlaubt es auch, OPML basierte Wiedergabelisten auf dem Server zu durchsuchen und bearbeiten. Aktiviere die folgende Option, um diesen Modus unter "Extras" auf dem Server Web-Interface anzuzeigen. EN The favorites plugin will also allow you to browse opml based playlists and edit opml playlists stored on your server. Select the option below to add this mode under 'Extras' on the server home page. diff --git a/Slim/Plugin/FullTextSearch/strings.txt b/Slim/Plugin/FullTextSearch/strings.txt index 2a3fd2f9148..e673d72dc05 100644 --- a/Slim/Plugin/FullTextSearch/strings.txt +++ b/Slim/Plugin/FullTextSearch/strings.txt @@ -10,7 +10,7 @@ PLUGIN_FULLTEXT PL Wyszukiwanie pełnotekstowe PLUGIN_FULLTEXT_DESC - CS Tento zásuvný modul nahrazuje poměrně zjednodušené vyhledávání v názvech fulltextovým vyhledáváním. To by např. umožnilo najít seznamy skladeb se skladbou hledaného názvu nebo odfiltrovat ztrátové soubory přidáním slova "flac" k hledanému výrazu. Vypnutím tohoto doplňku se obnoví staré, jednoduché vyhledávání názvů. Upozornění pro pokročilé uživatele: fulltextové vyhledávání není k dispozici při použití MySQL. + CS Tento zásuvný modul nahrazuje poměrně zjednodušené vyhledávání v názvech fulltextovým vyhledáváním. To umožní např. najít seznamy skladeb se skladbou hledaného názvu nebo odfiltrovat ztrátové soubory přidáním slova „flac" k hledanému výrazu. Vypnutím tohoto zásuvného modulu se obnoví staré, jednoduché vyhledávání názvů. Upozornění pro pokročilé uživatele: fulltextové vyhledávání není k dispozici při použití MySQL. DA Denne Plugin erstatter den simple titelsøgning med en fuldtekst søgning. Dette vil f.eks. finde titler på numre i afspillelister, eller bortfiltrere filer komprimeret med tab af opløsning ved at tilføje "Flac" i søgefeltet. Ved deaktivering af denne plugin genetableres den simple titelsøgning. Info til avancerede brugere: Fuldtekst søgning er ikke tilgængelig når man bruger MySQL. DE Diese Erweiterung ersetzt die einfache Titelsuche durch eine Volltextsuche, welche z.B. auch Titel innerhalb einer Playlist findet, oder durch einfache Eingabe von "flac" alle verlustbehafteten Dateien aus den Suchresultaten ausblendet. Deaktivieren dieses Plugins stellt die alte, einfache Titelsuche wieder her. Achtung Power-User: bei Verwendung von MySQL steht die Volltextsuche nicht zur Verfügung. EN This extension replaces the rather simplistic title search with a full text search. This would eg. find playlists with a track of the searched title, or filter out lossy files by adding "flac" to the search term. Disabling this plugin restores the old, simple title search. Powerusers please note: full text search is not available when using MySQL. diff --git a/Slim/Plugin/Podcast/strings.txt b/Slim/Plugin/Podcast/strings.txt index 3e40c29ca9c..78e90b8386c 100644 --- a/Slim/Plugin/Podcast/strings.txt +++ b/Slim/Plugin/Podcast/strings.txt @@ -362,7 +362,7 @@ PLUGIN_PODCAST_COUNTRY NL Land PLUGIN_PODCAST_SUBSCRIBE - CS Přihlásit se k odběru "%s" + CS Přihlásit se k odběru „%s" DA Abonnér på '%s' DE Podcast '%s' abonnieren EN Subscribe to '%s' @@ -371,7 +371,7 @@ PLUGIN_PODCAST_SUBSCRIBE NL Abonneren op '%s' PLUGIN_PODCAST_UNSUBSCRIBE - CS Odhlásit se z odběru "%s" + CS Odhlásit se z odběru „%s" DA Afmeld '%s' DE Von Podcast '%s' abmelden EN Unsubscribe from '%s' diff --git a/Slim/Plugin/PresetsEditor/strings.txt b/Slim/Plugin/PresetsEditor/strings.txt index d698c0ed0bd..1e478439e8e 100644 --- a/Slim/Plugin/PresetsEditor/strings.txt +++ b/Slim/Plugin/PresetsEditor/strings.txt @@ -8,7 +8,7 @@ PLUGIN_PRESETS_EDITOR NL Voorinstelling Aanpassen PLUGIN_PRESETS_EDITOR_DESC - CS Tento zásuvný modul umožňuje vizuálně upravovat konfiguraci tlačítek předvoleb Squeezeboxu. + CS Tento zásuvný modul umožňuje vizuálně upravovat konfiguraci předvoleb tlačítek Squeezeboxu. DA Dette plugin giver dig mulighed for at konfigurere de forudindstillede knapper på din Squeezebox. DE Dieses Plugin erlaubt es ihnen, die Preset-Tasten ihrer Squeezebox zu konfigurieren. EN This plugin allows you to visually edit the configuration of your Squeezebox preset keys. diff --git a/Slim/Plugin/Sounds/strings.txt b/Slim/Plugin/Sounds/strings.txt index a65f6ff20ef..e4e9168f275 100644 --- a/Slim/Plugin/Sounds/strings.txt +++ b/Slim/Plugin/Sounds/strings.txt @@ -31,6 +31,7 @@ PLUGIN_SOUNDS_ERROR SV Ljud och effekter: fel PLUGIN_SOUNDS_ALARMS + CS Zvuky budíku DE Weckertöne EN Alarm Sounds FR Sons d'alarme @@ -837,7 +838,7 @@ PLUGIN_SOUNDS_STREAM_BIRDS SV Bäck och fågelkvitter PLUGIN_SOUNDS_STREAM - CS Datový proud + CS Potok DA Stream DE Stream EN Stream @@ -1245,90 +1246,105 @@ PLUGIN_SOUNDS_ALARM_BUZZER HU Riasztócsengő PLUGIN_SOUNDS_ALARM_ACCELERATING + CS Zrychlující pípání DE Beschleunigendes Biepen EN Accelerating beep FR Bip accéléré NL Versnellende piep PLUGIN_SOUNDS_ALARM_HIGH_BEEP + CS Vysoké pípání DE Hohes Biepen EN High beep FR Bip aigu NL Hoge piep PLUGIN_SOUNDS_ALARM_SIMPLE_CLOCK + CS Jednoduché pípání DE Einfacher Signalton EN Simple beep FR Bip simple NL Eenvoudige piep PLUGIN_SOUNDS_ALARM_BEDSIDE + CS Čtyřnásobné pípání DE Vierfacher Signalton EN Quadrupel beep FR Bip quadruple NL Viervoudige piep PLUGIN_SOUNDS_ALARM_ELECTRONIC_BEEP + CS Elektronické pípání DE Elektronisches Piepen EN Electronical beep FR Bip électronique NL Elektronische piep PLUGIN_SOUNDS_ALARM_DIGITAL + CS Nízké pípání DE Tiefes Piepen EN Low beep FR Bip grave NL Lage piep PLUGIN_SOUNDS_ALARM_DISTORTED + CS Zkreslené pípání DE Verzerrtes Piepen EN Distorted beep FR Bip distordu NL Vervormde piep PLUGIN_SOUNDS_ALARM_DUAL_TONE + CS Střídavé pípání DE Wechselndes Piepen EN Alternating beep FR Bip alterné NL Afwisselende piep PLUGIN_SOUNDS_ALARM_ELECTRONICAL + CS Elektronické pípání 2 DE Elektronisches Piepen 2 EN Electronical beep 2 FR Bip électronique 2 NL Elektronische piep 2 PLUGIN_SOUNDS_ALARM_FUTURISTIC + CS Futuristický alarm DE Futuristischer Alarm EN Futuristic alarm FR Alarme futuriste NL Futuristisch alarm PLUGIN_SOUNDS_ALARM_PHONE + CS Zvonící telefon DE Klingelndes Telefon EN Ringing phone FR Téléphone qui sonne NL Rinkelende telefoon PLUGIN_SOUNDS_ALARM_RINGING + CS Zvonící alarm DE Klingelnder Alarm EN Ringing alarm FR Alarme sonore NL Rinkelend alarm PLUGIN_SOUNDS_ALARM_RINGTONE + CS Vyzváněcí tón DE Klingelton EN Ringtone FR Sonnerie NL Beltoon PLUGIN_SOUNDS_ALARM_TIC_TAC + CS Tik-tak DE Tick-Tack EN Tic-Tac FR Tic-Tac NL Tik-Tak PLUGIN_SOUNDS_ALARM_TICKING + CS Tikající hodiny DE Tickende Uhr EN Ticking clock FR Horloge qui tic-tac diff --git a/Slim/Plugin/ViewTags/strings.txt b/Slim/Plugin/ViewTags/strings.txt index c33c7f55cff..1a3e19746d7 100644 --- a/Slim/Plugin/ViewTags/strings.txt +++ b/Slim/Plugin/ViewTags/strings.txt @@ -89,7 +89,7 @@ PLUGIN_VIEW_TAGS_CUSTOM_TAGS NL Toon additionele tags PLUGIN_VIEW_TAGS_CUSTOM_TAGS_DESC - CS "Název tagu" se vztahuje na skutečný tag, jak je uložen v souboru, např. "WEBSITE". Zobrazí se v nabídce "Zobrazit tagy". "Zobrazovaný název" je uživatelsky přívětivější název, který se použije v uživatelském rozhraní. "Adresa URL" určuje, zda pole obsahuje adresu URL. V tomto případě mohou uživatelská rozhraní, která jsou schopná odkazovat na adresy URL, zobrazit obsah s odkazem. + CS „Název tagu" se vztahuje na skutečný tag, jak je uložen v souboru, např. „WEBSITE". Zobrazí se v nabídce „Zobrazit tagy". „Zobrazovaný název" je uživatelsky přívětivější název, který se použije v uživatelském rozhraní. „Adresa URL" určuje, zda pole obsahuje adresu URL. V tomto případě mohou uživatelská rozhraní, která jsou schopná odkazovat na adresy URL, zobrazit obsah s odkazem. DA "Mærkenavn" er det faktiske navn som er gemt i filen, f.eks. "WEBSITE". Dette vises også i "Vis mærker" menuen. "Mærkenavn at vise" er et mere brugervenligt navn, der vil blive vist i brugergrænsefladen. "URL" definerer, om den viste værdi skal vises som et link (hvis muligt). DE "Tag Name" ist der eigentliche Name, wie er in der Datei gespeichert ist, z.B. "WEBSITE". Dieser Name wird auch in "Tags anzeigen" eines Titels angezeigt. "Anzuzeigender Name" ist ein benutzerfreundlicherer Name, der in der Benutzeroberfläche angezeigt wird. "URL" definiert, ob der angezeigte Wert als Link dargestellt werden soll (wenn möglich). EN "Tag name" refers to the actual tag, as stored in the file, eg. "WEBSITE". The "View Tags" menu shows these. The "Name to be displayed" is a more user friendly name to be used in the UI. "URL" defines whether the field contains a URL. In this case UIs able to link to URLs can render the content with a link. @@ -134,7 +134,7 @@ PLUGIN_VIEW_TAGS_TOPLEVEL NL Toon tags op het hoogste niveau PLUGIN_VIEW_TAGS_MOREINFO - CS Zobrazit tagy v "Další informace" + CS Zobrazit tagy v „Další informace" DA Vis mærker i "Mere info" DE Tags in "Weitere Infos" anzeigen EN Show tags in "More Info" diff --git a/Slim/Plugin/iTunes/strings.txt b/Slim/Plugin/iTunes/strings.txt index 3124a9bf6f4..3ba97edace9 100644 --- a/Slim/Plugin/iTunes/strings.txt +++ b/Slim/Plugin/iTunes/strings.txt @@ -428,7 +428,7 @@ ITUNES_ARTWORK_PHASE_2_PROGRESS ITUNES_IGNORED_PLAYLISTS_DEFAULTS # SLT: These terms MUST correspond to the translation used in iTunes, or the filter will fail - CS Knihovna, videa, filmy, televizní show, hudba, koupené, půjčené filmy, Staženo + CS Knihovna, Videa, Filmy, TV pořady, Hudba, Zakoupeno, Půjčené filmy, Staženo DA Bibliotek, Videoer, Film, Tv-udsendelser, Musik, Indkøb, Lejede film, Hentet DE Mediathek, Videos, Filme, Fernsehsendungen, Musik, Einkäufe, Ausgeliehene Filme, Geladen EN Library, Videos, Movies, TV Shows, Music, Purchased, Rented Movies, Downloaded @@ -460,7 +460,7 @@ SETUP_ITUNES_IGNORED_PLAYLISTS SV Ignorererade spellistor SETUP_ITUNES_IGNORED_PLAYLISTS_DESC - CS Definujte čárkou oddělené seznamy skladeb iTunes, které nechcete importovat (např. "Videa, koupená"). + CS Definujte čárkou oddělené seznamy skladeb iTunes, které nechcete importovat (např. „Videa, Zakoupeno"). DA Opret en kommaadskilt liste med de afspilningslister fra iTunes som ikke skal importeres (fx Videoklip, Købt). DE Definiert eine durch Komma getrennte Liste von iTunes-Wiedergabelisten, die nicht importiert werden sollen (z.B. "Videos, gekauft"). EN Define a comma separated list of iTunes playlists you don't want to be imported (eg. "Videos, Purchased"). diff --git a/strings.txt b/strings.txt index 15704e81f51..184a9d86f73 100644 --- a/strings.txt +++ b/strings.txt @@ -97,7 +97,7 @@ CREDITS ZH_CN Kok-Bin Lee COPYRIGHT - CS © 2001-2024 Lyrion – verze 9.0.4 + CS © 2001-2024 Lyrion verze 9.0.4 DA © 2001-2024 Lyrion - version 9.0.4 DE © 2001-2024 Lyrion Version 9.0.4 EN © 2001-2024 Lyrion Version 9.0.4 @@ -169,7 +169,7 @@ LOADING_SQUEEZEBOX_SERVER EN_SKIN # SLT: please use "Light" as in "light weight", not "illumination" - CS Tenký + CS Lehký DA Let DE Light EN Light @@ -209,6 +209,7 @@ DEFAULT_SKIN ZH_CN 缺省 LOGIC_SKIN + CS Logic tyrkysová DA Logic blågrøn EN Logic Teal @@ -1875,7 +1876,7 @@ ALARM_ADD SV Lägg till alarm ALARM_ADD_DESC - CS Můžete přidat tolik budíků, kolik chcete. Každý budík může být nastaven na každý den, pouze na určité dny nebo jen jednou. Nový budík přidáte volbou "Přidat budík". + CS Můžete přidat tolik budíků, kolik chcete. Každý budík může být nastaven na každý den, pouze na určité dny nebo jen jednou. Nový budík přidáte volbou „Přidat budík". DA Du kan tilføje lige så mange vækkeure som du vil. Hvert vækkeur kan indstilles til at ringe hver dag, på bestemte dage eller kun en enkelt gang. Vælg Tilføj vækkeur for at indstille et nyt. DE Sie können beliebig viele Wecker einrichten. Ein Wecker kann jeden Tag, nur an bestimmten Tagen oder nur einmal gelten. Wählen Sie "Wecker hinzufügen", um einen neuen Wecker hinzuzufügen. EN You can add as many alarms as you like. Each alarm can be set to go off every day, on particular days only, or just once. Select "Add Alarm" to start adding a new alarm. @@ -2149,7 +2150,7 @@ ALARM_DELETING SV Tar bort alarm... ALARM_NOW_PLAYING - CS Budík "Právě hraje" + CS Budík „Právě hraje" DA Vækkeuret spiller nu DE Aktuelle Wecker-Wiedergabe EN Alarm Clock Now Playing @@ -3349,6 +3350,7 @@ PLAYLIST_NO_ITEMS_FOUND SV Fel: Spellistan är tom. PLAYLIST_PROBLEM_CONNECTING + CS Chyba: Nelze se připojit k získání seznamu skladeb DA Fejl: Kan ikke tilslutte for at hente spillelisten DE Fehler: Herstellen einer Verbindung zum Laden der Wiedergabeliste nicht möglich EN Error: Can't connect to retrieve playlist @@ -3767,6 +3769,7 @@ SOURCE ZH_CN 源头 EXTERNAL_ID + CS Externí ID DA Ekstern ID DE Externe ID EN External ID @@ -3920,7 +3923,7 @@ SETUP_GROUP_MENUITEMS ZH_CN 主页菜单 SETUP_GROUP_MENUITEMS_DESC - CS Můžete si upravit volby, které se objeví ve vaší Domovské nabídce na displeji přehrávače. Klepnutím na položky je můžete přesunout nahoru a dolů nebo odstranit. Klepnutím na "Přidat" přidáte odstraněnou položku zpět do nabídky. + CS Můžete si upravit volby, které se objeví ve vaší Domovské nabídce na displeji přehrávače. Klepnutím na položky je můžete přesunout nahoru a dolů nebo odstranit. Klepnutím na „Přidat" přidáte odstraněnou položku zpět do nabídky. DA Du kan selv vælge hvilke menupunkter der skal vises på øverste niveau i hovedmenuen på afspillerens display. Du kan flytte menupunkter op og ned eller fjerne dem ved at klikke på knapperne ud for dem. Klik på Tilføj hvis du vil tilføje et punkt som er fjernet fra menuen. DE Sie können die im Hauptmenü des Players verfügbaren Einträge bestimmen. Klicken Sie auf die entsprechenden Schaltflächen, um Einträge nach oben bzw. unten zu verschieben oder sie zu entfernen. Klicken Sie auf 'Hinzufügen', um einen entfernten Eintrag wieder aufzunehmen. EN You can customize the choices that are available on the top-level Home menu on the player's display. Click to move items up and down or to remove menu items. Click on "Add" to add a removed item back to the menu. @@ -4922,7 +4925,7 @@ SETUP_SENSAUTOBRIGHTNESS_DESC SV Ändra känsligheten för automatisk ljusstyrka. SETUP_PLAYINGDISPLAYMODE - CS Informace o "Právě hraje" + CS Informace o „Právě hraje" DA Oplysninger under afspilning DE Informationen zur aktuellen Wiedergabe EN Now Playing Information @@ -4942,7 +4945,7 @@ SETUP_PLAYINGDISPLAYMODE ZH_CN 播放中信息 SETUP_PLAYINGDISPLAYMODE_ABBR - CS Inf. o "Právě hraje" + CS Inf. o „Právě hraje" DA Oplysninger om nummer der spiller DE Aktueller Titel - Info EN Now Playing Info @@ -5437,7 +5440,7 @@ SETUP_STARTDELAY SV Fördröjning för spelarstart (ms) SETUP_STARTDELAY_DESC - CS Přehrávači může trvat nezanedbatelnou dobu, než spustí přehrávání (než začnete poslouchat hudbu) po zpracování příkazu ke startu od Lyrion Music Serveru. To může nastat v případě, když se používají digitální výstupy (v závislosti na připojením zařízení) nebo u softwarových přehrávačů na určitých platformách. V těchto případech lze nastavit zde toto zpoždění tak, aby Lyrion Music Server věděl, o kolik dříve musí spustit tento přehrávač, aby hudba ze všech synchronizovaných přehrávačů začala ve stejnou dobu. Poznámka: toto se přičítá k případnému "Zpoždění zvuku přehrávače" (níže). + CS Přehrávači může trvat nezanedbatelnou dobu, než spustí přehrávání (než začnete poslouchat hudbu) po zpracování příkazu ke startu od Lyrion Music Serveru. To může nastat v případě, když se používají digitální výstupy (v závislosti na připojením zařízení) nebo u softwarových přehrávačů na určitých platformách. V těchto případech lze nastavit zde toto zpoždění tak, aby Lyrion Music Server věděl, o kolik dříve musí spustit tento přehrávač, aby hudba ze všech synchronizovaných přehrávačů začala ve stejnou dobu. Poznámka: toto se přičítá k případnému „Zpoždění zvuku přehrávače" (níže). DA Det kan vare lidt fra du klikker på startknappen i Lyrion Music Server til afspilningen begynder (før du kan høre noget). Det kan forekomme når de digitale udgange bruges (afhængigt af hvad der er tilsluttet) eller i forbindelse med softwareafspillere på nogle platforme. I så fald kan du indstille en forsinkelse her sådan at Lyrion Music Server ved hvor meget tidligere afspilleren skal startes sådan at lyden på alle de synkroniserede afspillere startes på samme tid. Bemærk: Denne indstilling er i tillæg til en permanent indstilling af Lydforsinkelse for afspiller (nedenfor). DE Es kann eine gewisse Zeit dauern, bis ein Player die Wiedergabe beginnt (bis Sie die Musik hören), nachdem der von Lyrion Music Server empfangene Startbefehl verarbeitet wurde. Dies kann bei der Nutzung digitaler Ausgänge (abhängig vom angeschlossenen Gerät) oder bei bestimmten Software-Playern unter bestimmten Plattformen vorkommen. Sie können dann diese Verzögerung hier festlegen, damit Lyrion Music Server weiß, wie bald dieser Player gestartet werden soll, damit die Wiedergabe aus allen synchronisierten Playern gleichzeitig gestartet wird. Hinweis: Diese Verzögerung gilt zusätzlich zu 'Audioverzögerung des Players' (siehe unten). EN A player can take a noticeable time to start playing (before you begin to hear the audio) after it processes the start command from Lyrion Music Server. This can be the case when using digital outputs (depending upon the connected equipment) or with software players on some platforms. In these cases, this delay can be set here so that Lyrion Music Server knows how much in advance to start this player so that the audio from all the synchronized players starts at the same time. Note: this is in addition to any ongoing "Player Audio Delay" (below). @@ -5874,7 +5877,7 @@ SETUP_REPLAYGAINMODE ZH_CN 音量调整/重播增益 SETUP_REPLAYGAINMODE_DESC - CS Některé zvukové skladby obsahují informace o nastavení hlasitosti neboli "Replay Gain", které lze použít při přehrávání, aby skladby a alba zněly stejně hlasitě. Pokud je tato informace přítomna, přehrávač ji může použít. "Zesílení skladby" lze použít pro to, aby všechny skladby zněly stejně hlasitě. "Zesílení alba" lze použít pro to, aby všechna alba zněla stejně hlasitě, ale aby byly zachovány rozdíly v hlasitosti mezi skladbami v rámci alba. Volba "Inteligentní zesílení" používá zesílení alba, pokud jsou po sobě jdoucí skladby ze stejného alba nebo zesílení skladby pro smíšený seznam skladeb. + CS Některé zvukové skladby obsahují informace o nastavení hlasitosti neboli „Replay Gain", které lze použít při přehrávání, aby skladby a alba zněly stejně hlasitě. Pokud je tato informace přítomna, přehrávač ji může použít. „Zesílení skladby" lze použít pro to, aby všechny skladby zněly stejně hlasitě. „Zesílení alba" lze použít pro to, aby všechna alba zněla stejně hlasitě, ale aby byly zachovány rozdíly v hlasitosti mezi skladbami v rámci alba. Volba „Inteligentní zesílení" používá zesílení alba, pokud jsou po sobě jdoucí skladby ze stejného alba nebo zesílení skladby pro smíšený seznam skladeb. DA Nogle lydfiler indeholder oplysninger om lydstyrkejustering, også kaldet Replay Gain. Oplysningerne kan anvendes ved afspilningen for at sikre at forskellige nummer og album har den samme lydstyrke. Afspilleren kan anvende denne information hvis den findes. Forstærkning af nummer kan bruges til at sikre at alle numre har samme lydstyrke. Forstærkning af album kan bruges til at sikre at alle album har samme lydstyrke, men forskellen i lydstyrke mellem de enkelte numre på et album bevares. Dynamisk forstærkning anvender forstærkning af album hvis flere på hinanden følgende numre er fra samme album, og forstærkning af numre hvis afspilningslisten består af numre fra forskellige album. DE Titel können Informationen zur Normalisierung der Lautstärke enthalten ('Replay Gain'), damit alle Titel und Alben mit derselben Lautstärke wiedergegeben werden können. Der Player kann diese Information nutzen. 'Titel-Normalisierung' stellt sicher, dass alle Titel gleich laut wiedergegeben werden. 'Album-Normalisierung' stellt sicher, dass alle Alben gleich laut wiedergegeben werden, wobei Unterschiede in der Lautstärke in den Titeln eines Albums erhalten bleiben. 'Intelligente' Normalisierung nutzt die Album-Normalisierung, wenn aufeinanderfolgende Titel vom selben Album stammen bzw. die Titel-Normalisierung für gemischte Wiedergabelisten. EN Some audio tracks contain volume adjustment, or "Replay Gain", information that can be used during playback to make sure that tracks and albums sound equally loud. The player can use this information if it is present. "Track gain" can be used to make sure that all tracks sound equally loud. "Album gain" can be used to make sure that all albums sound equally loud, but that volume differences between tracks within an album are preserved. "Smart" gain selection uses album gain if successive songs are from the same album or track gain for a mixed playlist. @@ -6055,7 +6058,7 @@ SETUP_MP3STREAMINGMETHOD SV Strömningsmetod SETUP_MP3STREAMINGMETHOD_DESC - CS Při přehrávání datového proudu z internetu, může být přehrávání datových proudů provedeno jedním ze dvou způsobů. Při volbě "Přímé přehrávání datového proudu" přehrávač provede přímé spojení se serverem přehrávání zvukových proudů a tím mírně sníží zatížení Lyrion Music Serveru a umožní přehrávání proudu i po ztrátě spojení s Lyrion Music Serverem. Volba "Přehrávání datového proudu přes proxy" způsobí, že Lyrion Music Server zajistí spojení a přehraje zvuk prostřednictvím přehrávače. "Přímé přehrávání datového proudu" je výchozí nastavení, ale jestliže budete mít potíže s proudy, zkuste změnit nastavení na "Přehrávání datového proudu přes proxy". Pamatujte na to, že pokud jsou s proudem synchronizovány dva a více přehrávačů, použije se vždy "Přehrávání datového proudu přes proxy", aby se snížilo využití šířky pásma. + CS Při přehrávání datového proudu z internetu, může být přehrávání datových proudů provedeno jedním ze dvou způsobů. Při volbě „Přímé přehrávání datového proudu" přehrávač provede přímé spojení se serverem přehrávání zvukových proudů a tím mírně sníží zatížení Lyrion Music Serveru a umožní přehrávání proudu i po ztrátě spojení s Lyrion Music Serverem. Volba „Přehrávání datového proudu přes proxy" způsobí, že Lyrion Music Server zajistí spojení a přehraje zvuk prostřednictvím přehrávače. „Přímé přehrávání datového proudu" je výchozí nastavení, ale jestliže budete mít potíže s proudy, zkuste změnit nastavení na „Přehrávání datového proudu přes proxy". Pamatujte na to, že pokud jsou s proudem synchronizovány dva a více přehrávačů, použije se vždy „Přehrávání datového proudu přes proxy", aby se snížilo využití šířky pásma. DA Når der afspilles en stream fra internettet, kan det gøres på to måder. Ved direkte streaming etableres der en direkte forbindelse mellem afspilleren og serveren der streames fra. Det reducerer belastningen af Lyrion Music Server en smule og afspilningen fortsætter selvom forbindelsen til Lyrion Music Server bliver afbrudt. Ved streaming via en proxy vil Lyrion Music Server håndtere forbindelsen og sende lyden videre til afspilleren. Direkte streaming er standardmetoden, men hvis du har problemer med streams, kan du ændre indstillingen til Streaming via proxy. Bemærk at hvis to eller flere afspillere er synkroniseret til en stream, bliver proxymetoden altid anvendt for at begrænse brugen af båndbredde. DE Zur Wiedergabe eines Internet-Streams kann das Streaming auf zwei verschiedene Arten durchgeführt werden. Beim direkten Streaming erstellt der Player eine direkte Verbindung mit dem Audio-Streaming-Server, wodurch die Belastung von Lyrion Music Server verringert wird und der Stream auch fortgesetzt werden kann, wenn die Verbindung zu Lyrion Music Server unterbrochen wird. Beim Streaming über einen Proxy-Server verwaltet Lyrion Music Server die Verbindung und leitet die Musik an den Player weiter. Standardmäßig wird das direkte Streaming verwendet, aber wenn Probleme mit Streams auftreten, können Sie die andere Methode versuchen. Hinweis: Wenn zwei oder mehre Player synchron auf einem Stream zugreifen, wird immer das Streaming über einen Proxy-Server verwendet, um die Bandbreitennutzung zu reduzieren. EN When playing an Internet stream, the streaming can be done in one of two ways. Direct Streaming causes the player to make a direct connection to the audio streaming server, reducing the load on Lyrion Music Server slightly and allowing the stream to continue playing if the Lyrion Music Server connection is lost. Proxied Streaming causes Lyrion Music Server to handle the connection, passing the audio through to the player. Direct Streaming is the default, but if you experience problems with streams, try changing this setting to Proxied Streaming. Note that if two or more players are synchronized to an stream, proxied streaming is always used to reduce bandwidth usage. @@ -6666,7 +6669,7 @@ SETUP_SHOWARTIST_DESC ZH_CN 您可以选择通过浏览专辑时是否一同显示有关的艺人。当您选择一同显示时,有关艺人将显示在专辑标题旁边。 SETUP_GUESSFILEFORMATS - CS Odhadnutí formátů štítků (tagů) + CS Odhadnutí formátů tagů DA Gæt format for mærker DE Tag-Format erraten EN Guess Tags Formats @@ -6725,7 +6728,7 @@ SETUP_IRMAP ZH_CN 遥控键功能 SETUP_IRMAP_DESC - CS Můžete si zvolit mezi seznamy funkcí tlačítek. Tyto seznamy přiřazují konkrétní tlačítka na infračerveném dálkovém ovladači ke konkrétním funkcím. "Standardní" seznam je popsán v dokumentaci. + CS Můžete si zvolit mezi seznamy funkcí tlačítek. Tyto seznamy přiřazují konkrétní tlačítka na infračerveném dálkovém ovladači ke konkrétním funkcím. „Standardní" seznam je popsán v dokumentaci. DA Du kan vælge mellem forskellige funktionssæt til knapperne. Disse funktionssæt bestemmer hvilken funktion de forskellige knapper på fjernbetjeningen skal have. Standardsættet er det som er beskrevet i dokumentationen. DE Sie können zwischen Tastenfunktionsgruppen wählen, die Tasten der Fernbedienung mit bestimmten Funktionen belegen. Die Gruppe 'Standard' wird in der Dokumentation beschrieben. EN You can choose between button function sets. These sets map particular buttons on the infrared remote to particular functions. The "Standard" set is the one that is described in the documentation. @@ -6833,7 +6836,7 @@ SETUP_LIBRARY_NAME SV Mediebiblioteksnamn SETUP_LIBRARY_NAME_DESC - CS Tak se bude jmenovat vaše knihovna médií v nabídce "Moje média" vašeho Squeezeboxu. + CS Tak se bude jmenovat vaše knihovna médií v nabídce „Moje média" vašeho Squeezeboxu. DA Dit mediebibliotek får dette navn i Squeezebox-menuen Mine multimedier. DE Das ist der Name der Medienbibliothek im Squeezebox-Menü 'Eigene Medien'. EN This is how your media library will be named in your Squeezebox's "My Media" menu. @@ -6998,7 +7001,7 @@ SETUP_ARTFOLDER_DESC ZH_CN 您可以利用以上的文件名变量选项,把所有的图象集中存放在一个文件夹内。请在这里输入图象文件所在地点。如果服务器未能在所指定的封面图象文件夹中找到匹配图象,便会在各个音像文件所属的文件夹中寻找匹配的图象。 SETUP_BAD_FILE - CS Ouha – "%s" asi nebude platný soubor. Zkuste to znovu. + CS Ouha – „%s" asi nebude platný soubor. Zkuste to znovu. DA %s er ikke en gyldig fil. Prøv igen. DE Fehler: '%s' ist keine gültige Datei. Versuchen Sie es noch einmal. EN Oops - "%s" doesn't seem to be a valid file. Try again. @@ -7017,7 +7020,7 @@ SETUP_BAD_FILE ZH_CN "%s"似乎不是一个合法文件。请再次尝试。 SETUP_BAD_DIRECTORY - CS Ouha – "%s" asi nebude platný adresář. Zkuste to znovu. + CS Ouha – „%s" asi nebude platný adresář. Zkuste to znovu. DA %s er ikke en gyldig mappe. Prøv igen. DE Fehler: '%s' ist kein gültiges Verzeichnis. Versuchen Sie es noch einmal. EN Oops - "%s" doesn't seem to be a valid directory. Try again. @@ -7356,7 +7359,7 @@ SETUP_SKIN ZH_CN 网界面 SETUP_SKIN_DESC - CS Ze seznamu níže si můžete vybrat vzhled čili "skin" pro webové rozhraní. + CS Ze seznamu níže si můžete vybrat vzhled čili „skin" pro webové rozhraní. DA Du kan vælge et layout ("skin") til den webbaserede brugerflade på listen nedenfor. DE Sie können das Aussehen (eine 'Skin') für die Web-Benutzeroberfläche aus der folgenden Liste auswählen. EN You can choose a look or "skin" for the web interface from the list below. @@ -7429,6 +7432,7 @@ SETUP_EXTENSIONS_CATEGORY_ALL ZH_CN 全部 SETUP_EXTENSIONS_CATEGORY_TOP + CS Nejoblíbenější (není nainstalováno) DA Mest populære (ikke installeret) DE Populärste (nicht installierte) EN Most Popular (not installed) @@ -7444,6 +7448,7 @@ SETUP_EXTENSIONS_CATEGORY_DATABASE HU Zenei könyvtár SETUP_EXTENSIONS_CATEGORY_HARDWARE + CS Hardware DA Hardware EN Hardware FR Matériel @@ -7499,7 +7504,7 @@ SETUP_EXTENSIONS_CATEGORY_PLAYLISTS NL Afspeellijst SETUP_EXTENSIONS_CATEGORY_RADIO - CS Internetové rádio + CS Internetové rádia DA Internetradio DE Internetradio EN Internet Radio @@ -7887,7 +7892,7 @@ SETUP_COVERART ZH_CN 图象 SETUP_COVERART_DESC - CS Obrázky obalů alb, pokud jsou k dispozici, se zobrazují při prohlížení informací o albu nebo skladbě. Obrázky obalů alb se nacházejí v tagech ID3 u jednotlivých skladeb nebo mohou být uloženy ve stejné složce jako soubory skladeb. Standardně se používají názvy obrázků "cover.jpg", "folder.jpg", "album.jpg" nebo "thumb.jpg". Můžete zadat další názvy souborů pro obrázky obalů alb. Můžete zadat jiné názvy pro náhledy nebo pro obrázky plné velikosti. Přidejte před tuto volbu znak % a můžete za něj napsat libovolný řetězec vytvořený ze stejných prvků, které jsou pro Formáty názvů (např. %ARTIST - ALBUM bude hledat Artist - Album.jpg odpovídající nalezenému interpretovi a albu). + CS Obrázky obalů alb, pokud jsou k dispozici, se zobrazují při prohlížení informací o albu nebo skladbě. Obrázky obalů alb se nacházejí v tagech ID3 u jednotlivých skladeb nebo mohou být uloženy ve stejné složce jako soubory skladeb. Standardně se používají názvy obrázků „cover.jpg", „folder.jpg", „album.jpg" nebo „thumb.jpg". Můžete zadat další názvy souborů pro obrázky obalů alb. Můžete zadat jiné názvy pro náhledy nebo pro obrázky plné velikosti. Přidejte před tuto volbu znak % a můžete za něj napsat libovolný řetězec vytvořený ze stejných prvků, které jsou pro Formáty názvů (např. %ARTIST - ALBUM bude hledat Artist - Album.jpg odpovídající nalezenému interpretovi a albu). DA Der vises billeder af albumcovere når du vælger at se oplysninger om et album eller nummer. Coverbillederne hentes fra ID3-koderne i de enkelte numre eller fra mappen hvor filerne er placeret. Som standard indlæses følgende grafikfiler hvis der ikke er et billede i ID3-koden: "cover.jpg", "folder.jpg", "album.jpg" eller "thumb.jpg". Du kan angive flere filnavne der skal anvendes. Du kan endvidere angive forskellige filnavne for billeder i fuld størrelse og mindre størrelse. DE Plattenhüllen werden (falls verfügbar) beim Anzeigen eines Albums oder Titelinformationen angezeigt. Diese Bilder sind in den ID3-Tags der Titel bzw. demselben Ordner wie die Musikdateien enthalten. Standardmäßig werden Dateinamen wie "cover.jpg", "album.jpg" oder "thumb.jpg" verwendet. Sie können einen weiteren Dateinamen für Plattenhüllen angeben. Sie können unterschiedliche Dateinamen für Miniaturen und Vollbilder angeben. Stellen Sie ein % voran. Der Name kann aus denselben Elementen bestehen, die für Titelformate zulässig sind (z.B. %ARTIST - ALBUM sucht nach 'Interpret - Album.jpg', um die passende Datei zu finden. EN Images of album artwork, when available, are displayed when viewing an album or song information. Artwork images are found in the ID3 tags for individual songs or can reside in the same folder as song files. By default, images named "cover.jpg", "folder.jpg", "album.jpg", or "thumb.jpg" are used. You can specify an additional file name to use for album art images. You can specify different file names for thumbnail or full size images. Prefix the option with % and you can follow it with any string made up of the same elements available for Title Formats (eg %ARTIST - ALBUM, will look for Artist - Album.jpg to fit the artist and album information found). @@ -8153,9 +8158,10 @@ SETUP_CHECKVERSION ZH_CN 软件更新 SETUP_CHECKVERSION_DESC + CS Lyrion Music Server může automaticky zkontrolovat, zda je k dispozici aktualizovaná verze softwaru. Pokud ano, zobrazí se ve webovém rozhraní Lyrion Music Serveru zpráva. DA Lyrion Music Server kan checke automatisk om der er en ny software version tilgængelig. Hvis det er tilfældet, vil der dukke en besked op i Lyrion Music Sever web interfacet. DE Lyrion Music Server kann automatisch jeden Tag prüfen, ob eine neue Softwareversion verfügbar ist. Ist dies der Fall, wird dies in der Web-Benutzeroberfläche von Lyrion Music Server gemeldet. - EN Lyrion Music Server can automatically check to see if an updated version of the software is available. If it is, then a message will appear in Lyrion Music Server's web interface. + EN Lyrion Music Server can automatically check to see if an updated version of the software is available. If it is, then a message will appear in Lyrion Music Server's web interface. ES Lyrion Music Server se puede conectar automáticamente comprobar si hay disponible una versión actualizada del software. Si la hay, aparecerá un mensaje en la interfaz Web de Lyrion Music Server. FR Le serveur peut automatiquement vérifier la disponibilité d'une nouvelle version du logiciel. Le cas échéant, un message dans l'interface Web indique qu'une nouvelle version est disponible. HU A Lyrion Music Server automatikusan ellenőrzi, hogy elérhető-e a szoftver frissített verziója. Ha igen, akkor egy üzenet jelenik meg a Lyrion Music Server webes felületén. @@ -8455,7 +8461,7 @@ SETUP_ALARMSAVER_ABBR SV Vid alarm SETUP_SCREENSAVER_DESC - CS Po období nečinnosti dálkového ovladače může přehrávač zobrazovat různé informace jako "spořiče obrazovky". Můžete zvolit odlišné spořiče k zobrazení v závislosti na tom, jestli přehrávač hraje nebo ne nebo je vypnut. Můžete také zvolit dobu čekání před povolením těchto spořičů obrazovky. + CS Po období nečinnosti dálkového ovladače může přehrávač zobrazovat různé informace jako „spořiče obrazovky". Můžete zvolit odlišné spořiče k zobrazení v závislosti na tom, jestli přehrávač hraje nebo ne nebo je vypnut. Můžete také zvolit dobu čekání před povolením těchto spořičů obrazovky. DA Hvis du ikke har brugt fjernbetjeningen i et stykke tid, kan der vises forskellige oplysninger på displayet som en form for pauseskærm. Du kan vælge at bruge forskellige pauseskærme når afspilleren er hhv. tændt og slukket, når der spilles et nummer og når der ikke gør. Du kan også angive hvor lang tid der skal gå før pauseskærmene aktiveres. DE Sie können einen Bildschirmschoner wählen, der nach einer gewissen Inaktivität der Fernbedienung aktiviert wird. Außerdem können Sie die Zeit wählen, nach der der Bildschirmschoner aktiviert wird. Je nachdem, ob der Player Audio wiedergibt, angehalten oder ausgeschaltet wurde, können Sie verschiedene Bildschirmschoner wählen. EN After a period of inactivity from the remote control, the player can display various information as "screensavers". You can choose different screensavers to show, depending on whether the player is playing or not, or if it is powered off. You can also choose the amount of time to wait before enabling these screensavers. @@ -8473,6 +8479,7 @@ SETUP_SCREENSAVER_DESC ZH_CN 您可以通过遥控器选择在播放机非活动状态时以屏幕保护程序来显示信息。您可以设定屏幕保护程序介入前的等候时间。并且设定播放机在不同状态下如播放时、停止播放时、或关机时应用不同屏幕保护程序。 SETUP_NO_SCREENSAVERS + CS Zdá se, že nejsou nainstalovány žádné spořiče obrazovky. Chcete nainstalovat spořič obrazovky Datum a čas? DA Der ser ikke ud til at være installeret nogen pauseskærme. Vil du installere pauseskærmen Dato og tid? DE Es scheinen keine Bildschirmschoner installiert zu sein. Möchten Sie den Bildschirmschoner "Datum und Uhrzeit" installieren? EN There seem to be no screensavers installed. Do you want to install the Date and Time screensaver? @@ -8532,7 +8539,7 @@ SCREENSAVER_JUMP_BACK_NAME ZH_CN 播放中 SCREENSAVER_JUMP_TO_NOW_PLAYING - CS Přejít na "Právě hraje" + CS Přejít na „Právě hraje" DA Gå til Nu spiller DE In 'Aktuelle Wiedergabe' wechseln EN Jump To Now Playing @@ -8623,7 +8630,7 @@ SETUP_ADDITIONAL_PLAYLIST_BUTTONS SV Ytterligare spellisteknappar SETUP_ADDITIONAL_PLAYLIST_BUTTONS_DESC - CS Některé vzhledy mohou volitelně zobrazovat další tlačítka pro přehratelné položky, například "Přehrát další" nebo "Odstranit ze seznamu skladeb". + CS Některé vzhledy mohou volitelně zobrazovat další tlačítka pro přehratelné položky, například „Přehrát další" nebo „Odstranit ze seznamu skladeb". DA Nogle temaer kan vise flere knapper, fx Spil næste, Fjern fra afspilningsliste. DE Bestimmte Skins können wahlweise zusätzliche Wiedergabe-Schaltflächen (z.B. 'Nächsten wiedergeben' oder 'Aus Wiedergabeliste entfernen' enthalten. EN Some skins optionally can display additional buttons for playable items, like eg. "Play next" or "Remove from playlist". @@ -8694,7 +8701,7 @@ SETUP_SEARCHSUBSTRING_1 ZH_CN 在词内搜寻 SETUP_SEARCHSUBSTRING_DESC - CS Pokud hledáte mediální soubory, můžete pomocí serveru hledat odpovídající položky obsahující slova, která začínají stejnými písmeny jako hledaný řetězec, nebo obsahující slova, která mají hledaný řetězec kdekoliv ve slově. Například hledání začátku slov "RAIN" najde položky se slovem "RAINBOW". Hledání uvnitř slov vrátí také položku obsahující slovo "TRAIN". + CS Pokud hledáte mediální soubory, můžete pomocí serveru hledat odpovídající položky obsahující slova, která začínají stejnými písmeny jako hledaný řetězec, nebo obsahující slova, která mají hledaný řetězec kdekoliv ve slově. Například hledání začátku slov „RAIN" najde položky se slovem „RAINBOW". Hledání uvnitř slov vrátí také položku obsahující slovo „TRAIN". DA Når du søger efter mediefiler, kan serveren enten finde elementer med ord som begynder med de samme bogstaver som din søgestreng, eller ord som indeholder søgestrengen et vilkårligt sted i ordet. For eksempel vil søgestrengen ved søgning efter "RAIN" i begyndelsen finde elementer med ordet "RAINBOW". Søgning efter vilkårlige steder i ord vil også returnere elementer som indeholder ordet "TRAIN". DE Beim Suchen nach Mediendateien können Sie den Server anweisen, nur am Wortanfang nach Zeichenfolgen zu suchen oder an einer beliebigen Stelle im Wort. Beispiel: Wenn Sie den Wortanfang nach 'RAIN' durchsuchen, werden auch Einträge mit dem Wort 'RAINBOW' gefunden. Wird innerhalb des Wortes gesucht, werden auch Wörter wie 'TRAIN' gefunden. Bitte beachten Sie, dass die Einstellung ignoriert wird, wenn die Volltextsuche aktiviert ist. EN When you search for media files, you can have your server find matches for items that contain words that begin with the same letters in your search string or contain words that have the search string anywhere in the word. For example, searching the beginnings of words for "RAIN" in would find items with the word "RAINBOW". Searching within words would also return item containing the word "TRAIN". PLEASE NOTE: if you're using the Fulltext Search plugin, this flag does not apply. @@ -9135,7 +9142,7 @@ SETUP_IGNOREDARTICLES ZH_CN 进行排序时应忽略的词汇 SETUP_IGNOREDARTICLES_DESC - CS Seznam členů ("the", "les", "los" atd.) na začátku jména interpreta, skladby nebo alba, které se budou při řazení ignorovat. Více členů oddělte mezerami nebo nechte tento seznam prázdný, čímž se tato funkce vypne. Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. + CS Seznam členů („the", „les", „los" atd.) na začátku jména interpreta, skladby nebo alba, které se budou při řazení ignorovat. Více členů oddělte mezerami nebo nechte tento seznam prázdný, čímž se tato funkce vypne. Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. DA En liste med artikler ("the", "les", "los" (og evt. andre ord)) der skal ignoreres ved sortering af kunstnere, numre og albumnavne. De enkelte ord skal adskilles af mellemrum, og hvis du ikke vil benytte funktionen, skal listen være tom. Hvis du ændrer denne indstilling, bliver dit musikbibliotek gennemsøgt igen. DE Eine Liste von Artikeln ("die", "the", "los", "la" usw..), die bei Sortieren am Anfang des Namens von Interpreten, Titeln oder Alben ignoriert werden sollen. Trennen Sie verschiedene Artikel durch Leerzeichen oder lassen Sie die Liste leer, um diese Option nicht zu nutzen. Wenn Sie diese Einstellung ändern, wird die Musiksammlung erneut durchsucht. EN A list of articles ("the", "les", "los", etc.) to ignore at the beginning of artist, song or album names when sorting. Separate multiple articles by spaces or leave this list blank to disable this behavior. Changing this setting will start a rescan of your music library. @@ -9152,7 +9159,7 @@ SETUP_IGNOREDARTICLES_DESC SV En lista med artiklar (the, les, los, o.s.v.) som ska ignoreras när de kommer först i namn på artister, låtar och album. Avgränsa artiklarna med mellanslag eller lämna fältet tomt om du vill avaktivera funktionen. Om du ändrar den här inställningen söks musikbiblioteket igenom på nytt. SETUP_SPLITLIST - CS Oddělovač více položek ve štítcích + CS Oddělovač více položek v tazích DA Skilletegn når der er flere elementer i mærker DE Trennzeichen für mehrere Einträge in Tags EN Separator for Multiple Items in Tags @@ -9169,7 +9176,7 @@ SETUP_SPLITLIST SV Avgränsare för flera objekt i taggar SETUP_SPLITLIST_DESC - CS Lyrion Music Server může z tagů ve vašich hudebních souborech získat více interpretů, názvů alb a žánrů. Pokud ve vašich tagech najde některé ze slov nebo znaků uvedených níže, vytvoří pro každou položku jednotlivé výpisy. Pokud například do seznamu níže vložíte středník, skladba s tagem interpreta "J. S. Bach;Michael Tilson Thomas" se objeví v oblasti interpretů pro "J. S. Bach" i "Michael Tilson Thomas". Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. + CS Lyrion Music Server může z tagů ve vašich hudebních souborech získat více interpretů, názvů alb a žánrů. Pokud ve vašich tagech najde některé ze slov nebo znaků uvedených níže, vytvoří pro každou položku jednotlivé výpisy. Pokud například do seznamu níže vložíte středník, skladba s tagem interpreta „J. S. Bach;Michael Tilson Thomas" se objeví v oblasti interpretů pro „J. S. Bach" i „Michael Tilson Thomas". Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. DA Lyrion Music Server kan udtrække flere kunstnere, albumtitler og genre fra mærkerne i dine musikfiler. Hvis Lyrion Music Server finder nogle af de ord eller symboler nedenunder, vil der blive oprettet individuelle oversiger for hvert element. Hvis du for eksempel har indtastet et semikolon i listen nedenunder, vil numre med kunstnermærke "J. S. Bach;Michael Tilson Thomas" medføre at der oprettes to kunstnere, "J. S. Bach" og "Michael Tilson Thomas". Ændring af denne indstilling medfører at dit musikbibliotek bliver genindlæst. DE Lyrion Music Server kann mehrere Interpreten, Albumtitel und Stilrichtungen in den Tags von Musikdateien erkennen. Findet Lyrion Music Server folgende Wörter oder Zeichen in den Tags, wird für jeden Eintrag eine andere Liste erstellt. Beispiel: Wenn Sie einen Strichpunkt als Trennzeichen definieren, wird ein Titel mit dem Interpreten-Tag 'J. S. Bach;Michael Tilson Thomas' sowohl unter 'J. S. Bach' als auch 'Michael Tilson Thomas' aufgelistet. Wenn Sie diese Einstellung ändern, wird die Musiksammlung erneut durchsucht. EN Lyrion Music Server can extract multiple artist, album titles and genres from the tags inside your music files. If it finds any of the words or characters below in your tags, it will create individual listings for each item. For example, if you put a semicolon in the list below, a song with an artist tag of "J. S. Bach;Michael Tilson Thomas" will appear in the artists area for both "J. S. Bach" and "Michael Tilson Thomas". Changing this setting will start a rescan of your music library. @@ -9203,7 +9210,7 @@ SETUP_ARTISTS_BROWSE_MODES SV Bläddra efter artister SETUP_ARTISTS_BROWSE_MODES_DESC - CS Zvolte, zda chcete použít jeden konfigurovatelný seznam interpretů, nebo dva seznamy pro Interprety alba a Všechny interpreti. Interpreti alba je seznam, ve kterém je Interpret alba jediným interpretem na albu nebo interpretem uvedeným v tagu ALBUMARTIST. Všichni interpreti je seznam všech interpretů, kteří jsou uvedeni v tagu role přispěvatele (ARTIST, COMPOSER atd.). Jednotný konfigurovatelný seznam interpretů naproti tomu umožňuje určit, které role přispěvatelů mají být součástí nabídky Interpret. + CS Zvolte, zda chcete použít jeden konfigurovatelný seznam interpretů, nebo dva seznamy „Interpreti alba" a „Všichni interpreti". „Interpreti alba" je seznam, ve kterém je Interpret alba jediným interpretem na albu nebo interpretem uvedeným v tagu ALBUMARTIST. „Všichni interpreti" je seznam všech interpretů, kteří jsou uvedeni v tagu role přispěvatele (ARTIST, COMPOSER atd.). Jednotný konfigurovatelný seznam interpretů naproti tomu umožňuje určit, které role přispěvatelů mají být součástí nabídky Interpret. DA Vælg om du vil bruge en samlet konfigurerbar kunstnerliste, eller to separate lister for Album kunstner og Alle kunstnere. Album kunstner er en liste hvor kunstneren er den eneste på albumet eller hvor kunstneren er specificeret i ALBUMARTIST mærket. Alle kunstnere er en liste hvor samtlige kunstnere som er i en bidragsrolle (ARTIST, COMPOSER etc.) er inkluderet. Hvis du vælger en samlet liste, definerer du selv hvilke roller der skal inkluderes i listen. DE Wählen Sie, ob Sie eine einzelne, konfigurierbare Liste von Interpreten haben wollen, oder eine für Album-Interpreten und eine für Alle Interpreten. Album-Interpreten führt nur Künstler auf, welche für ein Album alleine gespeichert sind, oder im ALBUMARTIST Tag vermerkt sind. Alle Interpreten listet alle Künstler aller Rollen auf (ARTIST, COMPOSER etc.). Die konfigurierbare Interpretenliste lässt Sie festlegen, welche Rollen berücksichtigt werden sollen. EN Choose whether you want to use a single, configurable artists list, or two lists for Album Artists and All Artists. Album Artists is a list where Album Artist is the sole artist on an album or is the artist specified in the ALBUMARTIST tag. All Artists is a list of every artist that appears in a contributor role tag (ARTIST, COMPOSER etc.). The single, configurable list of artists on the other hand lets you define which contributor roles should be part of the Artists menu. @@ -9228,7 +9235,7 @@ SETUP_ARTISTS_BROWSE_MODES_UNIFIED_ON SV Använd en enda konfigurerbar artistlista SETUP_ARTISTS_BROWSE_MODES_UNIFIED_OFF - CS Použít dva samostatné seznamy pro Interpreta alba a Všechny interprety + CS Použít dva samostatné seznamy pro Interpreti alba a Všichni interpreti DA Brug to separate lister for Album kunstner og Alle kunstnere DE Verwende getrennte Listen für Album-Interpreten und Alle Künstler EN Use two separate lists for Album Artists and All Artists @@ -9491,7 +9498,7 @@ SETUP_ENHANCEDHTTP NL Streammethode voor HTTP(S) SETUP_ENHANCEDHTTP_DESC - CS Pokud dojde k selhání připojení HTTP(S) k serveru, Lyrion Music Server ukončí přehrávání. Může se také pokusit o jeho opětovné otevření (Trvalý režim) nebo může ukládat datové proudy (Režim mezipaměti) definované délky (podcasty, jednotlivé skladby) do vyrovnávací paměti v souborech na disku. Ty budou po přehrání datového proudu odstraněny. To může zlepšit spolehlivost u některých serverů, které očekávají stahování skladeb, nikoliv přehrávání datového proudu, a proto uzavírají dlouhá spojení. Zároveň to ale způsobuje větší množství zápisu do souborového systému, což může potenciálně opotřebovat např. karty SD. Pokud máte dostatek místa pro ukládání souborů do vyrovnávací paměti, pak je režim "Mezipaměti" správnou cestou + CS Pokud dojde k selhání připojení HTTP(S) k serveru, Lyrion Music Server ukončí přehrávání. Může se také pokusit o jeho opětovné otevření (Trvalý režim) nebo může ukládat datové proudy (Režim mezipaměti) definované délky (podcasty, jednotlivé skladby) do vyrovnávací paměti v souborech na disku. Ty budou po přehrání datového proudu odstraněny. To může zlepšit spolehlivost u některých serverů, které očekávají stahování skladeb, nikoliv přehrávání datového proudu, a proto uzavírají dlouhá spojení. Zároveň to ale způsobuje větší množství zápisu do souborového systému, což může potenciálně opotřebovat např. karty SD. Pokud máte dostatek místa pro ukládání souborů do vyrovnávací paměti, pak je režim „Mezipaměti" správnou cestou DA Når en HTTP(S) forbindelse til en server fejler, vil Lyrion Music Server afslutte afspilningen. LMS kan forsøge at genåbne (Persistent mode) eller buffere (Cache mode) streams af forudefineret længde (podcasts, enkelte numre) til en disk fil. Disse bliver fjernet når afspilningen er afsluttet. Dette kan forbedre pålideligheden med nogle servere som forventer numrene downloades i stedet for at blive streamet og som derfor lukker langvarige forbindelser. Det kan medføre mere skrivning til filsystemet, hvilket potentielt kan forårsage slidtage på f.eks. SD kort. Hvis du har plads nok til at cache filerne, er det den bedste løsning DE Wenn eine HTTP(S)-Verbindung zu einem Server fehlschlägt, beendet Lyrion Music Server die Wiedergabe (Normaler Modus). Er kann auch versuchen, die Verbindung wieder zu öffnen (Persistenter Modus), oder er kann Streams von bestimmter Länge (Podcasts, einzelne Tracks) auf der Festplatte zwischenspeichern (Cache Modus). Diese Dateien werden entfernt, sobald der Stream abgespielt wurde. Dies erhöht die Zuverlässigkeit mit einigen Anbietern, kann aber das Dateisystem zusätzlich belasten (z.B. wenn eine SD Karte verwendet wird). EN When a HTTP(S) connection to a server fails, Lyrion Music Server terminates playback. It can also try to re-open it (Persistent mode) or it can buffer streams (Cache mode) of defined length (podcasts, single tracks) on disk files. These will be removed once the stream has been played. This can improve the reliability with some servers that expect tracks to be downloaded, not streamed and thus close long connections. But it also does cause more writing to the file system, which could potentially wear out e.g. SD cards. If you have enough space for buffering files, then "Cache" mode is the way to go. @@ -9815,6 +9822,7 @@ SETUP_UDPCHUNKSIZE ZH_CN 最大UDP数据大小 SETUP_MAX_REDIRECTS + CS Maximální počet přesměrování DE Maximale Anzahl Weiterleitungen DA Maksimalt antal omdirigeringer EN Maximum number of redirects @@ -9822,6 +9830,7 @@ SETUP_MAX_REDIRECTS NL Maximum aantal omleidingen SETUP_MAX_REDIRECTS_DESC + CS Maximální počet přesměrování HTTP, která budou následována. Pokud je vyžadováno více přesměrování, je požadavek považován za neúspěšný. DE Die maximale Anzahl von HTTP Weiterleitungen, die gefolgt werden soll. Werden weitere Weiterleitungen angefordert, so gilt die Anfrage als fehlgeschlagen. DA Det maksimale antal HTTP-omdirigeringer, der skal følges. Hvis der kræves flere omdirigeringer, betragtes anmodningen som mislykket. EN The maximum number of HTTP redirects to follow. Should more redirects be required, then the request is considered failure. @@ -9896,7 +9905,7 @@ SETUP_CORS_ALLOWED_HOSTS SV Tillåtna CORS servrar SETUP_CORS_ALLOWED_HOSTS_DESC - CS Cross-Origin Resource Sharing (CORS) je mechanismus, který používá dodatečné hlavičky HTTP k tomu, aby prohlížeči sdělil, že webová aplikace spuštěná v jednom původu (doméně) má povolení k přístupu k vybraným prostředkům ze serveru v jiném původu.

Zadejte čárkou oddělený seznam názvů hostitelů, kterým chcete poskytnout přístup k Lyrion Music Serveru. Položky musí obsahovat protokol (např. "http"), plný název hostitele ("www.example.com") a číslo portu, pokud je toto číslo nestandardní. Ve většině případů by mělo stačit něco jako "https://www.example.com". + CS Cross-Origin Resource Sharing (CORS) je mechanismus, který používá dodatečné hlavičky HTTP k tomu, aby prohlížeči sdělil, že webová aplikace spuštěná v jednom původu (doméně) má povolení k přístupu k vybraným prostředkům ze serveru v jiném původu.

Zadejte čárkou oddělený seznam názvů hostitelů, kterým chcete poskytnout přístup k Lyrion Music Serveru. Položky musí obsahovat protokol (např. „http"), plný název hostitele („www.example.com") a číslo portu, pokud je toto číslo nestandardní. Ve většině případů by mělo stačit něco jako „https://www.example.com". DA Cross-Origin Resource Sharing (CORS) er en mekaniske som gør det muligt for en web-browser at tillade en web-server i et domæne at anvende web-ressourcer fra en server i et andet domæne.

Definér en komma-separeret liste med web-servere som tillades at få adgang til din Lyrion Music Server. Hver server skal have en protokol (f.eks. "http") angivet, samt hele servernavnet ("www.example.com") og et port nummer, hvis det er non-standard. Normalt vil noget i retning af "https://www.example.com" være tilstrækkeligt. DE Cross-Origin Resource Sharing (CORS) ist ein Mechanismus, der Webbrowsern oder auch anderen Webclients Cross-Origin-Requests ermöglicht.

Definieren Sie eine Komma separierte Liste von Hostnamen, die auf ihren Lyrion Music Server zugreifen dürfen. Es müssen Protokoll (z.B. "http"), voller Hostname ("www.example.com"), und allenfalls Port angegeben werden, wenn letzterer nicht dem Standard entspricht. In den meisten Fällen reicht ein Eintrag wie "https://www.example.com". EN Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin.

Enter a comma separated list of hostnames you want to give access to your Lyrion Music Server. The entries need to have the protocol (eg. "http"), full host name ("www.example.com"), plus the port number, should the latter be non-standard. In most cases something like "https://www.example.com" should be good enough. @@ -9962,7 +9971,7 @@ SETUP_INSECURE_HTTPS2 NL Uitschakelen van certificaatverificatie bij HTTPS verbindingen SETUP_INSECURE_HTTPS_DESC - CS Povolením možnosti "Nezabezpečené HTTPS" se vypne ověřování certifikátů, pokud Lyrion Music Server funguje jako klient HTTPS. Povolení této možnosti se nedoporučuje! Vypnutí ověřování certifikátů je špatnou praxí, ale za určitých okolností může být nezbytné, např. když nelze aktualizovat knihovny. + CS Povolením možnosti „Nezabezpečené HTTPS" se vypne ověřování certifikátů, pokud Lyrion Music Server funguje jako klient HTTPS. Povolení této možnosti se nedoporučuje! Vypnutí ověřování certifikátů je špatnou praxí, ale za určitých okolností může být nezbytné, např. když nelze aktualizovat knihovny. DA Aktivering af "Usikker HTTPS" betyder, at certifikat verifikation deaktiveres når Lyrion Music Server er en HTTPS klient. Aktivering af denne option anbefales ikke! Grundlæggende bør certifikater altid verificeres, men det kan være nødvendigt under visse omstændigheder, f.eks. hvis et onlinebibliotek ikke kan opdateres. DE "Unsicheres HTTPS" bedeutet, dass Lyrion Music Server Zertifikate von entfernten Servern nicht mehr auf ihre Gültigkeit überprüft. Es wird nicht empfohlen, diese Option zu aktivieren!. Grundsätzlich sollten Zertifikate immer überprüft werden. Allerdings kann dies unter Umständen fehlschlagen, wenn etwa eine Bibliothek nicht aktualisiert werden kann. EN Enabling "Insecure HTTPS" switches off certificate verification when Lyrion Music Server acts as an HTTPS client. Enabling this option is discouraged! It is bad practice to disable certificate verification, but can be necessary under certain circumstances, eg. when the libraries can't be updated. @@ -10134,7 +10143,7 @@ SETUP_BAD_VALUE ZH_CN 指定价值无效: %s SETTINGS_INVALIDVALUE - CS Neplatná hodnota "%s" pro %s + CS Neplatná hodnota „%s" pro %s DA Værdien "%s" for %s er ugyldig DE "%s" ist kein gültiger Wert für %s EN Invalid value "%s" for %s @@ -10206,7 +10215,7 @@ SETUP_AUTHORIZE ZH_CN 密码保护 SETUP_AUTHORIZE_DESC - CS Můžete si zvolit ochranu heslem pro dálkové ovládání Lyrion Music Serveru. Zvolte "Ochrana heslem" níže a zadejte uživatelské jméno a heslo, potom klikněte na Změnit. Od tohoto okamžiku budete muset při používání dálkového ovládání Lyrion Music Serveru zadávat toto uživatelské jméno a heslo ve svém webovém prohlížeči. + CS Můžete si zvolit ochranu heslem pro dálkové ovládání Lyrion Music Serveru. Zvolte „Ochrana heslem" níže a zadejte uživatelské jméno a heslo, potom klikněte na Změnit. Od tohoto okamžiku budete muset při používání dálkového ovládání Lyrion Music Serveru zadávat toto uživatelské jméno a heslo ve svém webovém prohlížeči. DA Du kan vælge at beskytte adgangen til Lyrion Music Servers fjernbetjening med en adgangskode. Vælg Beskyt med adgangskode, angiv et brugernavn og en adgangskode, og klik på Skift. Når du herefter ønsker at bruge Lyrion Music Servers fjernbetjening, skal du angive brugernavnet og adgangskoden i browseren. DE Sie können Lyrion Music Server Remote Control mit einem Kennwort schützen. Klicken Sie unten auf 'Kennwortschutz', geben Sie einen Benutzernamen und ein Kennwort ein, und klicken Sie auf 'Ändern'. Wenn Sie dann Lyrion Music Server Remote Control aufrufen, müssen Sie diesen Benutzernamen und das Kennwort eingeben. EN You can choose to password protect Lyrion Music Server Remote Control. Choose "Password protection" below and enter a username and password, then click Change. From that point on when you use Lyrion Music Server Remote Control, you'll need to enter this username and password in your web browser. @@ -10371,7 +10380,7 @@ LANGUAGE ZH_CN 语言 SETUP_RELEASE_TYPES - CS Typy vydání pro Alba + CS Typy vydání pro alba DA Udgivelsestyper for albums DE Album Veröffentlichungstypen EN Release types for Albums @@ -10381,7 +10390,7 @@ SETUP_RELEASE_TYPES PT Tipo de lançamento para os albuns SETUP_RELEASE_TYPES_INCLUDE - CS Typy vydání zahrnuté do seznamu Alb + CS Typy vydání zahrnuté do seznamu alb DA Udgivelsestyper for filtrering og inkludering i Album liste DE Album Veröffentlichungstypen filtern EN Release types to include in Albums list @@ -10391,7 +10400,7 @@ SETUP_RELEASE_TYPES_INCLUDE PT Tipos de lançamentos para serem incluídos na Lista de albuns SETUP_RELEASE_TYPES_DESC - CS Můžete určit, jaké typy vydání chcete zahrnout do seznamu alb (viz MusicBrainz). Pokud vydání nemá definovaný typ, předpokládá se "Album". Alba nelze z tohoto seznamu vyloučit. + CS Můžete určit, jaké typy vydání chcete zahrnout do seznamu alb (viz MusicBrainz). Pokud vydání nemá definovaný typ, předpokládá se „Album". Alba nelze z tohoto seznamu vyloučit. DA Du kan specificere hvilke udgivelsestypper som ønskes inkluderet i Album listen (se MusicBrainz). Hvis en udgivelse ikke har en typespecifikation, bliver "Album" antaget og de kan ikke bortfiltreres fra listen. DE Sie können angeben, welche Veröffentlichungstypen (siehe MusicBrainz) in der Albenliste mit aufgeführt werden sollen. Falls für eine Veröffentlichung kein Typ definiert wurde, so wird "Album" angenommen. Diese können nicht ausgeschlossen werden. EN You can specify what release types you want to include in the albums list (see MusicBrainz). If a release doesn't have a type defined, "Album" is assumed. Albums can't be excluded from that list. @@ -10411,7 +10420,7 @@ SETUP_RELEASE_TYPES_COMPOSER_ALBUM_GROUP_OPTIONS PT Opções para Compositor do album SETUP_RELEASE_TYPES_COMPOSER_ALBUM_GROUP_OPTIONS_DESC - CS Vytvořit skupinu Alba skladatele – vždy, nikdy nebo pro určité žánry. Pokud kvůli tomuto nastavení nejsou některé skladatelské role zahrnuty do skupiny Alba skladatele, zobrazí se místo toho v samostatné skupině "Kompozice", která bude obsahovat seznam jednotlivých skladeb, nikoli alb. Seznam žánrů by měl být oddělen čárkou. + CS Vytvořit skupinu Alba skladatele – vždy, nikdy nebo pro určité žánry. Pokud kvůli tomuto nastavení nejsou některé skladatelské role zahrnuty do skupiny Alba skladatele, zobrazí se místo toho v samostatné skupině „Kompozice", která bude obsahovat seznam jednotlivých skladeb, nikoli alb. Seznam žánrů by měl být oddělen čárkou. DA Opret en Komponistalbum gruppe - altid, aldrig, eller for bestemte genrer. Når visse komponist roller ikke inkluderes i Composer Albums pga. denne indstilling, vil de i stedet dukke op i en separat "Compositions" gruppe, som lister individuelle numre, ikke albums. Listen over genrer skal være komma-separeret. EN Create a Composer Albums group - always, never, or for certain genres. If due to this setting, certain composer roles are not included in the Composer Albums group, they will appear in a separate "Compositions" group instead, which will list individual tracks, not albums. The genre list should be comma separated. FR Créer un groupe "Albums du compositeur" : toujours, jamais ou pour des genres spécifiques. Si, en raison de ce paramètre, certaines œuvres du compositeur ne sont pas incluses dans le groupe "Albums du compositeur", elles apparaîtront à la place dans un groupe "Compositions" distinct, qui répertoriera les morceaux individuels, pas les albums. (Par exemple, un morceau avec un tag "ARTIST" différent du tag "COMPOSER" se retrouvera dans le groupe "Compositions".) Les genres de la liste doivent être séparés par des virgules. @@ -10441,7 +10450,7 @@ SETUP_RELEASE_TYPES_COMPOSER_ROLE_GROUPING_1 ES Crear siempre un grupo de Álbum de compositor SETUP_RELEASE_TYPES_COMPOSER_ROLE_GROUPING_2 - CS Vytvoření skupiny Skladatelské album pro "Moje žánry pro díla a skladatelská alba" (výše) + CS Vytvoření skupiny Skladatelské album pro „Moje žánry pro díla a skladatelská alba" (výše) DA Opret en komponistalbumgruppe for "Mine genrer til værker og komponistalbums" (ovenfor) DE Erstellen einer Komponistenalbengruppe für "Genres für Werke und Komponistenalben" (oben) EN Create a Composer Album group for "My work and composer album genres" (above) @@ -10451,7 +10460,7 @@ SETUP_RELEASE_TYPES_COMPOSER_ROLE_GROUPING_2 NL Maak een componistenalbumgroep voor 'Mijn genres voor werken en albums van componisten' (hierboven) SETUP_IGNORE_RELEASE_TYPES_0 - CS Povolit podporu typu vydání pro alba + CS Povolit podporu typů vydání pro alba DA Aktivér understøttelse af udgivelsestyper for albums DE Unterstützung für Veröffentlichungstypen von Alben aktivieren EN Enable release type support for albums @@ -10471,7 +10480,7 @@ SETUP_IGNORE_RELEASE_TYPES_1 PT Ignore o tipo de lançamento dos albuns SETUP_CLEANUP_RELEASE_TYPES - CS Zkusit automaticky rozpoznat EP a singly, pokud je informace o typu vydání "album" nebo chybí. + CS Zkusit automaticky rozpoznat EP a singly, pokud je informace o typu vydání „album" nebo chybí. DA Forsøg at genkende EPs og singler automatisk, når udgivelsestype informationen er "Album" eller mangler. DE Versuchen, EPs und Singles ohne definierten Veröffentlichungstypen, oder die als Album deklariert sind, selber zu erkennen. EN Try to recognize EPs and singles automatically when release type information is "album" or is missing. @@ -10531,7 +10540,7 @@ SETUP_GROUPDISCS ZH_CN 组合光碟 SETUP_GROUPDISCS_DESC - CS Můžete zadat, aby vícediskové sady byly považovány za jedno album (s jedním názvem) nebo za více alb, každé se svým názvem pro disk, například "Název alba (disk 2 ze 3)". Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. + CS Můžete zadat, aby vícediskové sady byly považovány za jedno album (s jedním názvem) nebo za více alb, každé se svým názvem pro disk, například „Název alba (disk 2 ze 3)". Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. DA Du kan angive om album med flere cd'er skal opfattes som et enkelt album (med et enkelt navn), eller som flere album med et unikt navn for hver cd, fx Albumtitel (cd 1 af 3). Hvis du ændrer denne indstilling, bliver dit musikbibliotek gennemsøgt igen. DE Sie können angeben, ob mehrere CDs eines Albums als ein Album (unter dem gleichen Namen) oder als getrennte Alben (z.B. 'Albumtitel (CD 1 von 2)' angezeigt werden sollen. Wenn Sie diese Einstellung ändern, wird die Musiksammlung erneut durchsucht. EN You can specify if multiple disc sets are treated as a single album (with a single name) or as multiple albums, each with a unique name per disc, for example "Album Title (Disc 2 of 3)". Changing this setting will start a rescan of your music library. @@ -10615,6 +10624,7 @@ SETUP_NO_JAVASCRIPT SV Använd en aktuell webbläsare (Firefox®, Apple Safari®, Microsoft® Internet Explorer 10, Opera 25 eller senare) och kontrollera att JavaScript är aktiverat i webbläsaren för att få tillgång till Lyrion Music Server. Alternativt kan du använda ett enklare skal, t.ex. Classic. SETUP_WIZARD_WELCOME + CS Vítejte v úvodním nastavení Lyrion Music Serveru DA Velkommen til den indledende opsætning af Lyrion Music Server DE Willkommen beim Einrichtungsassistenten für ihr neues Lyrion Music Server Setup EN Welcome to the initial Lyrion Music Server setup @@ -10623,6 +10633,7 @@ SETUP_WIZARD_WELCOME HU Üdvözöljük a Lyrion Music Server kezdő beállításokban SETUP_WIZARD_WELCOME_INTRO + CS Tento průvodce vás provede úvodním nastavením vašeho Lyrion Music Serveru. DA Denne assistent vil hjælpe dig igennem den indledende opsætning af din Lyrion Music Server. DE Dieser Assistent führt dich durch den initalen Setup deines Lyrion Music Servers. EN This assistant will guide you through the initial setup of your Lyrion Music Server. @@ -10631,6 +10642,7 @@ SETUP_WIZARD_WELCOME_INTRO HU Ez az asszisztens végigvezeti Önt a Lyrion Music Server kezdeti beállításán. SETUP_WIZARD_PLUGINS_INTRO + CS Doporučujeme instalaci následujících zásuvných modulů (pluginů) třetích stran. Mnoho dalších zásuvných modulů lze kdykoli nainstalovat v Nastavení/Správa zásuvných modulů po dokončení instalace. DA Vi anbefaler installation af følgende tredjeparts plugins. Mange andre plugins kan installeres i Settings/Manage Plugins efter at installationen er afsluttet. DE Wir empfehlen die Installations folgender Drittanbietererweiterungen. Zahlreiche weitere Plugins können später zu jeder Zeit hinzugefügt werden. Wählen Sie herfür später Einstellungen/Plugins verwalten. EN We recommend the installation of the following 3rd party plugins. Many other plugins can be installed any time in Settings/Manage Plugins after the installation has completed. @@ -12741,6 +12753,7 @@ ALBUM ZH_CN 专辑 RELEASE_TYPE + CS Typ vydání DA Udgivelsestype DE Veröffentlichungstyp EN Release type @@ -12748,42 +12761,52 @@ RELEASE_TYPE NL Releasetype RELEASE_TYPE_SINGLE + CS Singl DA Single EN Single RELEASE_TYPE_SINGLES + CS Singly DA Singler EN Singles RELEASE_TYPE_EP + CS EP DA EP EN EP RELEASE_TYPE_EPS + CS EP DA EPs EN EPs RELEASE_TYPE_BESTOF + CS Výběr EN Best Of RELEASE_TYPE_BESTOFS + CS Výběry EN Best Ofs RELEASE_TYPE_BOXSET + CS Box set DA Samling EN Box Set FR Coffret RELEASE_TYPE_BOXSETS + CS Box sety DA Samlinger EN Box Sets FR Coffrets RELEASE_TYPE_BROADCAST + CS Vysílání DA Udsendelse EN Broadcast RELEASE_TYPE_OTHER + CS Jiné DA Andre DE Andere EN Other @@ -13420,6 +13443,7 @@ MODTIME ZH_CN 日期已更改 ADDEDTIME + CS Datum přidání DA Tilføjet den DE Hinzugefügt am EN Date Added @@ -14769,6 +14793,7 @@ BROWSE_BY_SONG_DBL PL Utwory BROWSE_BY_WORK + CS Díla DA Værker DE Werke EN Works @@ -15243,7 +15268,7 @@ FILENAME_WARNING SV Namnet innehåller otillåtna tecknet. Ändra namnet. RENAME_WARNING - CS Název, který jste zvolili, byl již vybrán. Zvolte prosím pro svůj seznam skladeb jiný název nebo zaškrtnutím "Potvrdit přepsání" přepište stávající seznam skladeb. + CS Název, který jste zvolili, byl již vybrán. Zvolte prosím pro svůj seznam skladeb jiný název nebo zaškrtnutím „Potvrdit přepsání" přepište stávající seznam skladeb. DA Navnet du angav, er allerede i brug. Giv afspilningslisten et andet navn, eller vælg at overskrive den eksisterende. DE Dieser Name ist bereits vorhanden. Wählen Sie einen anderen für die Wiedergabeliste oder aktivieren Sie 'Überschreiben bestätigen'. EN The name you chose is already taken. Please choose another name for your playlist, or check 'confirm overwrite' to replace your existing playlist. @@ -15263,7 +15288,7 @@ RENAME_WARNING ZH_CN 您选择的名字已被使用。请选择其它的播放表名字,或选择《确定重写》替换您现有的播放表。 DELETE_WARNING - CS Jste si jisti, že je chcete odstranit? Zaškrtněte políčko "Potvrdit odstranění", chcete-li odstranit svůj seznam skladeb. + CS Jste si jisti, že je chcete odstranit? Zaškrtněte políčko „Potvrdit odstranění", chcete-li odstranit svůj seznam skladeb. DA Vil du slette? Du skal markere "bekræft sletning" for at slette afspilningslisten. DE Wirklich löschen? Aktivieren Sie 'Löschen bestätigen', um die Wiedergabeliste zu löschen. EN Are you sure you want to delete? Check 'confirm delete' to delete your playlist. @@ -15936,7 +15961,7 @@ DEBUG_DEFAULT SV Återställ loggningsinställningar SETUP_GROUP_DEBUG_DESC - CS Lyrion Music Server má řadu nastavení protokolování, která lze použít pro zapsání podrobných informací o provozu serveru a prohledávání. Každá kategorie protokolů má určitou závažnost pro protokolování. Volba "Ladění" je nejvíce informativní, volba "Vypnuto" nejméně. + CS Lyrion Music Server má řadu nastavení protokolování, která lze použít pro zapsání podrobných informací o provozu serveru a prohledávání. Každá kategorie protokolů má určitou závažnost pro protokolování. Volba „Ladění" je nejvíce informativní, volba „Vypnuto" nejméně. DA Lyrion Music Server har en række indstillinger til logføring som kan bruges til at registrere detaljerede oplysninger om serveren og søgninger. Hver logføringskategori kan indstilles til at registrere flere eller færre oplysninger. Fejlsøgning giver flest detaljer og Fra ingen. DE Lyrion Music Server enthält eine Reihe von Protokolleinstellungen, mit denen Sie umfangreiche Angaben über Lyrion Music Server- und Scanner-Vorgänge aufzeichnen können. Jede Protokollkategorie unterliegt einer Begrenzung in der Protokollierung ("Debug" mit der höchsten Wortanzahl, "Off" mit der niedrigsten). EN Lyrion Music Server has a number of logging settings that can be used to record detailed information about server and scanner operation. Each logging category has a severity for logging. With "Debug" being the most verbose, and "Off" being the least. @@ -16995,7 +17020,7 @@ CSRF_ERROR_INFO ZH_CN 如果要从Bookmark/Favorite或其他方法请求这URL(从Lyrion Music Server网界面跟随链接除外),您将需要使用以\"cauth \"为安全参数的URL。如果您从Lyrion Music Server网界面跟随链接而出现错误,您需要确定您的浏览器软件(包括网代理伺服器和spyware/privacy软件)允许发送\"Referer\"倒坠。下面是您试图访问的URL的正确的URL。 CSRF_ERROR_MEDIUM - CS

Jelikož je vaše úroveň ochrany CSRF nastavena na "STŘEDNÍ", můžete použít stejnou hodnotu ";cauth=" pro libovolnou adresu URL; to znamená, že byste měli být opatrnější, s kým sdílíte své adresy URL.

+ CS

Jelikož je vaše úroveň ochrany CSRF nastavena na „STŘEDNÍ", můžete použít stejnou hodnotu ";cauth=" pro libovolnou adresu URL; to znamená, že byste měli být opatrnější, s kým sdílíte své adresy URL.

DA

Da CSRF-beskyttelsesnivauet er sat til Mellem, kan du anvende den samme værdi for cauth= i alle internetadresser. Det betyder at du skal være forsigtig med hvem du deler dine adresser med.

DE

Da Ihr CSRF-Schutzniveau auf 'Medium' (Mittel) gesetzt ist, können Sie denselben ';cauth' Wert für beliebige URLs verwenden. Dies bedeutet aber, dass Sie beim Austausch dieser URLs vorsichtig vorgehen sollten.

EN

Because your CSRF protection level is set at 'MEDIUM', you can use the same ";cauth=" value for any URL; this means you should be more careful who you share your URLs with.

@@ -18021,6 +18046,7 @@ RADIO_PROVIDERS_SOMAFM SV SomaFM RADIO_PROVIDERS_SKYFM + CS RadioTunes EN RadioTunes NL RadioTunes NO RadioTunes @@ -18137,7 +18163,7 @@ RADIO_TUNEIN_NOW ZH_CN 现在调谐 RADIO_TUNEIN_DESC - CS Pokud již znáte adresu URL stanice, kterou chcete poslouchat, zadejte ji zde a klikněte na tlačítko "Naladit". Můžete zadat adresu URL buď samotného radiového proudu (např. http://62.49.59.50:8000) nebo souboru seznamu skladeb, který k proudu odkazuje (např. http://www.hitzradio.com/hitzradio.pls). + CS Pokud již znáte adresu URL stanice, kterou chcete poslouchat, zadejte ji zde a klikněte na tlačítko „Naladit". Můžete zadat adresu URL buď samotného radiového proudu (např. http://62.49.59.50:8000) nebo souboru seznamu skladeb, který k proudu odkazuje (např. http://www.hitzradio.com/hitzradio.pls). DA Hvis du allerede kender stationens internetadresse, kan du angive den her og klikke på Stil ind. Du kan angive adressen til selve radiostreamen (fx http://62.49.59.50:8000) eller til en afspilningsliste der henviser til den (fx http://www.hitzradio.com/hitzradio.pls). DE Falls Sie die URL eines Internet-Radiosenders bereits kennen, können Sie diese hier eingeben und auf 'Sender wählen' klicken. Sie können entweder die URL des Datenstroms (z.B. http://62) oder die Wiedergabeliste, die auf den Datenstrom zeigt (z.B. http://www.hitzradio.com/hitzradio.pls) eingeben. EN If you already know the URL of the station you would like to listen to, enter it here and click on the "Tune In" button. You can enter the URL of either the radio stream itself (e.g. http://62.49.59.50:8000) or the playlist file that is pointing to the stream (e.g. http://www.hitzradio.com/hitzradio.pls). @@ -19722,6 +19748,7 @@ ANY_TYPE ZH_CN 任何文件格式 MIDWORDS_UPPER + CS 0 DA 0 DE 1 EN 0 @@ -19977,7 +20004,7 @@ SETUP_VARIOUSARTISTS ZH_CN 合辑 SETUP_VARIOUSARTISTAUTOIDENTIFICATION_DESC - CS Můžete si zvolit, aby se sbírky alb zobrazily společně pod "Různí interpreti" nebo aby se zobrazily pod každým interpretem ve sbírce. + CS Můžete si zvolit, aby se sbírky alb zobrazily společně pod „Různí interpreti" nebo aby se zobrazily pod každým interpretem ve sbírce. DA Du kan vælge at vise kompilationsalbum samlet under Diverse kunstnere, eller under hver kunstner på kompilationen. DE Sie können Kompilationen (Alben mit mehreren Interpreten) zusammen unter 'Diverse Interpreten' aufführen oder die einzelnen Lieder unter den einzelnen Interpreten. EN You can choose to have compilation albums appear together under "Various Artists" or have them appear under each artist in the compilation. @@ -20031,7 +20058,7 @@ SETUP_VARIOUSARTISTAUTOIDENTIFICATION_0 ZH_CN 把合辑发表在个别艺人中 SETUP_VARIOUSARTISTSSTRING_DESC - CS Pokud jsou sbírky seskupeny dohromady, zobrazí se standardně pod názvem "Různí interpreti". Tento název můžete změnit níže. + CS Pokud jsou sbírky seskupeny dohromady, zobrazí se standardně pod názvem „Různí interpreti". Tento název můžete změnit níže. DA Når numrene på kompilationsalbum grupperes, vises de som standard under Diverse. Du kan ændre navnet nedenfor. DE Gruppierte Kompilationen werden standardmäßig unter 'Diverse Interpreten' angezeigt. Sie können diesen Namen unten ändern. EN When compilation albums are grouped together, they appear under "Various Artists" by default. You can change that name below. @@ -20126,7 +20153,7 @@ UNSYNC ZH_CN 非同步 SETUP_USEBANDASALBUMARTIST_DESC - CS Alba obsahující skladby, které jsou označené štítkem skupiny, mohou být u tohoto alba uvedena buď pod jménem skupiny nebo s ostatními interprety. Tag skupiny se nazývá také TPE2 a v některých programech se může zobrazovat jako "Interpret alba". + CS Alba obsahující skladby, které jsou označené tagem skupiny, mohou být u tohoto alba uvedena buď pod jménem skupiny nebo s ostatními interprety. Tag skupiny se nazývá také TPE2 a v některých programech se může zobrazovat jako „Interpret alba". DA Album der indeholder numre som er mærket med navnet på et band, kan vises under dette bands navn eller sammen med de andre kunstnere som optræder på albummet. Bandmærket kaldes også TPE2 og vises som "album artist" i nogle programmer. DE Alben, die Lieder enthalten, die mit einem Band-Tag versehen sind, können unter diesem Interpreten oder bei den übrigen Interpreten des Albums aufgeführt werden. Der Band-Tag (auch TPE2 genannt) wird in bestimmten Anwendungen auch als 'Album Artist' (Albuminterpret) bezeichnet. EN Albums that contain songs that are tagged with a band may be listed under that band name or with the other artists for that album. The band tag is also known as TPE2 and may appear as the "album artist" in some software. @@ -20143,7 +20170,7 @@ SETUP_USEBANDASALBUMARTIST_DESC SV Album som innehåller låtar som taggats med ett bandnamn kan listas under bandnamnet eller tillsammans med de andra artisterna på albumet. Bandtaggen kallas också TPE2, och visas i vissa program som Albumartist. SETUP_USETPE2ASALBUMARTIST_DESC - CS Formát MP3 tagů neposkytuje standardní způsob, jak definovat Interpreta alba. Některé nástroje pro MP3 tagy používají pro Interpreta alba pole TPE2 (iTunes, Winamp, Windows Media Player), jiné je mohou používat pro zamýšlený význam "Skupina/orchestr". Zvolte význam, který má Lyrion Music Server používat. Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. + CS Formát MP3 tagů neposkytuje standardní způsob, jak definovat Interpreta alba. Některé nástroje pro MP3 tagy používají pro Interpreta alba pole TPE2 (iTunes, Winamp, Windows Media Player), jiné je mohou používat pro zamýšlený význam „Skupina/orchestr". Zvolte význam, který má Lyrion Music Server používat. Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. DA MP3-mærkeformatet er en standardiseret metode til at definere en kunstner og dennes album. Nogle programmer til at håndtere mp3-mærker benytter feltet TPE2 til Albumkunstner (iTunes, Winamp, Windows Media Player) mens andre benytter det til den intenderede betydning af Band/orkester. Du skal vælge hvilken model der skal bruges i Lyrion Music Server. Hvis du ændrer indstillingen, bliver hele musikbiblioteket gennemsøgt igen. DE Das MP3-Tag-Format bietet keine Standardmöglichkeit zum Definieren des Interpreten des Albums. Manche MP3-Anwendungen (iTunes, Winamp, Windows Media Player) nutzen das Feld TPE2 für den Interpreten des Albums, andere nutzen es für den eigentlichen Zweck (Band/Orchester). Wählen Sie die gewünschte Bedeutung. Wenn Sie diese Einstellung ändern, wird die Musiksammlung erneut durchsucht. EN The MP3 tag format does not provide a standard way of defining an Album Artist. Some MP3 tagging tools use the TPE2 field for Album Artist (iTunes, Winamp, Windows Media Player) while others may use it for the intended meaning of "Band/orchestra". Select the meaning you would like Lyrion Music Server to use. Changing this setting will start a rescan of your music library. @@ -20372,7 +20399,7 @@ ARTWORK ZH_CN 封面图 ONE_BY_ONE_ARTWORK - CS Obaly alb "jeden po druhém" + CS Obaly alb „jeden po druhém" DA Albumcover 1-til-1 DE Plattenhüllen einzeln EN 1-by-1 Artwork @@ -21399,7 +21426,7 @@ SETUP_WORDCLOCKOUTPUT ZH_CN S/PDIF输出产生字形时钟信息 SETUP_WORDCLOCKOUTPUT_DESC - CS Při použití digitálních vstupů může Transporter být nadřízeným generátorem taktu ("clock master") a vysílat taktovací signál (word clock) do svých výstupů S/PDIF. Tuto funkci je nutno povolit pouze tehdy, když zdrojové zařízení zajišťuje vstup taktovacího signálu (word clock) a kabel je připojen. + CS Při použití digitálních vstupů může Transporter být nadřízeným generátorem taktu („clock master") a vysílat taktovací signál (word clock) do svých výstupů S/PDIF. Tuto funkci je nutno povolit pouze tehdy, když zdrojové zařízení zajišťuje vstup taktovacího signálu (word clock) a kabel je připojen. DA Ved brug af de digitale indgange, kan Transporter virke som clock-master og sende et såkaldt Wordclock-signal via S/PDIF-udgangene. Denne funktion må kun aktiveres hvis kilde-enheden sender et Wordclock-signal, og kablet er forbundet. DE Wenn die digitalen Eingänge verwendet werden, kann Transporter das Signal direkt durchschleifen oder an den S/PDIF-Ausgängen ein Word Clock-Signal erzeugen. EN When using the digital inputs, Transporter can be the clock master, and transmit a word clock signal on its S/PDIF outputs. This feature must only be enabled if the source device provides a word clock input and the cable is connected. @@ -21671,7 +21698,7 @@ SETUP_ANALOGOUTMODE SV Utgång SETUP_ANALOGOUTMODE_DESC - CS Zvolte funkci portu sluchátka/sub out Boomu. Volba Sluchátka vypne vnitřní reproduktory. Volba "Vždy zapnuto" ponechá vnitřní reproduktory zapnuté i při připojených sluchátkách. + CS Zvolte funkci portu sluchátka/sub out Boomu. Volba Sluchátka vypne vnitřní reproduktory. Volba „Vždy zapnuto" ponechá vnitřní reproduktory zapnuté i při připojených sluchátkách. DA Vælg hvad der skal ske når noget sluttes til udgangsstikket til hovedtelefoner/subwoofer på Boom. Når der tilsluttes hovedtelefoner, bliver de indbyggede højtalere slået fra. Hvis du vælger Altid slået til, forbliver de indbyggede højtalere slået til, også selvom der tilsluttes hovedtelefoner. DE Wählen Sie die Funktion des Kopfhörer/Sub Out-Anschlusses von Boom. 'Kopfhörer' deaktiviert die internen Lautsprecher. Mit 'Immer Aktiv' bleiben die internen Lautsprecher aktiv, auch wenn Kopfhörer angeschlossen sind. EN Choose the function of Boom headphone/sub out port. Headphone option will shut off the internal speakers. "Always On" will keep the internal speakers enabled, even while headphones are plugged in. @@ -25452,7 +25479,7 @@ CONTROLPANEL_PORTBLOCKED_APPS SV Följande program kan blockera anslutningen: CONTROLPANEL_CONFLICT_CISCOVPNSTATEFULINSPECTION - CS Pokud se vyskytnou problémy s připojením k Lyrion Music Serveru, ujistěte se, že je vypnuta funkce "Stateful Firewall (Always On)" + CS Pokud se vyskytnou problémy s připojením k Lyrion Music Serveru, ujistěte se, že je vypnuta funkce „Stateful Firewall (Always On)" DA Hvis der er problemer med forbindelsen til og fra Lyrion Music Server, skal du kontrollere at "Stateful Firewall (Always On)" er slået fra DE Wenn es Verbindungsprobleme mit Lyrion Music Server gibt, vergewissern Sie sich, dass die Option "Statusbehaftete Firewall (immer aktiv)" deaktiviert ist. EN If you encounter connectivity issues with Lyrion Music Server, please make sure "Stateful Firewall (Always On)" is turned off @@ -25805,7 +25832,7 @@ CONTROLPANEL_NO_STATUS SV Det finns ingen statusinformation. Tänk på att statusinformationen inte kan visas när Lyrion Music Server inte körs. CONTROLPANEL_NEED_ADMINISTRATOR - CS Nemáte práva instalovat nebo spouštět/zastavovat procesy Lyrion Music Serveru na pozadí. Spusťte ovládací panel z nabídky Start systému Windows prostřednictvím kontextové nabídky vyvolané pravým klepnutím tlačítka, a klikněte na možnost "Spustit jako správce". + CS Nemáte práva instalovat nebo spouštět/zastavovat procesy Lyrion Music Serveru na pozadí. Spusťte ovládací panel z nabídky Start systému Windows prostřednictvím kontextové nabídky vyvolané pravým klepnutím tlačítka, a klikněte na možnost „Spustit jako správce". DA Du har ikke rettigheder til at installere eller starte/stoppe baggrundstjenesten Lyrion Music Server. Start kontrolpanelet fra Startmenuen i Windows – via højrekliksmenuen klikker du på "Kør som administrator". DE Sie sind nicht dazu berechtigt, den Lyrion Music Server-Hintergrunddienst zu installieren oder zu starten bzw. anzuhalten. Öffnen Sie die Systemsteuerung im Windows-Startmenü über das Kontextmenü und wählen Sie 'Als Administrator ausführen'. EN You don't have privileges to install or start/stop the Lyrion Music Server background service. Please start the control panel from the Windows Start Menu, via the right click context menu, and click "Run as Administrator". @@ -25855,7 +25882,7 @@ RUN_AT_LOGIN SV Kör automatiskt vid inloggning RUN_FAILSAFE - CS Spustit bez zásuvných modulů ("Bezpečný režim") + CS Spustit bez zásuvných modulů („Bezpečný režim") DA Kør uden udvidelsesmoduler (fejlsikret tilstand) DE Ohne Benutzererweiterungen ausführen ("Abgesicherter Modus") EN Run with no user extensions ("Safe Mode") @@ -26094,7 +26121,7 @@ INTERNET_RADIO SV Radio HOWTO_INTERNET_RADIO - CS Přejděte na položku "Nejoblíbenější internetová rádia" a stiskněte tlačítko DOPRAVA. + CS Přejděte na položku „Nejoblíbenější internetová rádia" a stiskněte tlačítko DOPRAVA. DA Find Det bedste fra internetradio, og tryk på højrepilen. DE Markieren Sie die Option 'Die besten Internetradiosender' und drücken Sie RECHTS. EN Scroll to "Best of Internet Radio" and press RIGHT. @@ -26111,7 +26138,7 @@ HOWTO_INTERNET_RADIO SV Bläddra till Webbradiofavoriter och tryck på högerknappen. HOWTO_INTERNET_RADIO_CONTROLLER - CS Přejděte na položku "Nejoblíbenější internetová rádia" a stiskněte středové tlačítko. + CS Přejděte na položku „Nejoblíbenější internetová rádia" a stiskněte středové tlačítko. DA Find Det bedste fra internetradio, og tryk på midterknappen. DE Markieren Sie 'Die besten Internetradiosender' und drücken Sie die mittlere Taste. EN Scroll to "Best of Internet Radio" and press the center button. @@ -26769,6 +26796,7 @@ UPDATE SV Uppdatera TRACKS_FROM_OTHER_ALBUMS + CS Skladby z jiných alb DE Titel von anderen Alben DA Numre fra andre albums EN Tracks from other albums @@ -26779,6 +26807,7 @@ TRACKS_FROM_OTHER_ALBUMS PT Pistas de outros albuns SETUP_YEARMENU + CS Nabídka Roky DE Jahre Menü DA Årsmenu EN Year Menu @@ -26788,6 +26817,7 @@ SETUP_YEARMENU PT Menu Ano SETUP_YEARMENU_DESC + CS Má nabídka Roky zobrazovat pouze roky alb, nebo roky alb i skladeb? DA Skal årsmenuen kun vise album året, eller album- og nummeråret? DE Soll das Jahresmenü nur Albumjahre oder Album- und Trackjahre anzeigen? EN Should the Year menu show album years only, or album and track years? @@ -26797,6 +26827,7 @@ SETUP_YEARMENU_DESC PT O menu Ano deverá mostar só o ano do album ou de ambos, do album e da pista? SETUP_YEARMENU_0 + CS Zobrazit pouze roky alb DA Vis kun album året DE Zeige nur Albumjahre EN Show album years only @@ -26806,6 +26837,7 @@ SETUP_YEARMENU_0 PT Mostrar sómente o ano do album SETUP_YEARMENU_1 + CS Zobrazit roky alb i skladeb DA Vis album- og nummeråret DE Zeige Album- und Titeljahre EN Show album and track years @@ -26815,6 +26847,7 @@ SETUP_YEARMENU_1 PT Mostrar o ano do album e de cada pista SETUP_ALBUMLINKROLES + CS Odkazy interpretů v seznamech alb DA Kunstnerlinks i albumlisten DE Künstlerlinks in Albumlisten EN Artist links in album lists @@ -26825,6 +26858,7 @@ SETUP_ALBUMLINKROLES PT Links de artistas nas listas de álbuns SETUP_ALBUMLINKROLES_DESC + CS Můžete si vybrat, které role se mají zobrazit jako odkazy v seznamech alb. Hlavní přispěvatel alba identifikovaný hudebním skenerem bude vždy zobrazen. Také při procházení alb/vydání podle role budou zobrazeni přispěvatelé pro prohlíženou roli. DA Du kan vælge hvilke roller der skal vises som links i album listen. Albumets hovedkunstner vil altid blive vist. Når du gennemser album/udgivelser efter rolle, vises bidragyderne til den rolle, der gennemses. DE Sie können auswählen, welche Rollen als Links in Albumlisten angezeigt werden sollen. Der Hauptkünstler des Albums wird immer angezeigt. Wenn Sie Alben/Veröffentlichungen nach Rolle durchsuchen, werden auch die Mitwirkenden für die Rolle angezeigt, die gerade durchsucht wird. EN You can choose which roles to show as links in album listings. The main album contributor as identified by the music scanner will always be shown. Also, when browsing albums/releases by role, the Contributors for the role being browsed will be shown. @@ -26835,6 +26869,7 @@ SETUP_ALBUMLINKROLES_DESC PT Pode escolher quais as funções que serão apresentadas como links nas listas de álbuns. O principal contribuidor do álbum identificado pelo scanner de música será sempre mostrado. Além disso, ao navegar por álbuns/lançamentos por função, os Colaboradores para a função que está sendo navegada serão mostrados. SETUP_USERDEFINEDROLES + CS Uživatelsky definované role DA Brugerdefinerede roller EN User Defined Roles DE Benutzerdefinierte Rollen @@ -26844,6 +26879,7 @@ SETUP_USERDEFINEDROLES NL Door de gebruiker gedefinieerde rollen SETUP_USERDEFINEDROLES_DESC + CS Sdělte LMS jakékoli vlastní tagy rolí přispěvatelů používané v hudební knihovně. Například SOLOIST, DRUMMER, PRODUCER atd. Změny tagů rolí spustí opětovné prohledání vaší hudební knihovny. DA Oplys om de brugerdefinerede rolle-mærker, som bruges i musikbiblioteket. For eksempel SOLOIST, DRUMMER, PRODUCER, etc. Ændringer i rolle-mærker vil udløse en ny scanning af musikbiblioteket. EN Tell LMS about any custom contributor role tags used in the music library. For example, SOLOIST, DRUMMER, PRODUCER, etc. Role tag changes will trigger a rescan of your music library. DE Definiere benutzerdefinierte Rollen-Tags, die in der Musikbibliothek verwendet werden. Zum Beispiel SOLOIST, DRUMMER, PRODUCER, usw. Änderungen am Rollentag lösen einen erneuten Scan Ihrer Musikbibliothek aus. @@ -26853,6 +26889,7 @@ SETUP_USERDEFINEDROLES_DESC NL Vertel LMS over alle uitvoerende rollen die je hebt getagged in jouw muziekbibliotheek. Bijvoorbeeld SOLOIST, DRUMMER, PRODUCER, enz. Wijzigingen in de roltag zorgen ervoor dat uw muziekbibliotheek opnieuw wordt gescand. SETUP_USERDEFINEDROLES_TAG + CS Tag role DA Rolle-mærke EN Role tag DE Rollen-Tag @@ -26862,6 +26899,7 @@ SETUP_USERDEFINEDROLES_TAG NL Rol tag SETUP_USERDEFINEDROLES_TEXT + CS Zobrazený text DA Benævnelse EN Display text DE Bezeichnung @@ -26871,6 +26909,7 @@ SETUP_USERDEFINEDROLES_TEXT NL Tekst weergeven SETUP_USERDEFINEDROLES_TEXT_PLURAL + CS Zobrazené texty DA Benævnelser EN Display text (plural) DE Bezeichnung (Plural) @@ -26880,6 +26919,7 @@ SETUP_USERDEFINEDROLES_TEXT_PLURAL NL Tekst weergeven (meervoud) SETUP_WORKSSCAN + CS Prohledávání děl DE Werke suchen EN Works scanning ES Escaneo de obras @@ -26888,6 +26928,7 @@ SETUP_WORKSSCAN NL Scannen van werken SETUP_WORKSSCAN_1 + CS Prohledat celou knihovnu pro díla DE Die gesamte Bibliothek nach Werken durchsuchen EN Scan whole library for works ES Escanea toda la biblioteca en busca de obras @@ -26896,6 +26937,7 @@ SETUP_WORKSSCAN_1 NL Scan de hele bibliotheek op werken SETUP_WORKSSCAN_2 + CS Omezit prohledávání děl na „Moje žánry pro díla a skladatelská alba" (výše) DE Werke auf "Genres für Werke und Komponistenalben" beschränken (oben) EN Limit works scan to "My work and composer album genres" (above) ES Limitar el escaneo de obras a "Mis géneros para las obras y álbumes de compositores" (arriba) @@ -26904,6 +26946,7 @@ SETUP_WORKSSCAN_2 NL Beperk de werkscan tot "Mijn genres voor werken en albums van componisten" (hierboven) SETUP_WORKSSCAN_0 + CS Neskenovat díla DE Nicht nach Werken suchen EN Do not scan for Works ES No buscar obras @@ -26922,6 +26965,7 @@ SETUP_MYCLASSICALGENRES NL Mijn genres voor werken en albums van componisten SETUP_MYCLASSICALGENRES_DESC + CS Použít tyto žánry pro díla a alba skladatelů. Oddělte čárkami. DE Diese Genres für Werke und Komponistenalben verwenden (Komma getrennte Liste). EN Use these genres for works and composer albums. Separate with commas. ES Utiliza estos géneros para obras y álbumes de compositores. Separe con comas. @@ -26930,6 +26974,7 @@ SETUP_MYCLASSICALGENRES_DESC NL Gebruik deze genres voor werken en albums van componisten. Scheid met komma's. FIRST_N_ALBUMS + CS (prvních %s alb) DE (erste %s Alben) EN (first %s albums) ES (primeros %s álbumes) From 489f2a10317a0cf9bf1638f4360e340c6abf35ed Mon Sep 17 00:00:00 2001 From: Michael Herger Date: Mon, 10 Nov 2025 06:57:33 +0100 Subject: [PATCH 006/140] Changelog update Signed-off-by: Michael Herger --- Changelog9.html | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog9.html b/Changelog9.html index bf80386bdc2..59320263a74 100644 --- a/Changelog9.html +++ b/Changelog9.html @@ -8,6 +8,7 @@

Version 9.0.4

  • Server Changes:
    • +
    • Updated Czech translation - thanks @mipa87!

    From 5844af9853fb1628b51e33d6a43c60dbb16f3339 Mon Sep 17 00:00:00 2001 From: Michael Herger Date: Thu, 13 Nov 2025 09:27:11 +0100 Subject: [PATCH 007/140] It doesn't make sense to cache playcount and most recently played, as those lists change too often. Signed-off-by: Michael Herger --- Slim/Control/Queries.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Slim/Control/Queries.pm b/Slim/Control/Queries.pm index 937cc78abfd..8aaa5904ffc 100644 --- a/Slim/Control/Queries.pm +++ b/Slim/Control/Queries.pm @@ -419,9 +419,11 @@ sub albumsQuery { $order_by = 'MIN(tracks_persistent.added) DESC'; } elsif ($sort eq 'playcount') { + $ignoreNewAlbumsCache = 1; $order_by = 'albums_playcount DESC'; } elsif ($sort eq 'recentlyplayed') { + $ignoreNewAlbumsCache = 1; $order_by = 'MAX(tracks_persistent.lastplayed) DESC'; } } @@ -696,7 +698,7 @@ sub albumsQuery { # Get count of all results, the count is cached until the next rescan done event my $cacheKey = _buildCacheKey($sql, $p, $search, $client); - if ( $sort =~ /^(?:new|changed|playcount|recentlyplayed)$/ && $cache->{$newAlbumsCacheKey} && !$ignoreNewAlbumsCache ) { + if ( !$ignoreNewAlbumsCache && $sort =~ /^(?:new|changed|playcount|recentlyplayed)$/ && $cache->{$newAlbumsCacheKey} ) { my $albumCount = scalar @{$cache->{$newAlbumsCacheKey}}; $albumCount = $limit if ($limit && $limit < $albumCount); $cache->{$cacheKey} ||= $albumCount; From 3a0ad97bd9721328551ccda0d12465e6a51fed14 Mon Sep 17 00:00:00 2001 From: Michael Herger Date: Thu, 13 Nov 2025 20:01:21 +0100 Subject: [PATCH 008/140] Update `Proc::Background` Signed-off-by: Michael Herger --- CPAN/Proc/Background.pm | 661 ++++++++++++++++++++++++---------- CPAN/Proc/Background/Unix.pm | 239 +++++++++--- CPAN/Proc/Background/Win32.pm | 336 +++++++++++------ modules.conf | 1 - 4 files changed, 871 insertions(+), 366 deletions(-) diff --git a/CPAN/Proc/Background.pm b/CPAN/Proc/Background.pm index 75c7d32e2d8..e43c38747cb 100644 --- a/CPAN/Proc/Background.pm +++ b/CPAN/Proc/Background.pm @@ -1,23 +1,19 @@ -# Proc::Background: Generic interface to background process management. -# -# Copyright (C) 1998-2002 Blair Zajac. All rights reserved. - package Proc::Background; +# ABSTRACT: Generic interface to Unix and Win32 background process management require 5.004_04; use strict; use Exporter; use Carp; use Cwd; - -use vars qw(@ISA $VERSION @EXPORT_OK); -@ISA = qw(Exporter); -@EXPORT_OK = qw(timeout_system); -$VERSION = sprintf '%d.%02d', '$Revision: 1.08 $' =~ /(\d+)\.(\d+)/; +use Scalar::Util; +@Proc::Background::ISA = qw(Exporter); +@Proc::Background::EXPORT_OK = qw(timeout_system); # Determine if the operating system is Windows. my $is_windows = $^O eq 'MSWin32'; +my $weaken_subref = Scalar::Util->can('weaken'); # Set up a regular expression that tests if the path is absolute and # if it has a directory separator in it. Also create a list of file @@ -25,24 +21,27 @@ my $is_windows = $^O eq 'MSWin32'; # executable. my $is_absolute_re; my $has_dir_element_re; +my $path_sep; my @extensions = (''); if ($is_windows) { $is_absolute_re = '^(?:(?:[a-zA-Z]:[\\\\/])|(?:[\\\\/]{2}\w+[\\\\/]))'; $has_dir_element_re = "[\\\\/]"; + $path_sep = "\\"; push(@extensions, '.exe'); } else { $is_absolute_re = "^/"; $has_dir_element_re = "/"; + $path_sep = "/"; } # Make this class a subclass of Proc::Win32 or Proc::Unix. Any # unresolved method calls will go to either of these classes. if ($is_windows) { require Proc::Background::Win32; - unshift(@ISA, 'Proc::Background::Win32'); + unshift(@Proc::Background::ISA, 'Proc::Background::Win32'); } else { require Proc::Background::Unix; - unshift(@ISA, 'Proc::Background::Unix'); + unshift(@Proc::Background::ISA, 'Proc::Background::Unix'); } # Take either a relative or absolute path to a command and make it an @@ -50,7 +49,7 @@ if ($is_windows) { sub _resolve_path { my $command = shift; - return unless length $command; + return ( undef, 'empty command string' ) unless length $command; # Make the path to the progam absolute if it isn't already. If the # path is not absolute and if the path contains a directory element @@ -67,13 +66,11 @@ sub _resolve_path { last; } } - unless (defined $path) { - warn "$0: no executable program located at $command\n"; - } + return defined $path? ( $path, undef ) : ( undef, "no executable program located at $command" ); } else { my $cwd = cwd; if ($command =~ /$has_dir_element_re/o) { - my $p1 = "$cwd/$command"; + my $p1 = "$cwd$path_sep$command"; foreach my $ext (@extensions) { my $p2 = "$p1$ext"; if (-f $p2 and -x _) { @@ -84,8 +81,8 @@ sub _resolve_path { } else { foreach my $dir (split($is_windows ? ';' : ':', $ENV{PATH})) { next unless length $dir; - $dir = "$cwd/$dir" unless $dir =~ /$is_absolute_re/o; - my $p1 = "$dir/$command"; + $dir = "$cwd$path_sep$dir" unless $dir =~ /$is_absolute_re/o; + my $p1 = "$dir$path_sep$command"; foreach my $ext (@extensions) { my $p2 = "$p1$ext"; if (-f $p2 and -x _) { @@ -96,12 +93,20 @@ sub _resolve_path { last if defined $path; } } - unless (defined $path) { - warn "$0: cannot find absolute location of $command\n"; - } + return defined $path? ( $path, undef ) : ( undef, "cannot find absolute location of $command" ); } +} - $path; +# Define the set of allowed options, to warn about unknown ones. +# Make it a method so subclasses can override it. +%Proc::Background::_available_options= ( + autodie => 1, command => 1, exe => 1, + cwd => 1, stdin => 1, stdout => 1, stderr => 1, + autoterminate => 1, die_upon_destroy => 1, +); + +sub _available_options { + return \%Proc::Background::_available_options; } # We want the created object to live in Proc::Background instead of @@ -109,46 +114,123 @@ sub _resolve_path { sub new { my $class = shift; + # The parameters are an optional %options hashref followed by any number + # of arguments to become the @argv for exec(). If options are given, check + # the keys for typos. my $options; - if (@_ and defined $_[0] and UNIVERSAL::isa($_[0], 'HASH')) { - $options = shift; + if (@_ and ref $_[0] eq 'HASH') { + $options= shift; + my $known= $class->_available_options; + my @unknown= grep !$known->{$_}, keys %$options; + carp "Unknown options: ".join(', ', @unknown) + if @unknown; + } + else { + $options= {}; } - unless (@_ > 0) { - confess "Proc::Background::new called with insufficient number of arguments"; + my $self= bless {}, $class; + $self->{_autodie}= 1 if $options->{autodie}; + + # Resolve any confusion between the 'command' option and positional @argv params. + # Store the command in $self->{_command} so that the ::Unix and ::Win32 don't have + # to deal with it redundantly. + my $cmd= $options->{command}; + if (defined $cmd) { + croak "Can't use both 'command' option and command argument list" + if @_; + # Can be an arrayref or a single string + croak "command must be a non-empty string or an arrayref of strings" + unless (ref $cmd eq 'ARRAY' && defined $cmd->[0] && length $cmd->[0]) + or (!ref $cmd && defined $cmd && length $cmd); + } + else { + # Back-compat: maintain original API quirks + confess "Proc::Background::new called with insufficient number of arguments" + unless @_; + return $self->_fatal('command is undefined') unless defined $_[0]; + + # Interpret the parameters as an @argv if there is more than one, + # or if the 'exe' option was given. + $cmd= (@_ > 1 || defined $options->{exe})? [ @_ ] : $_[0]; } - return unless defined $_[0]; + $self->{_command}= $cmd; + $self->{_exe}= $options->{exe} if defined $options->{exe}; - my $self = $class->SUPER::_new(@_) or return; + # Also back-compat: failing to fork or CreateProcess returns undef + return unless $self->_start($options); - # Save the start time of the class. + # Save the start time $self->{_start_time} = time; - # Handle the specific options. - if ($options) { - $self->{_die_upon_destroy} = $options->{die_upon_destroy}; + if ($options->{autoterminate} || $options->{die_upon_destroy}) { + $self->autoterminate(1); } - bless $self, $class; + return $self; +} + +# The original API returns undef from the constructor in case of various errors. +# The autodie option converts these undefs into exceptions. +sub _fatal { + my ($self, $message)= @_; + croak $message if $self->{_autodie}; + warn "$0: $message"; + return undef; +} + +sub autoterminate { + my ($self, $newval)= @_; + if (@_ > 1 and ($newval xor $self->{_die_upon_destroy})) { + if ($newval) { + # Global destruction can break this feature, because there are no guarantees + # on which order object destructors are called. In order to avoid that, need + # to run all the ->die methods during END{}, and that requires weak + # references which weren't available until 5.8 + $weaken_subref->( $Proc::Background::_die_upon_destroy{$self+0}= $self ) + if $weaken_subref; + # could warn about it for earlier perl... but has been broken for 15 years and + # who is still using < 5.8 anyway? + } + else { + delete $Proc::Background::_die_upon_destroy{$self+0}; + } + $self->{_die_upon_destroy}= $newval? 1 : 0; + } + $self->{_die_upon_destroy} || 0 } sub DESTROY { my $self = shift; if ($self->{_die_upon_destroy}) { - $self->die; + # During a mainline exit() $? is the prospective exit code from the + # parent program. Preserve it across any waitpid() in die() + local $?; + $self->terminate; + delete $Proc::Background::_die_upon_destroy{$self+0}; + } +} + +END { + # Child processes need killed before global destruction, else the + # Win32::Process objects might get destroyed first. + for (grep defined, values %Proc::Background::_die_upon_destroy) { + $_->terminate; + delete $_->{_die_upon_destroy} } + %Proc::Background::_die_upon_destroy= (); } -# Reap the child. If the first argument is 0 the wait should return -# immediately, 1 if it should wait forever. If this number is -# non-zero, then wait. If the wait was sucessful, then delete +# Reap the child. If the first argument is false, then return immediately. +# Else, block waiting for the process to exit. If no second argument is +# given, wait forever, else wait for that number of seconds. +# If the wait was sucessful, then delete # $self->{_os_obj} and set $self->{_exit_value} to the OS specific # class return of _reap. Return 1 if we sucessfully waited, 0 # otherwise. sub _reap { - my $self = shift; - my $timeout = shift || 0; + my ($self, $blocking, $wait_seconds) = @_; return 0 unless exists($self->{_os_obj}); @@ -156,9 +238,9 @@ sub _reap { # the Proc::Background::*::waitpid call, which returns one of three # values. # (0, exit_value) : sucessfully waited on. - # (1, undef) : process already reaped and exist value lost. + # (1, undef) : process already reaped and exit value lost. # (2, undef) : process still running. - my ($result, $exit_value) = $self->_waitpid($timeout); + my ($result, $exit_value) = $self->_waitpid($blocking, $wait_seconds); if ($result == 0 or $result == 1) { $self->{_exit_value} = defined($exit_value) ? $exit_value : 0; delete $self->{_os_obj}; @@ -183,39 +265,79 @@ sub alive { !$self->_reap(0); } -sub wait { - my $self = shift; +sub suspended { + $_[0]->{_suspended}? 1 : 0 +} - # If neither _os_obj or _exit_value are set, then something is wrong. - if (!exists($self->{_exit_value}) and !exists($self->{_os_obj})) { - return; - } +sub suspend { + my $self= shift; + return $self->_fatal("can't suspend, process has exited") + if !$self->{_os_obj}; + $self->{_suspended} = 1 if $self->_suspend; + return $self->{_suspended}; +} + +sub resume { + my $self= shift; + return $self->_fatal("can't resume, process has exited") + if !$self->{_os_obj}; + $self->{_suspended} = 0 if $self->_resume; + return !$self->{_suspended}; +} + +sub wait { + my ($self, $timeout_seconds) = @_; # If $self->{_exit_value} exists, then we already waited. return $self->{_exit_value} if exists($self->{_exit_value}); - # Otherwise, wait forever for the process to finish. - $self->_reap(1); - return $self->{_exit_value}; + carp "calling ->wait on a suspended process" if $self->{_suspended}; + + # If neither _os_obj or _exit_value are set, then something is wrong. + return undef if !exists($self->{_os_obj}); + + # Otherwise, wait for the process to finish. + return $self->_reap(1, $timeout_seconds)? $self->{_exit_value} : undef; } +sub terminate { shift->die(@_) } sub die { my $self = shift; + croak "process is already terminated" if $self->{_autodie} && !$self->{_os_obj}; + # See if the process has already died. return 1 unless $self->alive; # Kill the process using the OS specific method. - $self->_die; + $self->_terminate(@_? ([ @_ ]) : ()); # See if the process is still alive. !$self->alive; } +sub command { + $_[0]->{_command}; +} + +sub exe { + $_[0]->{_exe} +} + sub start_time { $_[0]->{_start_time}; } +sub exit_code { + return undef unless exists $_[0]->{_exit_value}; + return $_[0]->{_exit_value} >> 8; +} + +sub exit_signal { + return undef unless exists $_[0]->{_exit_value}; + return $_[0]->{_exit_value} & 127; +} + sub end_time { $_[0]->{_end_time}; } @@ -236,14 +358,22 @@ sub timeout_system { my $proc = Proc::Background->new(@_) or return; my $end_time = $proc->start_time + $timeout; - while ($proc->alive and time < $end_time) { - sleep(1); + my $delay= $timeout; + while ($delay > 0 && defined $proc->{_os_obj}) { + last if defined $proc->wait($delay); + # If it times out, it's likely that wait() already waited the entire duration. + # But, if it got interrupted, there might be time remaining. + # But, if the system clock changes, this could break horribly. Constrain it to a sane value. + my $t= time; + if ($t < $end_time - $delay) { # time moved backward! + $end_time= $t + $delay; + } else { + $delay= $end_time - $t; + } } my $alive = $proc->alive; - if ($alive) { - $proc->die; - } + $proc->terminate if $alive; if (wantarray) { return ($proc->wait, $alive); @@ -258,29 +388,38 @@ __END__ =pod -=head1 NAME - -Proc::Background - Generic interface to Unix and Win32 background process management - =head1 SYNOPSIS - use Proc::Background; - timeout_system($seconds, $command, $arg1); - timeout_system($seconds, "$command $arg1"); - - my $proc1 = Proc::Background->new($command, $arg1, $arg2); - my $proc2 = Proc::Background->new("$command $arg1 1>&2"); - $proc1->alive; - $proc1->die; + use Proc::Background 'timeout_system'; + timeout_system($seconds, $command, $arg1, $arg2); + timeout_system($seconds, "$command $arg1 $arg2"); + + my $proc1 = Proc::Background->new($command, $arg1, $arg2) || die "failed"; + my $proc2 = Proc::Background->new("$command $arg1 1>&2") || die "failed"; + if ($proc1->alive) { + $proc1->terminate; $proc1->wait; - my $time1 = $proc1->start_time; - my $time2 = $proc1->end_time; - - # Add an option to kill the process with die when the variable is - # DETROYed. - my $opts = {'die_upon_destroy' => 1}; - my $proc3 = Proc::Background->new($opts, $command, $arg1, $arg2); - $proc3 = undef; + } + say 'Ran for ' . ($proc1->end_time - $proc1->start_time) . ' seconds'; + + Proc::Background->new({ + autodie => 1, # Throw exceptions instead of returning undef + cwd => 'some/path/', # Set working directory for the new process + exe => 'busybox', # Specify executable different from argv[0] + command => [ $command ] # resolve ambiguity of command line vs. argv[0] + }); + + # Set initial file handles + Proc::Background->new({ + stdin => undef, # /dev/null or NUL + stdout => '/append/to/fname', # will try to open() + stderr => $log_fh, # use existing handle + command => \@command, + }); + + # Automatically kill the process if the object gets destroyed + my $proc4 = Proc::Background->new({ autoterminate => 1 }, $command); + $proc4 = undef; # calls ->terminate =head1 DESCRIPTION @@ -288,7 +427,7 @@ This is a generic interface for placing processes in the background on both Unix and Win32 platforms. This module lets you start, kill, wait on, retrieve exit values, and see if background processes still exist. -=head1 METHODS +=head1 CONSTRUCTOR =over 4 @@ -296,67 +435,114 @@ on, retrieve exit values, and see if background processes still exist. =item B [options] 'I [I [I ...]]' -This creates a new background process. As exec() or system() may be -passed an array with a single single string element containing a -command to be passed to the shell or an array with more than one -element to be run without calling the shell, B has the same -behavior. - -In certain cases B will attempt to find I on the system -and fail if it cannot be found. - -For Win32 operating systems: - - The Win32::Process module is always used to spawn background - processes on the Win32 platform. This module always takes a - single string argument containing the executable's name and - any option arguments. In addition, it requires that the - absolute path to the executable is also passed to it. If - only a single argument is passed to new, then it is split on - whitespace into an array and the first element of the split - array is used at the executable's name. If multiple - arguments are passed to new, then the first element is used - as the executable's name. - - If the executable's name is an absolute path, then new - checks to see if the executable exists in the given location - or fails otherwise. If the executable's name is not - absolute, then the executable is searched for using the PATH - environmental variable. The input executable name is always - replaced with the absolute path determined by this process. - - In addition, when searching for the executable, the - executable is searched for using the unchanged executable - name and if that is not found, then it is checked by - appending `.exe' to the name in case the name was passed - without the `.exe' suffix. - - Finally, the argument array is placed back into a single - string and passed to Win32::Process::Create. - -For non-Win32 operating systems, such as Unix: - - If more than one argument is passed to new, then new - assumes that the command will not be passed through the - shell and the first argument is the executable's relative - or absolute path. If the first argument is an absolute - path, then it is checked to see if it exists and can be - run, otherwise new fails. If the path is not absolute, - then the PATH environmental variable is checked to see if - the executable can be found. If the executable cannot be - found, then new fails. These steps are taking to prevent - exec() from failing after an fork() without the caller of - new knowing that something failed. - -The first argument to B I may be a reference to a hash -which contains key/value pairs to modify Proc::Background's behavior. -Currently the only key understood by B is I. -When this value is set to true, then when the Proc::Background object -is being DESTROY'ed for any reason (i.e. the variable goes out of -scope) the process is killed via the die() method. - -If anything fails, then new returns an empty list in a list context, -an undefined value in a scalar context, or nothing in a void context. +This creates a new background process. Just like C, you can +supply a single string of the entire command line, or individual +arguments. The first argument may be a hashref of named options. +To resolve the ambiguity between a command line vs. a single-element +argument list, see the C option below. + +By default, the constructor returns an empty list on failure, +except for a few cases of invalid arguments which call C. + +For platform-specific details, see L +or L, but in short: + +=over 7 + +=item Unix + +This implementation uses C/C. If you supply a single-string +command line, it is passed to the shell. If you supply multiple arguments, +they are passed to C. In the multi-argument case, it will also check +that the executable exists before calling C. + +=item Win32 + +This implementation uses the L. +If you supply a single-string command line, it derives the executable by +parsing the command line and looking for the first element in the C, +appending C<".exe"> if needed. If you supply multiple arguments, the +first is used as the C and the command line is built using +L. To let Windows search for the executable, pass option +C<< { exe => undef } >>. + +=back + +B + +=over + +=item C + +This module traditionally has returned C if the child could not +be started. Modern Perl recommends the use of exceptions for things +like this. This option, like Perl's L pragma, causes all +fatal errors in starting the process to die with exceptions instead of +returning undef. (module-usage errors or other problems prior to +launching the process may still 'croak' regardless of this setting) + +=item C + +You may specify the command as an option instead of passing the command +as a list. A string value is considered a command line, and an arrayref +value is considered an argument list. Using this option resolves the +ambiguity in the plain-list constructor between a command line vs. +a single-element argument list. + +=item C + +Specify the executable. This can serve two purposes: +on Win32 it avoids the need to parse the commandline, and on Unix it can be +used to run an executable while passing a different value for C<$ARGV[0]>. + +=item C, C, C + +Specify one or more overrides for the standard handles of the child. +The value should be a Perl filehandle with an underlying system C +value. As a convenience, you can pass C to open the C device +on Win32 or C on Unix. You may also pass a plain-scalar file +name which this module will attmept to open for reading or appending. + +(for anything more elaborate, see L instead) + +Note that on Win32, none of the parent's handles are inherited by default, +which is the opposite on Unix. When you specify any of these handles on +Win32 the default will change to inherit the rest from the parent. + +=item C + +Specify a path which should become the child process's current working +directory. The path must already exist. + +=item C + +If you pass a true value for this option, then destruction of the +Proc::Background object (going out of scope, or script-end) will kill the +process via C<< ->terminate >>. Without this option, the child process +continues running. C is an alias for this option, used +by previous versions of this module. + +=back + +=back + +=head1 ATTRIBUTES + +=over + +=item B + +The command (string or arrayref) that was passed to the constructor. + +=item B + +The path to the executable that was passed as an option to the constructor, +or derived from the C. + +=item B + +Return the value that the Perl function time() returned when the +process was started. =item B @@ -365,36 +551,103 @@ even if the process has already finished. =item B -Return 1 if the process is still active, 0 otherwise. +Return 1 if the process is still active, 0 otherwise. This makes a +non-blocking call to C to check the real status of the process if it +has not been reaped yet. -=item B +=item B -Reliably try to kill the process. Returns 1 if the process no longer -exists once B has completed, 0 otherwise. This will also return -1 if the process has already died. On Unix, the following signals are -sent to the process in one second intervals until the process dies: -HUP, QUIT, INT, KILL. +Boolean whether the process is thought to be stopped. This does not actually +consult the operating system, and just returns the last known status from a +call to C or C. It is always false if C is false. + +=item B + +Returns the exit code of the process, assuming it exited cleanly. +Returns C if the process has not exited yet, and 0 if the +process exited with a signal (or TerminateProcess). Since 0 is +ambiguous, check for C first. + +=item B + +Returns the value of the signal the process exited with, assuming it +died on a signal. Returns C if it has not exited yet, and 0 +if it did not die to a signal. + +=item B + +Return the value that the Perl function time() returned when the exit +status was obtained from the process. + +=item B + +This writeable attribute lets you enable or disable the autoterminate +option, which could also be passed to the constructor. + +=back + +=head1 METHODS + +=over =item B + $exit= $proc->wait; # blocks forever + $exit= $proc->wait($timeout_seconds); # since version 1.20 + Wait for the process to exit. Return the exit status of the command as returned by wait() on the system. To get the actual exit value, divide by 256 or right bit shift by 8, regardless of the operating -system being used. If the process never existed, then return an empty -list in a list context, an undefined value in a scalar context, or -nothing in a void context. This function may be called multiple times -even after the process has exited and it will return the same exit -status. +system being used. If the process never existed, this returns undef. +This function may be called multiple times even after the process has +exited and it will return the same exit status. -=item B +Since version 1.20, you may pass an optional argument of the number of +seconds to wait for the process to exit. This may be fractional, and +if it is zero then the wait will be non-blocking. Note that on Unix +this is implemented with L before a call to wait(), +so it may not be compatible with scripts that use alarm() for other +purposes, or systems/perls that resume system calls after a signal. +In the event of a timeout, the return will be undef. -Return the value that the Perl function time() returned when the -process was started. +=item B -=item B +Pause the process. This returns true if the process is stopped afterward. +This throws an excetion if the process is not C and C is +enabled. -Return the value that the Perl function time() returned when the exit -status was obtained from the process. +=item B + +Resume a paused process. This returns true if the process is not stopped +afterward. This throws an exception if the process is not C and +C is enabled. + +=item B, B + +Reliably try to kill the process. Returns 1 if the process no longer +exists once B has completed, 0 otherwise. This will also return +1 if the process has already exited. + +C<@kill_sequence> is a list of actions and seconds-to-wait for that +action to end the process. The default is C< TERM 2 TERM 8 KILL 3 KILL 7 >. +On Unix this sends SIGTERM and SIGKILL; on Windows it just calls +TerminateProcess (graceful termination is still a TODO). + +Note that C (formerly named C) on Proc::Background 1.10 +and earlier on Unix called a sequence of: + + ->die( ( HUP => 1 )x5, ( QUIT => 1 )x5, ( INT => 1 )x5, ( KILL => 1 )x5 ); + +which wasn't what most people need, since SIGHUP is open to interpretation, +and QUIT is almost always immediately fatal and generates a coredump. +The new default should accomodate programs that acknowledge a second +SIGTERM, and give enough time for it to exit on a laggy system while still +not holding up the main script too much. + +C is preserved as an alias for C. + +This throws an exception if the process has been reaped and C is +enabled. =back @@ -407,12 +660,7 @@ status was obtained from the process. =item B 'I I [I [I...]]' Run a command for I seconds and if the process did not exit, -then kill it. While the timeout is implemented using sleep(), this -function makes sure that the full I is reached before killing -the process. B does not wait for the complete -I number of seconds before checking if the process has -exited. Rather, it sleeps repeatidly for 1 second and checks to see -if the process still exists. +then kill it. In a scalar context, B returns the exit status from the process. In an array context, B returns a two @@ -430,48 +678,63 @@ scalar context, or nothing in a void context. =back -=head1 IMPLEMENTATION - -I comes with two modules, I -and I. Currently, on Unix platforms -I uses the I class and on -Win32 platforms it uses I, which makes use of -I. - -The I assigns to @ISA either -I or I, which does -the OS dependent work. The OS independent work is done in -I. - -Proc::Background uses two variables to keep track of the process. -$self->{_os_obj} contains the operating system object to reference the -process. On a Unix systems this is the process id (pid). On Win32, -it is an object returned from the I class. When -$self->{_os_obj} exists, then the process is running. When the -process dies, this is recorded by deleting $self->{_os_obj} and saving -the exit value $self->{_exit_value}. - -Anytime I is called, a waitpid() is called on the process and -the return status, if any, is gathered and saved for a call to -I. This module does not install a signal handler for SIGCHLD. -If for some reason, the user has installed a signal handler for -SIGCHLD, then, then when this module calls waitpid(), the failure will -be noticed and taken as the exited child, but it won't be able to -gather the exit status. In this case, the exit status will be set to -0. +=head1 BUGS + +The following behaviors aren't ideal, but are preserved for backward-compatibility. + +=over + +=item Commandline vs. Single Argv[] + +C<< ->new($x) >> is treated as a command line. In C<< ->new({ exe => $y }, $x) >>, +$x is treated as C<$ARGV[0]>. Use C<< ->new({ command => ... }) >> +(scalar vs. arrayref) to dis-ambiguate. + +=item Win32 Argv Quoting + +This is a bug in Windows, not this module. It is not possible to universally +convert an @ARGV into a commandline, because each Win32 program performs its +own command line parsing, and cmd.exe and find.exe deviate from the majority +of other executables. Those things could be improved with hieuristics, which +this module doesn't have. + +=item Win32 exe determination + +If you don't specify an absolute path for option C, this module manually +searches the %PATH% looking for the executable, and is less thorough than the +native Windows shell behavior. Use C<< { exe => undef } >> to get the naive +Windows exe search. (but you need Win32::Process version 0.17 or newer) + +=item Win32 SIGTERM + +This module only supports TerminateProcess, which is equivalent to SIGKILL, not +SIGTERM. SIGTERM could be emulated by calling taskkill.exe, or using windows +messages. Patches welcome. + +=back =head1 SEE ALSO -See also L and L. +=over + +=item L -=head1 AUTHOR +IPC::Run is a much more complete solution for running child processes. +It handles dozens of forms of redirection and pipe pumping, and should +probably be your first stop for any complex needs. -Blair Zajac +However, also note the very large and slightly alarming list of +limitations it lists for Win32. Proc::Background is a much simpler design +and should be more reliable for simple needs. -=head1 COPYRIGHT +=item L -Copyright (C) 1998-2002 Blair Zajac. All rights reserved. This -package is free software; you can redistribute it and/or modify it -under the same terms as Perl itself. +If you are running on Win32, this article by Daniel Colascione helps +describe the problem you are up against for passing argument lists: +L -=cut +This module gives you parsing / quoting per the standard +CommandLineToArgvW behavior. But, if you need to pass arguments to be +processed by C then you need to do additional work. + +=back diff --git a/CPAN/Proc/Background/Unix.pm b/CPAN/Proc/Background/Unix.pm index a0f8567f541..344e5f0ffb8 100644 --- a/CPAN/Proc/Background/Unix.pm +++ b/CPAN/Proc/Background/Unix.pm @@ -1,78 +1,185 @@ -# Proc::Background::Unix: Unix interface to background process management. -# -# Copyright (C) 1998-2002 Blair Zajac. All rights reserved. - package Proc::Background::Unix; +# ABSTRACT: Unix-specific implementation of process create/wait/kill require 5.004_04; use strict; use Exporter; use Carp; -use POSIX qw(:errno_h :sys_wait_h); +use POSIX qw( :errno_h :sys_wait_h ); + +# Test for existence of FD_CLOEXEC, needed for child-error-through-pipe trick +my ($FD_CLOEXEC); +eval { + require Fcntl; + $FD_CLOEXEC= Fcntl::FD_CLOEXEC(); +}; -use vars qw(@ISA $VERSION); -@ISA = qw(Exporter); -$VERSION = sprintf '%d.%02d', '$Revision: 1.08 $' =~ /(\d+)\.(\d+)/; +# For un-explained mysterious reasons, Time::HiRes::alarm seem to misbehave on 5.10 and earlier +# but core alarm works fine. +my $alarm= ($] >= 5.012)? do { require Time::HiRes; \&Time::HiRes::alarm; } + : sub { + # round up to whole seconds + CORE::alarm(POSIX::ceil($_[0])); + }; + +@Proc::Background::Unix::ISA = qw(Exporter); # Start the background process. If it is started sucessfully, then record # the process id in $self->{_os_obj}. -sub _new { - my $class = shift; +sub _start { + my ($self, $options)= @_; + + # There are three main scenarios for how-to-exec: + # * single-string command, to be handled by shell + # * arrayref command, to be handled by execve + # * arrayref command with 'exe' (fake argv0) + # and one that isn't logical: + # * single-string command with exe + # throw an error for that last one rather than trying something awkward + # like splitting the command string. - unless (@_ > 0) { - confess "Proc::Background::Unix::_new called with insufficient number of arguments"; + my @argv; + my ($cmd, $exe)= @{$self}{'_command','_exe'}; + + if (ref $cmd eq 'ARRAY') { + @argv= @$cmd; + ($exe, my $err) = Proc::Background::_resolve_path(defined $exe? $exe : $argv[0]); + return $self->_fatal($err) unless defined $exe; + $self->{_exe}= $exe; + } elsif (defined $exe) { + croak "Can't combine 'exe' option with single-string 'command', use arrayref 'command' instead."; } - return unless defined $_[0]; - - # If there is only one element in the @_ array, then it may be a - # command to be passed to the shell and should not be checked, in - # case the command sets environmental variables in the beginning, - # i.e. 'VAR=arg ls -l'. If there is more than one element in the - # array, then check that the first element is a valid executable - # that can be found through the PATH and find the absolute path to - # the executable. If the executable is found, then replace the - # first element it with the absolute path. - my @args = @_; - if (@_ > 1) { - $args[0] = Proc::Background::_resolve_path($args[0]) or return; + if (defined $options->{cwd}) { + -d $options->{cwd} + or return $self->_fatal("directory does not exist: '$options->{cwd}'"); } - my $self = bless {}, $class; + my ($new_stdin, $new_stdout, $new_stderr); + $new_stdin= _resolve_file_handle($options->{stdin}, '<', \*STDIN) + if exists $options->{stdin}; + $new_stdout= _resolve_file_handle($options->{stdout}, '>>', \*STDOUT) + if exists $options->{stdout}; + $new_stderr= _resolve_file_handle($options->{stderr}, '>>', \*STDERR) + if exists $options->{stderr}; # Fork a child process. + my ($pipe_r, $pipe_w); + if (defined $FD_CLOEXEC) { + # use a pipe for the child to report exec() errors + pipe $pipe_r, $pipe_w or return $self->_fatal("pipe: $!"); + # This pipe needs to be in the non-preserved range that doesn't exist after exec(). + # In the edge case where a pipe received a FD less than $^F, the CLOEXEC flag isn't set. + # Try again on higher descriptors, then close the lower ones. + my @rejects; + while (fileno $pipe_r <= $^F or fileno $pipe_w <= $^F) { + push @rejects, $pipe_r, $pipe_w; + pipe $pipe_r, $pipe_w or return $self->_fatal("pipe: $!"); + } + } my $pid; { if ($pid = fork()) { # parent $self->{_os_obj} = $pid; $self->{_pid} = $pid; + if (defined $pipe_r) { + close $pipe_w; + # wait for child to reply or close the pipe + local $SIG{PIPE}= sub {}; + my $msg= ''; + while (0 < read $pipe_r, $msg, 1024, length $msg) {} + close $pipe_r; + # If child wrote anything to the pipe, it failed to exec. + # Reap it before dying. + if (length $msg) { + waitpid $pid, 0; + return $self->_fatal($msg); + } + } last; } elsif (defined $pid) { # child - exec @_ or croak "$0: exec failed: $!\n"; + # Make absolutely sure nothing in this block interacts with the rest of the + # process state, and that flow control never skips the _exit(). + $SIG{$_}= sub{die;} for qw( INT HUP QUIT TERM ); # clear custom signal handlers + $SIG{$_}= 'DEFAULT' for qw( __WARN__ __DIE__ ); + eval { + eval { + chdir($options->{cwd}) or die "chdir($options->{cwd}): $!\n" + if defined $options->{cwd}; + + open STDIN, '<&'.fileno($new_stdin) or die "Can't redirect STDIN: $!\n" + if defined $new_stdin; + open STDOUT, '>&'.fileno($new_stdout) or die "Can't redirect STDOUT: $!\n" + if defined $new_stdout; + open STDERR, '>&'.fileno($new_stderr) or die "Can't redirect STDERR: $!\n" + if defined $new_stderr; + + if (defined $exe) { + exec { $exe } @argv or die "$0: exec failed: $!\n"; + } else { + exec $cmd or die "$0: exec failed: $!\n"; + } + }; + if (defined $pipe_w) { + print $pipe_w $@; + close $pipe_w; # force it to flush. Nothing else needs closed because we are about to _exit + } else { + print STDERR $@; + } + }; + POSIX::_exit(1); } elsif ($! == EAGAIN) { sleep 5; redo; } else { - return; + return $self->_fatal("fork: $!"); } } $self; } +sub _resolve_file_handle { + my ($thing, $mode, $default)= @_; + if (!defined $thing) { + open my $fh, $mode, '/dev/null' or croak "open(/dev/null): $!"; + return $fh; + } elsif (ref $thing) { + # use 'undef' to mean no-change + return (fileno($thing) == fileno($default))? undef : $thing; + } else { + open my $fh, $mode, $thing or croak "open($thing): $!"; + return $fh; + } +} + # Wait for the child. +# (0, exit_value) : sucessfully waited on. +# (1, undef) : process already reaped and exit value lost. +# (2, undef) : process still running. sub _waitpid { - my $self = shift; - my $timeout = shift; + my ($self, $blocking, $wait_seconds) = @_; { # Try to wait on the process. - my $result = waitpid($self->{_os_obj}, $timeout ? 0 : WNOHANG); + # Implement the optional timeout with the 'alarm' call. + my $result= 0; + if ($blocking && $wait_seconds) { + local $SIG{ALRM}= sub { die "alarm\n" }; + $alarm->($wait_seconds); + eval { $result= waitpid($self->{_os_obj}, 0); }; + $alarm->(0); + } + else { + $result= waitpid($self->{_os_obj}, $blocking? 0 : WNOHANG); + } + # Process finished. Grab the exit value. if ($result == $self->{_os_obj}) { + delete $self->{_suspended}; return (0, $?); } # Process already reaped. We don't know the exist status. @@ -89,21 +196,25 @@ sub _waitpid { return 0; } -sub _die { - my $self = shift; +sub _suspend { + kill STOP => $_[0]->{_os_obj}; +} + +sub _resume { + kill CONT => $_[0]->{_os_obj}; +} +sub _terminate { + my $self = shift; + my @kill_sequence= @_ && ref $_[0] eq 'ARRAY'? @{ $_[0] } : qw( TERM 2 TERM 8 KILL 3 KILL 7 ); # Try to kill the process with different signals. Calling alive() will # collect the exit status of the program. - SIGNAL: { - foreach my $signal (qw(HUP QUIT INT KILL)) { - my $count = 5; - while ($count and $self->alive) { - --$count; - kill($signal, $self->{_os_obj}); - last SIGNAL unless $self->alive; - sleep 1; - } - } + while (@kill_sequence and $self->alive) { + my $sig= shift @kill_sequence; + my $delay= shift @kill_sequence; + kill($sig, $self->{_os_obj}); + next unless defined $delay; + last if $self->_reap(1, $delay); # block before sending next signal } } @@ -111,28 +222,42 @@ sub _die { __END__ -=head1 NAME +=head1 DESCRIPTION -Proc::Background::Unix - Unix interface to process mangement +This module does not have a public interface. Use L. -=head1 SYNOPSIS +=head1 IMPLEMENTATION -Do not use this module directly. +=head2 Command vs. Exec -=head1 DESCRIPTION +Unix systems start a new process by creating a mirror of the current process +(C) and then having it alter its own state to prepare for the new +program, and then calling C to replace the running code with code loaded +from a new file. However, there is a second common method where the user +wants to specify a command line string as they would type it in their shell. +In this case, the actual program being executed is the shell, and the command +line is given as one element of its argument list. -This is a process management class designed specifically for Unix -operating systems. It is not meant used except through the -I class. See L for more information. +Perl already supports both methods, such that if you pass one string to C +containing shell characters, it calls the shell, and if you pass multiple +arguments, it directly invokes C. -=head1 AUTHOR +This module mostly just lets Perl's C do its job, but also checks for +the existence of the executable first, to make errors easier to catch. This +check is skipped if there is a single-string command line. -Blair Zajac +Unix lets you run a different executable than what is listed in the first +argument. (this feature lets one Unix executable behave as multiple +different programs depending on what name it sees in the first argument) +You can use that feature by passing separate options of C and C +to this module's constructor instead of a simple argument list. But, you +can't mix a C option with a shell-interpreted command line string. -=head1 COPYRIGHT +=head2 Errors during Exec -Copyright (C) 1998-2002 Blair Zajac. All rights reserved. This -package is free software; you can redistribute it and/or modify it -under the same terms as Perl itself. +If the C option is enabled, and the system supports C, +this module uses a trick where the forked child relays any errors through +a pipe so that the parent can throw and handle the exception directly instead +of creating a child process that is dead-on-arrival with the error on STDERR. =cut diff --git a/CPAN/Proc/Background/Win32.pm b/CPAN/Proc/Background/Win32.pm index 8aa2347df9b..320a34e622e 100644 --- a/CPAN/Proc/Background/Win32.pm +++ b/CPAN/Proc/Background/Win32.pm @@ -1,104 +1,152 @@ -# Proc::Background::Win32 Windows interface to background process management. -# -# Copyright (C) 1998-2002 Blair Zajac. All rights reserved. - package Proc::Background::Win32; +# ABSTRACT: Windows-specific implementation of process create/wait/kill require 5.004_04; use strict; use Exporter; use Carp; +use Win32; +use Win32::Process qw( NORMAL_PRIORITY_CLASS INFINITE ); +use Win32::ShellQuote (); + +@Proc::Background::Win32::ISA = qw(Exporter); + +sub _start { + my ($self, $options)= @_; + my ($cmd, $exe, $cmdline, $err)= @{$self}{'_command','_exe'}; + + # If 'command' is a single string, treat it as system() would and assume + # it should be split into arguments. The first argument is then the + # application executable, if not already specified as an option. + if (ref $cmd ne 'ARRAY') { + $cmdline= $cmd; + ($exe) = Win32::ShellQuote::unquote_native($cmdline) + unless exists $options->{exe}; + } + # system() would treat a list of arguments as an un-quoted ARGV + # for the program, so concatenate them into a command line appropriate + # for Win32 CommandLineToArgvW to decode back to what we started with. + # Preserve the first un-quoted argument for use as lpApplicationName, + # unless user requested some value (including undef). + else { + $exe = $cmd->[0] unless exists $options->{exe}; + $cmdline= Win32::ShellQuote::quote_native(@$cmd); + } -use vars qw(@ISA $VERSION); -@ISA = qw(Exporter); -$VERSION = sprintf '%d.%02d', '$Revision: 1.08 $' =~ /(\d+)\.(\d+)/; - -BEGIN { - eval "use Win32"; - $@ and die "Proc::Background::Win32 needs Win32 from libwin32-?.??.zip to run.\n"; - eval "use Win32::Process"; - $@ and die "Proc::Background::Win32 needs Win32::Process from libwin32-?.??.zip to run.\n"; -} - -sub _new { - my $class = shift; + if (defined $exe) { + # Find the absolute path to the program. If it cannot be found, + # then return. + ($exe, $err) = Proc::Background::_resolve_path($exe); + return $self->_fatal($err) unless defined $exe; + # To work around a problem where Win32::Process::Create cannot start a + # process when the full pathname has a space in it, convert the full + # pathname to the Windows short 8.3 format which contains no spaces. + $exe = Win32::GetShortPathName($exe) + } + else { + Win32::Process->VERSION > 0.16 + or croak "{exe => undef} feature requires Win32::Process 0.17"; + } - unless (@_ > 0) { - confess "Proc::Background::Win32::_new called with insufficient number of arguments"; + my $cwd= '.'; + if (defined $options->{cwd}) { + -d $options->{cwd} + or return $self->_fatal("directory does not exist: '$options->{cwd}'"); + $cwd= $options->{cwd}; } - return unless defined $_[0]; - - # If there is only one element in the @_ array, then just split the - # argument by whitespace. If there is more than one element in @_, - # then assume that each argument should be properly protected from - # the shell so that whitespace and special characters are passed - # properly to the program, just as it would be in a Unix - # environment. This will ensure that a single argument with - # whitespace will not be split into multiple arguments by the time - # the program is run. Make sure that any arguments that are already - # protected stay protected. Then convert unquoted "'s into \"'s. - # Finally, check for whitespace and protect it. - my @args; - if (@_ == 1) { - @args = split(' ', $_[0]); + # On Strawberry Perl, CreateProcess will inherit the current process STDIN/STDOUT/STDERR, + # but there is no way to specify them without altering the current process. + # So, redirect handles, then create process, then revert them. + my ($inherit, $new_stdin, $old_stdin, $new_stdout, $old_stdout, $new_stderr, $old_stderr); + if (exists $options->{stdin}) { + $inherit= 1; + $new_stdin= _resolve_file_handle($options->{stdin}, '<', \*STDIN); + open $old_stdin, '<&'.fileno(\*STDIN) or croak "Can't save STDIN: $!\n" + if defined $new_stdin; + } + if (exists $options->{stdout}) { + $inherit= 1; + $new_stdout= _resolve_file_handle($options->{stdout}, '>>', \*STDOUT); + open $old_stdout, '>&'.fileno(\*STDOUT) or croak "Can't save STDOUT: $!\n" + if defined $new_stdout; + } + if (exists $options->{stderr}) { + $inherit= 1; + $new_stderr= _resolve_file_handle($options->{stderr}, '>>', \*STDERR); + open $old_stderr, '>&'.fileno(\*STDERR) or croak "Can't save STDERR: $!\n" + if defined $new_stderr; + } + + { + local $@; + eval { + open STDIN, '<&'.fileno($new_stdin) or die "Can't redirect STDIN: $!\n" + if defined $new_stdin; + open STDOUT, '>&'.fileno($new_stdout) or die "Can't redirect STDOUT: $!\n" + if defined $new_stdout; + open STDERR, '>&'.fileno($new_stderr) or die "Can't redirect STDERR: $!\n" + if defined $new_stderr; + + # Perl 5.004_04 cannot run Win32::Process::Create on a nonexistant + # hash key. + my $os_obj = 0; + + # Create the process. + Win32::Process::Create($os_obj, $exe, $cmdline, $inherit, NORMAL_PRIORITY_CLASS, $cwd) + or die Win32::FormatMessage( Win32::GetLastError() )."\n"; + $self->{_pid} = $os_obj->GetProcessID; + $self->{_os_obj} = $os_obj; + }; + chomp($err= $@); + # Now restore handles before throwing exception + open STDERR, '>&'.fileno($old_stderr) or warn "Can't restore STDERR: $!\n" + if defined $old_stderr; + open STDOUT, '>&'.fileno($old_stdout) or warn "Can't restore STDOUT: $!\n" + if defined $old_stdout; + open STDIN, '<&'.fileno($old_stdin) or warn "Can't restore STDIN: $!\n" + if defined $old_stdin; + } + if ($self->{_os_obj}) { + return 1; } else { - @args = @_; - for (my $i=1; $i<@args; ++$i) { - my $arg = $args[$i]; - $arg =~ s#\\\\#\200#g; - $arg =~ s#\\"#\201#g; - $arg =~ s#"#\\"#g; - $arg =~ s#\200#\\\\#g; - $arg =~ s#\201#\\"#g; - if (length($arg) == 0 or $arg =~ /\s/) { - $arg = "\"$arg\""; - } - $args[$i] = $arg; - } + return $self->_fatal($err); } +} - # Find the absolute path to the program. If it cannot be found, - # then return. To work around a problem where - # Win32::Process::Create cannot start a process when the full - # pathname has a space in it, convert the full pathname to the - # Windows short 8.3 format which contains no spaces. - $args[0] = Proc::Background::_resolve_path($args[0]) or return; - $args[0] = Win32::GetShortPathName($args[0]); - - my $self = bless {}, $class; - - # Perl 5.004_04 cannot run Win32::Process::Create on a nonexistant - # hash key. - my $os_obj = 0; - - # Create the process. - if (Win32::Process::Create($os_obj, - $args[0], - "@args", - 0, - CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS, - '.')) { - $self->{_pid} = $os_obj->GetProcessID; - $self->{_os_obj} = $os_obj; - return $self; +sub _resolve_file_handle { + my ($thing, $mode, $default)= @_; + if (!defined $thing) { + open my $fh, $mode, 'NUL' or croak "open(NUL): $!"; + return $fh; + } elsif (ref $thing) { + return fileno($thing) == fileno($default)? undef : $thing; } else { - return; + open my $fh, $mode, $thing or croak "open($thing): $!"; + return $fh; } } # Reap the child. +# (0, exit_value) : sucessfully waited on. +# (1, undef) : process already reaped and exit value lost. +# (2, undef) : process still running. sub _waitpid { - my ($self, $timeout) = @_; + my ($self, $blocking, $wait_seconds) = @_; # Try to wait on the process. - my $result = $self->{_os_obj}->Wait($timeout ? INFINITE : 0); + my $result = $self->{_os_obj}->Wait($wait_seconds? int($wait_seconds * 1000) : $blocking ? INFINITE : 0); # Process finished. Grab the exit value. if ($result == 1) { - my $_exit_status; - $self->{_os_obj}->GetExitCode($_exit_status); - return (0, $_exit_status<<8); + delete $self->{_suspended}; + my $exit_code; + $self->{_os_obj}->GetExitCode($exit_code); + if ($exit_code == 256 && $self->{_called_terminateprocess}) { + return (0, 9); # simulate SIGKILL exit status + } else { + return (0, $exit_code<<8); + } } # Process still running. elsif ($result == 0) { @@ -108,50 +156,120 @@ sub _waitpid { return (0, 1<<8); } -sub _die { - my $self = shift; - - # Try the kill the process several times. Calling alive() will - # collect the exit status of the program. - my $count = 5; - while ($count and $self->alive) { - --$count; - $self->{_os_obj}->Kill(1<<8); - last unless $self->alive; - sleep 1; - } +sub _suspend { + $_[0]->{_os_obj}->Suspend(); } -1; +sub _resume { + $_[0]->{_os_obj}->Resume(); +} -__END__ +sub _terminate { + my $self = shift; + my @kill_sequence= @_ && ref $_[0] eq 'ARRAY'? @{ $_[0] } : qw( TERM 2 TERM 8 KILL 3 KILL 7 ); + + # Try the kill the process several times. + # _reap will collect the exit status of the program. + while (@kill_sequence and $self->alive) { + my $sig= shift @kill_sequence; + my $delay= shift @kill_sequence; + # TODO: fix _taskkill, then re-enable: $sig eq 'KILL'? $self->_terminateprocess : $self->_taskkill; + $self->_terminateprocess; + next unless defined $delay; + last if $self->_reap(1, $delay); # block before sending next signal + } +} -=head1 NAME +# Use taskkill.exe as a sort of graceful SIGTERM substitute. +sub _taskkill { + my $self = shift; + # TODO: This doesn't work reliably. Disabled for now, and continue to be heavy-handed + # using TerminateProcess. The right solution would either be to do more elaborate setup + # to make sure the correct taskkill.exe is used (and available), or to dig much deeper + # into Win32 API to enumerate windows or threads and send WM_QUIT, or whatever other APIs + # processes might be watching on Windows. That should probably be its own module. + my $pid= $self->{_pid}; + my $out= `taskkill.exe /PID $pid`; + # If can't run taskkill, fall back to TerminateProcess + $self->_terminateprocess unless $? == 0; +} -Proc::Background::Win32 - Interface to process mangement on Win32 systems +# Win32 equivalent of SIGKILL is TerminateProcess() +sub _terminateprocess { + my $self = shift; + $self->{_os_obj}->Kill(256); # call TerminateProcess, essentially SIGKILL + $self->{_called_terminateprocess} = 1; +} -=head1 SYNOPSIS +1; -Do not use this module directly. +__END__ =head1 DESCRIPTION -This is a process management class designed specifically for Win32 -operating systems. It is not meant used except through the -I class. See L for more information. +This module does not have a public interface. Use L. =head1 IMPLEMENTATION -This package uses the Win32::Process class to manage the objects. - -=head1 AUTHOR - -Blair Zajac and C are +a broken approximation of their Unix counterparts. Calling C creates a +I instead of a process, and there is no way to exit the thread without +running Perl cleanup code, which could damage the parent in unpredictable +ways, like closing file handles. Calling C will kill both +parent and child (the whole process), and even calling C in the child +still runs global destruction. File handles are shared between parent and +child, so any file handle redirection you perform in the forked child will +affect the parent and vice versa. + +In short, B call C or C on native Win32 Perl. + +=head2 Command Line + +This module implements background processes using L, which +uses the Windows API's concepts of C, C, +C, C, and so on. + +Windows CreateProcess expects an executable name and a command line; breaking +the command line into an argument list is left to each individual application, +most of which use the library function L. This module +uses L to parse and format Windows command lines. + +If you supply a single-string command line, and don't specify the executable +with the C option, this module parses the first argument from the +command line to be the 'exe' option. It then looks for the 'exe' in +C<< $ENV{PATH} >>, and tries again with a suffix of C<< .exe >> if it didn't +find one. If you specify the option as C<< { exe => undef } >>, this module +skips that step and passes NULL to Win32 C, which causes +Windows to parse the first argument and find the executable on its own. +(Letting Windows search for the executable is probably a better idea anyway, +and this might become the default in the future. It only works with +Win32::Process 0.17 or later) + +If you supply an array of arguments as the command, this module combines them +into a command line using C. The first +argument is used as the executable (unless you specified the C<'exe'> option, +like above). + +=head2 Initial File Handles + +When B are specified, the new process does B +of the current process. This differs from the Unix implementation where they are all +inherited by default, but I'm leaving it this way for backward compatibility. +In other words, yes, they ought to be inherited by default, but changing that now +is more likely to break things than fix things. + +If you specify B of C, C, or C, any handle not +specified B as-is. In other words, by indicating you are +interested in passing file handles, the default Unix behavior occurs. +If you wish to redirect a handle to NUL, set the option to C: + + stdin => undef, # stdin will read from NUL device + stdout => $some_fh, # stdout will write to a file handle + stderr => \*STDERR, # stderr will go to the same STDERR of the current process + +You may set a file handle to a pipe, but beware, Windows does not support +non-blocking reads or writes to pipes. =cut diff --git a/modules.conf b/modules.conf index e08ea8160a8..07825b9870b 100644 --- a/modules.conf +++ b/modules.conf @@ -25,7 +25,6 @@ JSON::XS 2.3 JSON::XS::VersionOneAndTwo 0.31 Log::Log4perl 1.23 Path::Class 0.17 -Proc::Background 1.08 SQL::Abstract 1.56 Sub::Name 0.05 Text::Unidecode 0.04 From f2e60e1337b81d944e131746c5a2336eaccfa0b3 Mon Sep 17 00:00:00 2001 From: Martin Williams Date: Fri, 14 Nov 2025 15:37:41 +0000 Subject: [PATCH 009/140] Fix Squeezeplay Playlist icons - Move from 'Default' to 'EN' skin hierarchies This change moves playlist related images from the 'Default skin' hierarchy to the generic fallback 'EN' hierarchy. They are used to generate Squeezeplay icons. At present, they will not be found, and icons will not be generated, unless the user is using the 'Default' skin. Moving to 'EN' ensures they will be found, and icons generated, regardless of the skin in use. The change also removes the 'cover.png' and 'radio.png' images from the 'Default' hierarchy. They are identical to those found in the 'EN' hierarchy, and serve no useful purpose. (They did once differ, but were made identical in LMS v7.4 - circa 2009). Signed-off-by: Martin Williams --- HTML/Default/html/images/cover.png | Bin 28688 -> 0 bytes HTML/Default/html/images/radio.png | Bin 43400 -> 0 bytes HTML/{Default => EN}/html/images/blank.png | Bin HTML/{Default => EN}/html/images/playlist.png | Bin .../{Default => EN}/html/images/playlistadd.png | Bin .../html/images/playlistclear.png | Bin .../html/images/playlistclear_40x40_m.png | Bin .../html/images/playlistedit.png | Bin .../html/images/playlistsave.png | Bin .../html/images/playlistsave_40x40_m.png | Bin 10 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 HTML/Default/html/images/cover.png delete mode 100644 HTML/Default/html/images/radio.png rename HTML/{Default => EN}/html/images/blank.png (100%) rename HTML/{Default => EN}/html/images/playlist.png (100%) rename HTML/{Default => EN}/html/images/playlistadd.png (100%) rename HTML/{Default => EN}/html/images/playlistclear.png (100%) rename HTML/{Default => EN}/html/images/playlistclear_40x40_m.png (100%) rename HTML/{Default => EN}/html/images/playlistedit.png (100%) rename HTML/{Default => EN}/html/images/playlistsave.png (100%) rename HTML/{Default => EN}/html/images/playlistsave_40x40_m.png (100%) diff --git a/HTML/Default/html/images/cover.png b/HTML/Default/html/images/cover.png deleted file mode 100644 index 4c363f3f0586eecba494a733b1c498a267a5d37c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28688 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 UxMRy+bENZfa%8h|9JWUP1AM4XcK`qY diff --git a/HTML/Default/html/images/blank.png b/HTML/EN/html/images/blank.png similarity index 100% rename from HTML/Default/html/images/blank.png rename to HTML/EN/html/images/blank.png diff --git a/HTML/Default/html/images/playlist.png b/HTML/EN/html/images/playlist.png similarity index 100% rename from HTML/Default/html/images/playlist.png rename to HTML/EN/html/images/playlist.png diff --git a/HTML/Default/html/images/playlistadd.png b/HTML/EN/html/images/playlistadd.png similarity index 100% rename from HTML/Default/html/images/playlistadd.png rename to HTML/EN/html/images/playlistadd.png diff --git a/HTML/Default/html/images/playlistclear.png b/HTML/EN/html/images/playlistclear.png similarity index 100% rename from HTML/Default/html/images/playlistclear.png rename to HTML/EN/html/images/playlistclear.png diff --git a/HTML/Default/html/images/playlistclear_40x40_m.png b/HTML/EN/html/images/playlistclear_40x40_m.png similarity index 100% rename from HTML/Default/html/images/playlistclear_40x40_m.png rename to HTML/EN/html/images/playlistclear_40x40_m.png diff --git a/HTML/Default/html/images/playlistedit.png b/HTML/EN/html/images/playlistedit.png similarity index 100% rename from HTML/Default/html/images/playlistedit.png rename to HTML/EN/html/images/playlistedit.png diff --git a/HTML/Default/html/images/playlistsave.png b/HTML/EN/html/images/playlistsave.png similarity index 100% rename from HTML/Default/html/images/playlistsave.png rename to HTML/EN/html/images/playlistsave.png diff --git a/HTML/Default/html/images/playlistsave_40x40_m.png b/HTML/EN/html/images/playlistsave_40x40_m.png similarity index 100% rename from HTML/Default/html/images/playlistsave_40x40_m.png rename to HTML/EN/html/images/playlistsave_40x40_m.png From 566fbf4afc1c502d01a420c3307c9f55331d70c5 Mon Sep 17 00:00:00 2001 From: Michael Herger Date: Mon, 17 Nov 2025 09:18:15 +0100 Subject: [PATCH 010/140] Changelog update. Signed-off-by: Michael Herger --- Changelog9.html | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog9.html b/Changelog9.html index dcce5e4d223..5cead544cf7 100644 --- a/Changelog9.html +++ b/Changelog9.html @@ -51,6 +51,7 @@

    Version 9.1.0

  • Upgrade DBD::SQLite to v1.75 for Perl 5.40 (Linux x86_64, aarch64), 5.38 (Linux x86_64), 5.36 (Linux x86_64, aarch64, armv7), 5.34 (Linux x86_64, aarch64; macOS), 5.32 (Linux x86_64, aarch64, armv7).
  • #73 - Add a note about setting the hostname in a Docker container (thanks @hartzell!)
  • #86 - Add more tags to Docker images to better support automated updates (thanks @stavros-k!)
  • +
  • #101 - Add package opus-tools to docker image (thanks @terual!)

  • From 7cdb0d46c973166cb51a856f300d3ef4bb410d64 Mon Sep 17 00:00:00 2001 From: Michael Herger Date: Mon, 17 Nov 2025 14:46:38 +0100 Subject: [PATCH 011/140] Some users of `Async::Util::amap()` might call the callback twice - ignore second call! Signed-off-by: Michael Herger --- lib/Async/Util.pm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Async/Util.pm b/lib/Async/Util.pm index 0ef4b734003..08d70868b61 100644 --- a/lib/Async/Util.pm +++ b/lib/Async/Util.pm @@ -71,6 +71,9 @@ sub _amap { $after_work = sub { my ($output, $err, $index) = @_; + # prevent handling the same output twice - some misbehaving actions might call us twice! + return if defined $outputs->[$index]; + $cb_count++; $inflight--; From 9e331ee9069fea63b4bee370a3e1101335970374 Mon Sep 17 00:00:00 2001 From: LMSSonos Date: Wed, 19 Nov 2025 09:09:29 +0000 Subject: [PATCH 012/140] Add devcontainer configuration with Dockerfile and docker-compose setup This allows autmatic dev setup in vscode when checking out the repo After checkout, just run `perl slimserverl.pl` to launch the server. For streaming use the webplayer Signed-off-by: LMSSonos --- .devcontainer/Dockerfile | 15 +++++++++++++ .devcontainer/devcontainer.json | 36 ++++++++++++++++++++++++++++++++ .devcontainer/docker-compose.yml | 16 ++++++++++++++ .gitignore | 7 +++++++ 4 files changed, 74 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/docker-compose.yml create mode 100644 .gitignore diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000000..7cf5a1b7e5c --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,15 @@ +FROM mcr.microsoft.com/devcontainers/base:bookworm + +# taken from: https://github.com/LMS-Community/slimserver-platforms/blob/public/9.1/Docker/Dockerfile + +# Set environment variables +ENV DEBIAN_FRONTEND=noninteractive +ENV LC_ALL="C.UTF-8" LANG="en_US.UTF-8" LANGUAGE="en_US.UTF-8" + + +# Install packages +RUN sudo apt-get update -qq && \ + sudo apt-get install --no-install-recommends -qy procps psmisc wget curl perl tzdata libcrypt-blowfish-perl libwww-perl libfont-freetype-perl liblinux-inotify2-perl \ + libdata-dump-perl libio-socket-ssl-perl libnet-ssleay-perl libcrypt-ssleay-perl libcrypt-openssl-rsa-perl libssl-dev libgomp1 libasound2 lame opus-tools && \ + sudo apt-get clean -qy && \ + sudo rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000000..495fb6ed918 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,36 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/debian +{ + "name": "Lyrion Debian devcontainer", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + //"image": "mcr.microsoft.com/devcontainers/base:bookworm", + "dockerComposeFile": "docker-compose.yml", + "service": "lyrion-devcontainer", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [ + 9000, + 3483, + 9090 + ], + "portsAttributes": { + "9000": { + "label": "web interface", + "protocol": "http" + }, + "3483": { + "label": "SlimProto" + }, + "9090": { + "label": "CLI" + } + }, + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "wget -O /workspaces/slimserver/Slim/Utils/OS/Custom.pm https://raw.githubusercontent.com/LMS-Community/slimserver-platforms/public/9.1/Docker/Slim-Utils-OS-Custom.pm" + // Configure tool-specific properties. + // "customizations": {}, + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} \ No newline at end of file diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 00000000000..48ec338bdcc --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -0,0 +1,16 @@ +version: '3.11' + +services: + lyrion-devcontainer: + # add this line so we can connect to the host machine + build: + context: . + dockerfile: Dockerfile + volumes: + - lyrion-dev-volume:/workspace + + # Overrides default command so things don't shut down after the process ends. + command: sleep infinity + +volumes: + lyrion-dev-volume: \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..5246cc88216 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# Ignore custom OS module as this is installed in devcontainer and not part of this repo +Slim/Utils/OS/Custom.pm + +# Ignore cache, logs and prefs files +Cache/* +Logs/* +prefs/* \ No newline at end of file From 776145fd8ad275eb9388faa37c03f58286b3a47f Mon Sep 17 00:00:00 2001 From: LMSSonos Date: Wed, 19 Nov 2025 13:44:05 +0000 Subject: [PATCH 013/140] moved logic to post-create script, which checks if file exist for current branch, else takes latest Signed-off-by: LMSSonos --- .devcontainer/devcontainer.json | 2 +- .devcontainer/post-create.sh | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100755 .devcontainer/post-create.sh diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 495fb6ed918..711cda1ce87 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -28,7 +28,7 @@ } }, // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": "wget -O /workspaces/slimserver/Slim/Utils/OS/Custom.pm https://raw.githubusercontent.com/LMS-Community/slimserver-platforms/public/9.1/Docker/Slim-Utils-OS-Custom.pm" + "postCreateCommand": "/workspaces/slimserver/.devcontainer/post-create.sh" // Configure tool-specific properties. // "customizations": {}, // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh new file mode 100755 index 00000000000..9ec2d65a4a9 --- /dev/null +++ b/.devcontainer/post-create.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -e + +# get current git branch +BRANCH="$(git rev-parse --abbrev-ref HEAD)" + +URL_BRANCH="https://raw.githubusercontent.com/LMS-Community/slimserver-platforms/${BRANCH}/Docker/Slim-Utils-OS-Custom.pm" +URL_HEAD="https://raw.githubusercontent.com/LMS-Community/slimserver-platforms/HEAD/Docker/Slim-Utils-OS-Custom.pm" +TARGET_FILE="/workspaces/slimserver/Slim/Utils/OS/Custom.pm" + +echo "Detected branch: ${BRANCH}" +echo "Trying branch-specific file..." + +# Try downloading branch version +if curl -fSL "$URL_BRANCH" -o "$TARGET_FILE"; then + echo "Downloaded branch version from: $URL_BRANCH" +else + echo "Branch file not found, falling back to HEAD..." + curl -fSL "$URL_HEAD" -o "$TARGET_FILE" + echo "Downloaded latest version from: $URL_HEAD" +fi \ No newline at end of file From a3091ba9015677cc9a294a0fc0d7e1f1b922eb21 Mon Sep 17 00:00:00 2001 From: LMSSonos Date: Sat, 22 Nov 2025 12:51:39 +0000 Subject: [PATCH 014/140] added documentation Signed-off-by: LMSSonos --- DEVCONTAINERS.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 DEVCONTAINERS.md diff --git a/DEVCONTAINERS.md b/DEVCONTAINERS.md new file mode 100644 index 00000000000..16854d2ca5c --- /dev/null +++ b/DEVCONTAINERS.md @@ -0,0 +1,18 @@ +# Dev Container Environment + +You can run the project either entirely in the cloud using GitHub Codespaces or locally using VS Code with Dev Containers. Both methods provide a fully configured environment without requiring manual setup on your machine. + +## Development Modes + +### 1. GitHub Codespaces +- In Github on the Code tab click the **Code Button** → **Codespaces** → **Create Codespace**. +- Wait for the browser-based VS Code to start. +- Run `slimserver` in the terminal. +- Open the **Ports** tab and click the forwarded port to access the SlimServer web UI. +- Note: Codespaces includes free-tier limitations. + +### 2. Local VS Code with Dev Containers +- Install the Dev Containers extension: `ext install ms-vscode-remote.remote-containers` and make sure Dev Containers work. +- Run **Dev Containers: Clone Repository** command and follow the steps. +- The container builds automatically—no local dependencies required. +- After build completion, the environment is ready to use. From 402261d79d2efd140582eaab4a8bf67cc6aec03d Mon Sep 17 00:00:00 2001 From: philippe44 Date: Sat, 22 Nov 2025 23:58:58 +0100 Subject: [PATCH 015/140] Close HTTP connection only if close or if (request not keep-alive and not 1.0) --- Slim/Networking/Async/HTTP.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Slim/Networking/Async/HTTP.pm b/Slim/Networking/Async/HTTP.pm index 914f1dd25fd..11b67092838 100644 --- a/Slim/Networking/Async/HTTP.pm +++ b/Slim/Networking/Async/HTTP.pm @@ -590,7 +590,8 @@ sub _http_read_body { # if here, we've reached the end of the body # close and remove the socket if not keep-alive - if ( $self->response->headers->header('Connection') =~ /close/i || $self->request->headers->header('Connection') !~ /keep-alive/i ) { + if ( $self->response->headers->header('Connection') =~ /close/i || + ($self->request->headers->header('Connection') !~ /keep-alive/i && $self->request->protocol =~ m|HTTP/1.0|i) ) { $self->fh->close if $self->fh; $self->disconnect; main::DEBUGLOG && $log->debug("closing mode"); From 70182742de8d74346cdac60f4a8925684d9ed21b Mon Sep 17 00:00:00 2001 From: philippe44 Date: Sun, 23 Nov 2025 00:01:20 +0100 Subject: [PATCH 016/140] Revert "Close HTTP connection only if close or if (request not keep-alive and not 1.0)" This reverts commit 402261d79d2efd140582eaab4a8bf67cc6aec03d. --- Slim/Networking/Async/HTTP.pm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Slim/Networking/Async/HTTP.pm b/Slim/Networking/Async/HTTP.pm index 11b67092838..914f1dd25fd 100644 --- a/Slim/Networking/Async/HTTP.pm +++ b/Slim/Networking/Async/HTTP.pm @@ -590,8 +590,7 @@ sub _http_read_body { # if here, we've reached the end of the body # close and remove the socket if not keep-alive - if ( $self->response->headers->header('Connection') =~ /close/i || - ($self->request->headers->header('Connection') !~ /keep-alive/i && $self->request->protocol =~ m|HTTP/1.0|i) ) { + if ( $self->response->headers->header('Connection') =~ /close/i || $self->request->headers->header('Connection') !~ /keep-alive/i ) { $self->fh->close if $self->fh; $self->disconnect; main::DEBUGLOG && $log->debug("closing mode"); From 2e034d48490369f2dd2db587b351740d76fb4f7d Mon Sep 17 00:00:00 2001 From: philippe44 Date: Sun, 23 Nov 2025 00:05:45 +0100 Subject: [PATCH 017/140] Don't close HTTP when 1.1, unless explicit asked --- Slim/Networking/Async/HTTP.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Slim/Networking/Async/HTTP.pm b/Slim/Networking/Async/HTTP.pm index 914f1dd25fd..11b67092838 100644 --- a/Slim/Networking/Async/HTTP.pm +++ b/Slim/Networking/Async/HTTP.pm @@ -590,7 +590,8 @@ sub _http_read_body { # if here, we've reached the end of the body # close and remove the socket if not keep-alive - if ( $self->response->headers->header('Connection') =~ /close/i || $self->request->headers->header('Connection') !~ /keep-alive/i ) { + if ( $self->response->headers->header('Connection') =~ /close/i || + ($self->request->headers->header('Connection') !~ /keep-alive/i && $self->request->protocol =~ m|HTTP/1.0|i) ) { $self->fh->close if $self->fh; $self->disconnect; main::DEBUGLOG && $log->debug("closing mode"); From 7a5c02653944274b15a21ea165ad6d296dc3666f Mon Sep 17 00:00:00 2001 From: mipa87 <62723159+mipa87@users.noreply.github.com> Date: Sun, 23 Nov 2025 19:27:13 +0100 Subject: [PATCH 018/140] Update Czech translations Update Czech translations and correct quotes --- Slim/Plugin/ACLFiletest/strings.txt | 2 +- Slim/Plugin/ExtendedBrowseModes/strings.txt | 4 +- Slim/Plugin/Favorites/strings.txt | 4 +- Slim/Plugin/FullTextSearch/strings.txt | 2 +- Slim/Plugin/Podcast/strings.txt | 4 +- Slim/Plugin/ViewTags/strings.txt | 4 +- Slim/Plugin/iTunes/strings.txt | 2 +- strings.txt | 112 ++++++++++---------- 8 files changed, 67 insertions(+), 67 deletions(-) diff --git a/Slim/Plugin/ACLFiletest/strings.txt b/Slim/Plugin/ACLFiletest/strings.txt index 1a5c54c92ed..cdbc99f0e14 100644 --- a/Slim/Plugin/ACLFiletest/strings.txt +++ b/Slim/Plugin/ACLFiletest/strings.txt @@ -8,7 +8,7 @@ PLUGIN_ACL_FILETEST NO Aktiver ACL-filtest PLUGIN_ACL_FILETEST_DESC - CS Tento zásuvný modul umožňuje kontrolovat oprávnění k souborům na základě ACL v některých systémech. Tento doplněk nepovolujte, pokud nevíte, že váš systém podporuje ACL a Perl "use filetest". + CS Tento zásuvný modul umožňuje kontrolovat oprávnění k souborům na základě ACL v některých systémech. Tento doplněk nepovolujte, pokud nevíte, že váš systém podporuje ACL a Perl „use filetest“. DA Med dette pluginmodul kan du kontrollere filrettigheder baseret på ACL (Access-controlled list) på nogle systemer. Brug kun dette plugin hvis du ved, at dit system understøtter ACL'er og Perls 'use filetest'. EN This plugin allows you to check file permissions based on ACLs on some systems. Do not enable this plugin unless you know your system does support ACLs and Perl's 'use filetest'. FR Ce plugin permet sur certains systèmes d'exploitation de vérifier les autorisations de fichiers en fonction des ACL (Access Control List). N'activez ce plugin que si vous êtes sûr que votre système prend en charge les ACL et le "use filetest" de Perl. diff --git a/Slim/Plugin/ExtendedBrowseModes/strings.txt b/Slim/Plugin/ExtendedBrowseModes/strings.txt index 260e8cf1e98..7b2a08c49f8 100644 --- a/Slim/Plugin/ExtendedBrowseModes/strings.txt +++ b/Slim/Plugin/ExtendedBrowseModes/strings.txt @@ -256,7 +256,7 @@ PLUGIN_EXTENDED_BROWSEMODES_FLOP_TRACKS SV Floppspår PLUGIN_EXTENDED_BROWSEMODES_USE_X - CS Použít „%s" + CS Použít „%s“ DA Benyt '%s' DE '%s' verwenden EN Use '%s' @@ -268,7 +268,7 @@ PLUGIN_EXTENDED_BROWSEMODES_USE_X SV Använd '%s' PLUGIN_EXTENDED_BROWSEMODES_USING_X - CS Nyní používáte „%s" + CS Nyní používáte „%s“ DA Bruger nu '%s' DE Verwende nun '%s' EN Now using '%s' diff --git a/Slim/Plugin/Favorites/strings.txt b/Slim/Plugin/Favorites/strings.txt index 4c5b35320bf..983db6ef9a3 100644 --- a/Slim/Plugin/Favorites/strings.txt +++ b/Slim/Plugin/Favorites/strings.txt @@ -206,7 +206,7 @@ PLUGIN_FAVORITES_USE_DSTM NL Don't Stop The Music PLUGIN_FAVORITES_USE_DSTM_DESC - CS Zaregistrujte si oblíbené položky jako možnosti pro „Nezastavuj přehrávání hudby". + CS Zaregistrujte si oblíbené položky jako možnosti pro „Nezastavuj přehrávání hudby“. DA Benyt favoritter som valg for "Don't Stop The Music". DE Favoriten als Option für "Musikwiedergabe nie anhalten" verwenden. EN Register favorites as options for "Don't Stop The Music". @@ -233,7 +233,7 @@ PLUGIN_FAVORITES_PLAYLIST_EDITOR SV Bläddring och redigering för opml-spellistor PLUGIN_FAVORITES_PLAYLIST_EDITOR_DESC - CS Zásuvný modul Oblíbené položky vám také umožňuje procházet seznamy skladeb založené na OPML, které jsou uložené na vašem serveru. K přidání tohoto režimu do složky „Doplňky" domovské stránky vašeho serveru zvolte níže uvedenou možnost. + CS Zásuvný modul Oblíbené položky vám také umožňuje procházet seznamy skladeb založené na OPML, které jsou uložené na vašem serveru. K přidání tohoto režimu do složky „Doplňky“ domovské stránky vašeho serveru zvolte níže uvedenou možnost. DA Med udvidelsesmodulet Favoritter kan du gennemse og redigere opml-baserede afspilningslister som er gemt på din server. Marker denne mulighed hvis du vil føje den til menuen Ekstra i den webbaserede brugerflade. DE Das Favoriten Plugin erlaubt es auch, OPML basierte Wiedergabelisten auf dem Server zu durchsuchen und bearbeiten. Aktiviere die folgende Option, um diesen Modus unter "Extras" auf dem Server Web-Interface anzuzeigen. EN The favorites plugin will also allow you to browse opml based playlists and edit opml playlists stored on your server. Select the option below to add this mode under 'Extras' on the server home page. diff --git a/Slim/Plugin/FullTextSearch/strings.txt b/Slim/Plugin/FullTextSearch/strings.txt index e673d72dc05..ff0901a1af5 100644 --- a/Slim/Plugin/FullTextSearch/strings.txt +++ b/Slim/Plugin/FullTextSearch/strings.txt @@ -10,7 +10,7 @@ PLUGIN_FULLTEXT PL Wyszukiwanie pełnotekstowe PLUGIN_FULLTEXT_DESC - CS Tento zásuvný modul nahrazuje poměrně zjednodušené vyhledávání v názvech fulltextovým vyhledáváním. To umožní např. najít seznamy skladeb se skladbou hledaného názvu nebo odfiltrovat ztrátové soubory přidáním slova „flac" k hledanému výrazu. Vypnutím tohoto zásuvného modulu se obnoví staré, jednoduché vyhledávání názvů. Upozornění pro pokročilé uživatele: fulltextové vyhledávání není k dispozici při použití MySQL. + CS Tento zásuvný modul nahrazuje poměrně zjednodušené vyhledávání v názvech fulltextovým vyhledáváním. To umožní např. najít seznamy skladeb se skladbou hledaného názvu nebo odfiltrovat ztrátové soubory přidáním slova „flac“ k hledanému výrazu. Vypnutím tohoto zásuvného modulu se obnoví staré, jednoduché vyhledávání názvů. Upozornění pro pokročilé uživatele: fulltextové vyhledávání není k dispozici při použití MySQL. DA Denne Plugin erstatter den simple titelsøgning med en fuldtekst søgning. Dette vil f.eks. finde titler på numre i afspillelister, eller bortfiltrere filer komprimeret med tab af opløsning ved at tilføje "Flac" i søgefeltet. Ved deaktivering af denne plugin genetableres den simple titelsøgning. Info til avancerede brugere: Fuldtekst søgning er ikke tilgængelig når man bruger MySQL. DE Diese Erweiterung ersetzt die einfache Titelsuche durch eine Volltextsuche, welche z.B. auch Titel innerhalb einer Playlist findet, oder durch einfache Eingabe von "flac" alle verlustbehafteten Dateien aus den Suchresultaten ausblendet. Deaktivieren dieses Plugins stellt die alte, einfache Titelsuche wieder her. Achtung Power-User: bei Verwendung von MySQL steht die Volltextsuche nicht zur Verfügung. EN This extension replaces the rather simplistic title search with a full text search. This would eg. find playlists with a track of the searched title, or filter out lossy files by adding "flac" to the search term. Disabling this plugin restores the old, simple title search. Powerusers please note: full text search is not available when using MySQL. diff --git a/Slim/Plugin/Podcast/strings.txt b/Slim/Plugin/Podcast/strings.txt index 78e90b8386c..10ae6883d53 100644 --- a/Slim/Plugin/Podcast/strings.txt +++ b/Slim/Plugin/Podcast/strings.txt @@ -362,7 +362,7 @@ PLUGIN_PODCAST_COUNTRY NL Land PLUGIN_PODCAST_SUBSCRIBE - CS Přihlásit se k odběru „%s" + CS Přihlásit se k odběru „%s“ DA Abonnér på '%s' DE Podcast '%s' abonnieren EN Subscribe to '%s' @@ -371,7 +371,7 @@ PLUGIN_PODCAST_SUBSCRIBE NL Abonneren op '%s' PLUGIN_PODCAST_UNSUBSCRIBE - CS Odhlásit se z odběru „%s" + CS Odhlásit se z odběru „%s“ DA Afmeld '%s' DE Von Podcast '%s' abmelden EN Unsubscribe from '%s' diff --git a/Slim/Plugin/ViewTags/strings.txt b/Slim/Plugin/ViewTags/strings.txt index 1a3e19746d7..afa77b52581 100644 --- a/Slim/Plugin/ViewTags/strings.txt +++ b/Slim/Plugin/ViewTags/strings.txt @@ -89,7 +89,7 @@ PLUGIN_VIEW_TAGS_CUSTOM_TAGS NL Toon additionele tags PLUGIN_VIEW_TAGS_CUSTOM_TAGS_DESC - CS „Název tagu" se vztahuje na skutečný tag, jak je uložen v souboru, např. „WEBSITE". Zobrazí se v nabídce „Zobrazit tagy". „Zobrazovaný název" je uživatelsky přívětivější název, který se použije v uživatelském rozhraní. „Adresa URL" určuje, zda pole obsahuje adresu URL. V tomto případě mohou uživatelská rozhraní, která jsou schopná odkazovat na adresy URL, zobrazit obsah s odkazem. + CS „Název tagu“ se vztahuje na skutečný tag, jak je uložen v souboru, např. „WEBSITE“. Zobrazí se v nabídce „Zobrazit tagy“. „Zobrazovaný název“ je uživatelsky přívětivější název, který se použije v uživatelském rozhraní. „Adresa URL“ určuje, zda pole obsahuje adresu URL. V tomto případě mohou uživatelská rozhraní, která jsou schopná odkazovat na adresy URL, zobrazit obsah s odkazem. DA "Mærkenavn" er det faktiske navn som er gemt i filen, f.eks. "WEBSITE". Dette vises også i "Vis mærker" menuen. "Mærkenavn at vise" er et mere brugervenligt navn, der vil blive vist i brugergrænsefladen. "URL" definerer, om den viste værdi skal vises som et link (hvis muligt). DE "Tag Name" ist der eigentliche Name, wie er in der Datei gespeichert ist, z.B. "WEBSITE". Dieser Name wird auch in "Tags anzeigen" eines Titels angezeigt. "Anzuzeigender Name" ist ein benutzerfreundlicherer Name, der in der Benutzeroberfläche angezeigt wird. "URL" definiert, ob der angezeigte Wert als Link dargestellt werden soll (wenn möglich). EN "Tag name" refers to the actual tag, as stored in the file, eg. "WEBSITE". The "View Tags" menu shows these. The "Name to be displayed" is a more user friendly name to be used in the UI. "URL" defines whether the field contains a URL. In this case UIs able to link to URLs can render the content with a link. @@ -134,7 +134,7 @@ PLUGIN_VIEW_TAGS_TOPLEVEL NL Toon tags op het hoogste niveau PLUGIN_VIEW_TAGS_MOREINFO - CS Zobrazit tagy v „Další informace" + CS Zobrazit tagy v „Další informace“ DA Vis mærker i "Mere info" DE Tags in "Weitere Infos" anzeigen EN Show tags in "More Info" diff --git a/Slim/Plugin/iTunes/strings.txt b/Slim/Plugin/iTunes/strings.txt index 3ba97edace9..4687302b2cd 100644 --- a/Slim/Plugin/iTunes/strings.txt +++ b/Slim/Plugin/iTunes/strings.txt @@ -460,7 +460,7 @@ SETUP_ITUNES_IGNORED_PLAYLISTS SV Ignorererade spellistor SETUP_ITUNES_IGNORED_PLAYLISTS_DESC - CS Definujte čárkou oddělené seznamy skladeb iTunes, které nechcete importovat (např. „Videa, Zakoupeno"). + CS Definujte čárkou oddělené seznamy skladeb iTunes, které nechcete importovat (např. „Videa, Zakoupeno“). DA Opret en kommaadskilt liste med de afspilningslister fra iTunes som ikke skal importeres (fx Videoklip, Købt). DE Definiert eine durch Komma getrennte Liste von iTunes-Wiedergabelisten, die nicht importiert werden sollen (z.B. "Videos, gekauft"). EN Define a comma separated list of iTunes playlists you don't want to be imported (eg. "Videos, Purchased"). diff --git a/strings.txt b/strings.txt index 184a9d86f73..a35a095b7f1 100644 --- a/strings.txt +++ b/strings.txt @@ -1876,7 +1876,7 @@ ALARM_ADD SV Lägg till alarm ALARM_ADD_DESC - CS Můžete přidat tolik budíků, kolik chcete. Každý budík může být nastaven na každý den, pouze na určité dny nebo jen jednou. Nový budík přidáte volbou „Přidat budík". + CS Můžete přidat tolik budíků, kolik chcete. Každý budík může být nastaven na každý den, pouze na určité dny nebo jen jednou. Nový budík přidáte volbou „Přidat budík“. DA Du kan tilføje lige så mange vækkeure som du vil. Hvert vækkeur kan indstilles til at ringe hver dag, på bestemte dage eller kun en enkelt gang. Vælg Tilføj vækkeur for at indstille et nyt. DE Sie können beliebig viele Wecker einrichten. Ein Wecker kann jeden Tag, nur an bestimmten Tagen oder nur einmal gelten. Wählen Sie "Wecker hinzufügen", um einen neuen Wecker hinzuzufügen. EN You can add as many alarms as you like. Each alarm can be set to go off every day, on particular days only, or just once. Select "Add Alarm" to start adding a new alarm. @@ -2150,7 +2150,7 @@ ALARM_DELETING SV Tar bort alarm... ALARM_NOW_PLAYING - CS Budík „Právě hraje" + CS Budík „Právě hraje“ DA Vækkeuret spiller nu DE Aktuelle Wecker-Wiedergabe EN Alarm Clock Now Playing @@ -2221,7 +2221,7 @@ SETUP_SNOOZE_MINUTES SV Snoozetid (i minuter) SETUP_SNOOZE_MINUTES_DESC - CS Toto nastavení vám umožňuje zvolit dobu, po kterou je budík přerušen, když stisknete tlačítko Přerušovaný budík. + CS Toto nastavení vám umožňuje zvolit dobu, po kterou je budík přerušen, když stisknete tlačítko Opakovaný budík. DA Du bruger denne indstilling til at angive hvor lang tid vækkeuret skal være midlertidigt slukket når du trykker på slumreknappen. DE Mit dieser Einstellung können Sie bestimmen, nach welcher Zeit nach dem Drücken der Snooze-Taste der Wecker wiederholt wird. EN This setting allows you to choose how long an alarm pauses for when you hit the snooze button. @@ -3923,7 +3923,7 @@ SETUP_GROUP_MENUITEMS ZH_CN 主页菜单 SETUP_GROUP_MENUITEMS_DESC - CS Můžete si upravit volby, které se objeví ve vaší Domovské nabídce na displeji přehrávače. Klepnutím na položky je můžete přesunout nahoru a dolů nebo odstranit. Klepnutím na „Přidat" přidáte odstraněnou položku zpět do nabídky. + CS Můžete si upravit volby, které se objeví ve vaší Domovské nabídce na displeji přehrávače. Klepnutím na položky je můžete přesunout nahoru a dolů nebo odstranit. Klepnutím na „Přidat“ přidáte odstraněnou položku zpět do nabídky. DA Du kan selv vælge hvilke menupunkter der skal vises på øverste niveau i hovedmenuen på afspillerens display. Du kan flytte menupunkter op og ned eller fjerne dem ved at klikke på knapperne ud for dem. Klik på Tilføj hvis du vil tilføje et punkt som er fjernet fra menuen. DE Sie können die im Hauptmenü des Players verfügbaren Einträge bestimmen. Klicken Sie auf die entsprechenden Schaltflächen, um Einträge nach oben bzw. unten zu verschieben oder sie zu entfernen. Klicken Sie auf 'Hinzufügen', um einen entfernten Eintrag wieder aufzunehmen. EN You can customize the choices that are available on the top-level Home menu on the player's display. Click to move items up and down or to remove menu items. Click on "Add" to add a removed item back to the menu. @@ -4925,7 +4925,7 @@ SETUP_SENSAUTOBRIGHTNESS_DESC SV Ändra känsligheten för automatisk ljusstyrka. SETUP_PLAYINGDISPLAYMODE - CS Informace o „Právě hraje" + CS Informace o „Právě hraje“ DA Oplysninger under afspilning DE Informationen zur aktuellen Wiedergabe EN Now Playing Information @@ -4945,7 +4945,7 @@ SETUP_PLAYINGDISPLAYMODE ZH_CN 播放中信息 SETUP_PLAYINGDISPLAYMODE_ABBR - CS Inf. o „Právě hraje" + CS Inf. o „Právě hraje“ DA Oplysninger om nummer der spiller DE Aktueller Titel - Info EN Now Playing Info @@ -5440,7 +5440,7 @@ SETUP_STARTDELAY SV Fördröjning för spelarstart (ms) SETUP_STARTDELAY_DESC - CS Přehrávači může trvat nezanedbatelnou dobu, než spustí přehrávání (než začnete poslouchat hudbu) po zpracování příkazu ke startu od Lyrion Music Serveru. To může nastat v případě, když se používají digitální výstupy (v závislosti na připojením zařízení) nebo u softwarových přehrávačů na určitých platformách. V těchto případech lze nastavit zde toto zpoždění tak, aby Lyrion Music Server věděl, o kolik dříve musí spustit tento přehrávač, aby hudba ze všech synchronizovaných přehrávačů začala ve stejnou dobu. Poznámka: toto se přičítá k případnému „Zpoždění zvuku přehrávače" (níže). + CS Přehrávači může trvat nezanedbatelnou dobu, než spustí přehrávání (než začnete poslouchat hudbu) po zpracování příkazu ke startu od Lyrion Music Serveru. To může nastat v případě, když se používají digitální výstupy (v závislosti na připojením zařízení) nebo u softwarových přehrávačů na určitých platformách. V těchto případech lze nastavit zde toto zpoždění tak, aby Lyrion Music Server věděl, o kolik dříve musí spustit tento přehrávač, aby hudba ze všech synchronizovaných přehrávačů začala ve stejnou dobu. Poznámka: toto se přičítá k případnému „Zpoždění zvuku přehrávače“ (níže). DA Det kan vare lidt fra du klikker på startknappen i Lyrion Music Server til afspilningen begynder (før du kan høre noget). Det kan forekomme når de digitale udgange bruges (afhængigt af hvad der er tilsluttet) eller i forbindelse med softwareafspillere på nogle platforme. I så fald kan du indstille en forsinkelse her sådan at Lyrion Music Server ved hvor meget tidligere afspilleren skal startes sådan at lyden på alle de synkroniserede afspillere startes på samme tid. Bemærk: Denne indstilling er i tillæg til en permanent indstilling af Lydforsinkelse for afspiller (nedenfor). DE Es kann eine gewisse Zeit dauern, bis ein Player die Wiedergabe beginnt (bis Sie die Musik hören), nachdem der von Lyrion Music Server empfangene Startbefehl verarbeitet wurde. Dies kann bei der Nutzung digitaler Ausgänge (abhängig vom angeschlossenen Gerät) oder bei bestimmten Software-Playern unter bestimmten Plattformen vorkommen. Sie können dann diese Verzögerung hier festlegen, damit Lyrion Music Server weiß, wie bald dieser Player gestartet werden soll, damit die Wiedergabe aus allen synchronisierten Playern gleichzeitig gestartet wird. Hinweis: Diese Verzögerung gilt zusätzlich zu 'Audioverzögerung des Players' (siehe unten). EN A player can take a noticeable time to start playing (before you begin to hear the audio) after it processes the start command from Lyrion Music Server. This can be the case when using digital outputs (depending upon the connected equipment) or with software players on some platforms. In these cases, this delay can be set here so that Lyrion Music Server knows how much in advance to start this player so that the audio from all the synchronized players starts at the same time. Note: this is in addition to any ongoing "Player Audio Delay" (below). @@ -5877,7 +5877,7 @@ SETUP_REPLAYGAINMODE ZH_CN 音量调整/重播增益 SETUP_REPLAYGAINMODE_DESC - CS Některé zvukové skladby obsahují informace o nastavení hlasitosti neboli „Replay Gain", které lze použít při přehrávání, aby skladby a alba zněly stejně hlasitě. Pokud je tato informace přítomna, přehrávač ji může použít. „Zesílení skladby" lze použít pro to, aby všechny skladby zněly stejně hlasitě. „Zesílení alba" lze použít pro to, aby všechna alba zněla stejně hlasitě, ale aby byly zachovány rozdíly v hlasitosti mezi skladbami v rámci alba. Volba „Inteligentní zesílení" používá zesílení alba, pokud jsou po sobě jdoucí skladby ze stejného alba nebo zesílení skladby pro smíšený seznam skladeb. + CS Některé zvukové skladby obsahují informace o nastavení hlasitosti neboli „Replay Gain“, které lze použít při přehrávání, aby skladby a alba zněly stejně hlasitě. Pokud je tato informace přítomna, přehrávač ji může použít. „Zesílení skladby“ lze použít pro to, aby všechny skladby zněly stejně hlasitě. „Zesílení alba“ lze použít pro to, aby všechna alba zněla stejně hlasitě, ale aby byly zachovány rozdíly v hlasitosti mezi skladbami v rámci alba. Volba „Inteligentní zesílení“ používá zesílení alba, pokud jsou po sobě jdoucí skladby ze stejného alba nebo zesílení skladby pro smíšený seznam skladeb. DA Nogle lydfiler indeholder oplysninger om lydstyrkejustering, også kaldet Replay Gain. Oplysningerne kan anvendes ved afspilningen for at sikre at forskellige nummer og album har den samme lydstyrke. Afspilleren kan anvende denne information hvis den findes. Forstærkning af nummer kan bruges til at sikre at alle numre har samme lydstyrke. Forstærkning af album kan bruges til at sikre at alle album har samme lydstyrke, men forskellen i lydstyrke mellem de enkelte numre på et album bevares. Dynamisk forstærkning anvender forstærkning af album hvis flere på hinanden følgende numre er fra samme album, og forstærkning af numre hvis afspilningslisten består af numre fra forskellige album. DE Titel können Informationen zur Normalisierung der Lautstärke enthalten ('Replay Gain'), damit alle Titel und Alben mit derselben Lautstärke wiedergegeben werden können. Der Player kann diese Information nutzen. 'Titel-Normalisierung' stellt sicher, dass alle Titel gleich laut wiedergegeben werden. 'Album-Normalisierung' stellt sicher, dass alle Alben gleich laut wiedergegeben werden, wobei Unterschiede in der Lautstärke in den Titeln eines Albums erhalten bleiben. 'Intelligente' Normalisierung nutzt die Album-Normalisierung, wenn aufeinanderfolgende Titel vom selben Album stammen bzw. die Titel-Normalisierung für gemischte Wiedergabelisten. EN Some audio tracks contain volume adjustment, or "Replay Gain", information that can be used during playback to make sure that tracks and albums sound equally loud. The player can use this information if it is present. "Track gain" can be used to make sure that all tracks sound equally loud. "Album gain" can be used to make sure that all albums sound equally loud, but that volume differences between tracks within an album are preserved. "Smart" gain selection uses album gain if successive songs are from the same album or track gain for a mixed playlist. @@ -6058,7 +6058,7 @@ SETUP_MP3STREAMINGMETHOD SV Strömningsmetod SETUP_MP3STREAMINGMETHOD_DESC - CS Při přehrávání datového proudu z internetu, může být přehrávání datových proudů provedeno jedním ze dvou způsobů. Při volbě „Přímé přehrávání datového proudu" přehrávač provede přímé spojení se serverem přehrávání zvukových proudů a tím mírně sníží zatížení Lyrion Music Serveru a umožní přehrávání proudu i po ztrátě spojení s Lyrion Music Serverem. Volba „Přehrávání datového proudu přes proxy" způsobí, že Lyrion Music Server zajistí spojení a přehraje zvuk prostřednictvím přehrávače. „Přímé přehrávání datového proudu" je výchozí nastavení, ale jestliže budete mít potíže s proudy, zkuste změnit nastavení na „Přehrávání datového proudu přes proxy". Pamatujte na to, že pokud jsou s proudem synchronizovány dva a více přehrávačů, použije se vždy „Přehrávání datového proudu přes proxy", aby se snížilo využití šířky pásma. + CS Při přehrávání datového proudu z internetu, může být přehrávání datových proudů provedeno jedním ze dvou způsobů. Při volbě „Přímé přehrávání datového proudu“ přehrávač provede přímé spojení se serverem přehrávání zvukových proudů a tím mírně sníží zatížení Lyrion Music Serveru a umožní přehrávání proudu i po ztrátě spojení s Lyrion Music Serverem. Volba „Přehrávání datového proudu přes proxy“ způsobí, že Lyrion Music Server zajistí spojení a přehraje zvuk prostřednictvím přehrávače. „Přímé přehrávání datového proudu“ je výchozí nastavení, ale jestliže budete mít potíže s proudy, zkuste změnit nastavení na „Přehrávání datového proudu přes proxy“. Pamatujte na to, že pokud jsou s proudem synchronizovány dva a více přehrávačů, použije se vždy „Přehrávání datového proudu přes proxy“, aby se snížilo využití šířky pásma. DA Når der afspilles en stream fra internettet, kan det gøres på to måder. Ved direkte streaming etableres der en direkte forbindelse mellem afspilleren og serveren der streames fra. Det reducerer belastningen af Lyrion Music Server en smule og afspilningen fortsætter selvom forbindelsen til Lyrion Music Server bliver afbrudt. Ved streaming via en proxy vil Lyrion Music Server håndtere forbindelsen og sende lyden videre til afspilleren. Direkte streaming er standardmetoden, men hvis du har problemer med streams, kan du ændre indstillingen til Streaming via proxy. Bemærk at hvis to eller flere afspillere er synkroniseret til en stream, bliver proxymetoden altid anvendt for at begrænse brugen af båndbredde. DE Zur Wiedergabe eines Internet-Streams kann das Streaming auf zwei verschiedene Arten durchgeführt werden. Beim direkten Streaming erstellt der Player eine direkte Verbindung mit dem Audio-Streaming-Server, wodurch die Belastung von Lyrion Music Server verringert wird und der Stream auch fortgesetzt werden kann, wenn die Verbindung zu Lyrion Music Server unterbrochen wird. Beim Streaming über einen Proxy-Server verwaltet Lyrion Music Server die Verbindung und leitet die Musik an den Player weiter. Standardmäßig wird das direkte Streaming verwendet, aber wenn Probleme mit Streams auftreten, können Sie die andere Methode versuchen. Hinweis: Wenn zwei oder mehre Player synchron auf einem Stream zugreifen, wird immer das Streaming über einen Proxy-Server verwendet, um die Bandbreitennutzung zu reduzieren. EN When playing an Internet stream, the streaming can be done in one of two ways. Direct Streaming causes the player to make a direct connection to the audio streaming server, reducing the load on Lyrion Music Server slightly and allowing the stream to continue playing if the Lyrion Music Server connection is lost. Proxied Streaming causes Lyrion Music Server to handle the connection, passing the audio through to the player. Direct Streaming is the default, but if you experience problems with streams, try changing this setting to Proxied Streaming. Note that if two or more players are synchronized to an stream, proxied streaming is always used to reduce bandwidth usage. @@ -6728,7 +6728,7 @@ SETUP_IRMAP ZH_CN 遥控键功能 SETUP_IRMAP_DESC - CS Můžete si zvolit mezi seznamy funkcí tlačítek. Tyto seznamy přiřazují konkrétní tlačítka na infračerveném dálkovém ovladači ke konkrétním funkcím. „Standardní" seznam je popsán v dokumentaci. + CS Můžete si zvolit mezi seznamy funkcí tlačítek. Tyto seznamy přiřazují konkrétní tlačítka na infračerveném dálkovém ovladači ke konkrétním funkcím. „Standardní“ seznam je popsán v dokumentaci. DA Du kan vælge mellem forskellige funktionssæt til knapperne. Disse funktionssæt bestemmer hvilken funktion de forskellige knapper på fjernbetjeningen skal have. Standardsættet er det som er beskrevet i dokumentationen. DE Sie können zwischen Tastenfunktionsgruppen wählen, die Tasten der Fernbedienung mit bestimmten Funktionen belegen. Die Gruppe 'Standard' wird in der Dokumentation beschrieben. EN You can choose between button function sets. These sets map particular buttons on the infrared remote to particular functions. The "Standard" set is the one that is described in the documentation. @@ -6836,7 +6836,7 @@ SETUP_LIBRARY_NAME SV Mediebiblioteksnamn SETUP_LIBRARY_NAME_DESC - CS Tak se bude jmenovat vaše knihovna médií v nabídce „Moje média" vašeho Squeezeboxu. + CS Tak se bude jmenovat vaše knihovna médií v nabídce „Moje média“ vašeho Squeezeboxu. DA Dit mediebibliotek får dette navn i Squeezebox-menuen Mine multimedier. DE Das ist der Name der Medienbibliothek im Squeezebox-Menü 'Eigene Medien'. EN This is how your media library will be named in your Squeezebox's "My Media" menu. @@ -7001,7 +7001,7 @@ SETUP_ARTFOLDER_DESC ZH_CN 您可以利用以上的文件名变量选项,把所有的图象集中存放在一个文件夹内。请在这里输入图象文件所在地点。如果服务器未能在所指定的封面图象文件夹中找到匹配图象,便会在各个音像文件所属的文件夹中寻找匹配的图象。 SETUP_BAD_FILE - CS Ouha – „%s" asi nebude platný soubor. Zkuste to znovu. + CS Ouha – „%s“ asi nebude platný soubor. Zkuste to znovu. DA %s er ikke en gyldig fil. Prøv igen. DE Fehler: '%s' ist keine gültige Datei. Versuchen Sie es noch einmal. EN Oops - "%s" doesn't seem to be a valid file. Try again. @@ -7020,7 +7020,7 @@ SETUP_BAD_FILE ZH_CN "%s"似乎不是一个合法文件。请再次尝试。 SETUP_BAD_DIRECTORY - CS Ouha – „%s" asi nebude platný adresář. Zkuste to znovu. + CS Ouha – „%s“ asi nebude platný adresář. Zkuste to znovu. DA %s er ikke en gyldig mappe. Prøv igen. DE Fehler: '%s' ist kein gültiges Verzeichnis. Versuchen Sie es noch einmal. EN Oops - "%s" doesn't seem to be a valid directory. Try again. @@ -7359,7 +7359,7 @@ SETUP_SKIN ZH_CN 网界面 SETUP_SKIN_DESC - CS Ze seznamu níže si můžete vybrat vzhled čili „skin" pro webové rozhraní. + CS Ze seznamu níže si můžete vybrat vzhled čili „skin“ pro webové rozhraní. DA Du kan vælge et layout ("skin") til den webbaserede brugerflade på listen nedenfor. DE Sie können das Aussehen (eine 'Skin') für die Web-Benutzeroberfläche aus der folgenden Liste auswählen. EN You can choose a look or "skin" for the web interface from the list below. @@ -7892,7 +7892,7 @@ SETUP_COVERART ZH_CN 图象 SETUP_COVERART_DESC - CS Obrázky obalů alb, pokud jsou k dispozici, se zobrazují při prohlížení informací o albu nebo skladbě. Obrázky obalů alb se nacházejí v tagech ID3 u jednotlivých skladeb nebo mohou být uloženy ve stejné složce jako soubory skladeb. Standardně se používají názvy obrázků „cover.jpg", „folder.jpg", „album.jpg" nebo „thumb.jpg". Můžete zadat další názvy souborů pro obrázky obalů alb. Můžete zadat jiné názvy pro náhledy nebo pro obrázky plné velikosti. Přidejte před tuto volbu znak % a můžete za něj napsat libovolný řetězec vytvořený ze stejných prvků, které jsou pro Formáty názvů (např. %ARTIST - ALBUM bude hledat Artist - Album.jpg odpovídající nalezenému interpretovi a albu). + CS Obrázky obalů alb, pokud jsou k dispozici, se zobrazují při prohlížení informací o albu nebo skladbě. Obrázky obalů alb se nacházejí v tagech ID3 u jednotlivých skladeb nebo mohou být uloženy ve stejné složce jako soubory skladeb. Standardně se používají názvy obrázků „cover.jpg“, „folder.jpg“, „album.jpg“ nebo „thumb.jpg“. Můžete zadat další názvy souborů pro obrázky obalů alb. Můžete zadat jiné názvy pro náhledy nebo pro obrázky plné velikosti. Přidejte před tuto volbu znak % a můžete za něj napsat libovolný řetězec vytvořený ze stejných prvků, které jsou pro Formáty názvů (např. %ARTIST - ALBUM bude hledat Artist - Album.jpg odpovídající nalezenému interpretovi a albu). DA Der vises billeder af albumcovere når du vælger at se oplysninger om et album eller nummer. Coverbillederne hentes fra ID3-koderne i de enkelte numre eller fra mappen hvor filerne er placeret. Som standard indlæses følgende grafikfiler hvis der ikke er et billede i ID3-koden: "cover.jpg", "folder.jpg", "album.jpg" eller "thumb.jpg". Du kan angive flere filnavne der skal anvendes. Du kan endvidere angive forskellige filnavne for billeder i fuld størrelse og mindre størrelse. DE Plattenhüllen werden (falls verfügbar) beim Anzeigen eines Albums oder Titelinformationen angezeigt. Diese Bilder sind in den ID3-Tags der Titel bzw. demselben Ordner wie die Musikdateien enthalten. Standardmäßig werden Dateinamen wie "cover.jpg", "album.jpg" oder "thumb.jpg" verwendet. Sie können einen weiteren Dateinamen für Plattenhüllen angeben. Sie können unterschiedliche Dateinamen für Miniaturen und Vollbilder angeben. Stellen Sie ein % voran. Der Name kann aus denselben Elementen bestehen, die für Titelformate zulässig sind (z.B. %ARTIST - ALBUM sucht nach 'Interpret - Album.jpg', um die passende Datei zu finden. EN Images of album artwork, when available, are displayed when viewing an album or song information. Artwork images are found in the ID3 tags for individual songs or can reside in the same folder as song files. By default, images named "cover.jpg", "folder.jpg", "album.jpg", or "thumb.jpg" are used. You can specify an additional file name to use for album art images. You can specify different file names for thumbnail or full size images. Prefix the option with % and you can follow it with any string made up of the same elements available for Title Formats (eg %ARTIST - ALBUM, will look for Artist - Album.jpg to fit the artist and album information found). @@ -8461,7 +8461,7 @@ SETUP_ALARMSAVER_ABBR SV Vid alarm SETUP_SCREENSAVER_DESC - CS Po období nečinnosti dálkového ovladače může přehrávač zobrazovat různé informace jako „spořiče obrazovky". Můžete zvolit odlišné spořiče k zobrazení v závislosti na tom, jestli přehrávač hraje nebo ne nebo je vypnut. Můžete také zvolit dobu čekání před povolením těchto spořičů obrazovky. + CS Po období nečinnosti dálkového ovladače může přehrávač zobrazovat různé informace jako „spořiče obrazovky“. Můžete zvolit odlišné spořiče k zobrazení v závislosti na tom, jestli přehrávač hraje nebo ne nebo je vypnut. Můžete také zvolit dobu čekání před povolením těchto spořičů obrazovky. DA Hvis du ikke har brugt fjernbetjeningen i et stykke tid, kan der vises forskellige oplysninger på displayet som en form for pauseskærm. Du kan vælge at bruge forskellige pauseskærme når afspilleren er hhv. tændt og slukket, når der spilles et nummer og når der ikke gør. Du kan også angive hvor lang tid der skal gå før pauseskærmene aktiveres. DE Sie können einen Bildschirmschoner wählen, der nach einer gewissen Inaktivität der Fernbedienung aktiviert wird. Außerdem können Sie die Zeit wählen, nach der der Bildschirmschoner aktiviert wird. Je nachdem, ob der Player Audio wiedergibt, angehalten oder ausgeschaltet wurde, können Sie verschiedene Bildschirmschoner wählen. EN After a period of inactivity from the remote control, the player can display various information as "screensavers". You can choose different screensavers to show, depending on whether the player is playing or not, or if it is powered off. You can also choose the amount of time to wait before enabling these screensavers. @@ -8539,7 +8539,7 @@ SCREENSAVER_JUMP_BACK_NAME ZH_CN 播放中 SCREENSAVER_JUMP_TO_NOW_PLAYING - CS Přejít na „Právě hraje" + CS Přejít na „Právě hraje“ DA Gå til Nu spiller DE In 'Aktuelle Wiedergabe' wechseln EN Jump To Now Playing @@ -8630,7 +8630,7 @@ SETUP_ADDITIONAL_PLAYLIST_BUTTONS SV Ytterligare spellisteknappar SETUP_ADDITIONAL_PLAYLIST_BUTTONS_DESC - CS Některé vzhledy mohou volitelně zobrazovat další tlačítka pro přehratelné položky, například „Přehrát další" nebo „Odstranit ze seznamu skladeb". + CS Některé vzhledy mohou volitelně zobrazovat další tlačítka pro přehratelné položky, například „Přehrát další“ nebo „Odstranit ze seznamu skladeb“. DA Nogle temaer kan vise flere knapper, fx Spil næste, Fjern fra afspilningsliste. DE Bestimmte Skins können wahlweise zusätzliche Wiedergabe-Schaltflächen (z.B. 'Nächsten wiedergeben' oder 'Aus Wiedergabeliste entfernen' enthalten. EN Some skins optionally can display additional buttons for playable items, like eg. "Play next" or "Remove from playlist". @@ -8701,7 +8701,7 @@ SETUP_SEARCHSUBSTRING_1 ZH_CN 在词内搜寻 SETUP_SEARCHSUBSTRING_DESC - CS Pokud hledáte mediální soubory, můžete pomocí serveru hledat odpovídající položky obsahující slova, která začínají stejnými písmeny jako hledaný řetězec, nebo obsahující slova, která mají hledaný řetězec kdekoliv ve slově. Například hledání začátku slov „RAIN" najde položky se slovem „RAINBOW". Hledání uvnitř slov vrátí také položku obsahující slovo „TRAIN". + CS Pokud hledáte mediální soubory, můžete pomocí serveru hledat odpovídající položky obsahující slova, která začínají stejnými písmeny jako hledaný řetězec, nebo obsahující slova, která mají hledaný řetězec kdekoliv ve slově. Například hledání začátku slov „RAIN“ najde položky se slovem „RAINBOW“. Hledání uvnitř slov vrátí také položku obsahující slovo „TRAIN“. DA Når du søger efter mediefiler, kan serveren enten finde elementer med ord som begynder med de samme bogstaver som din søgestreng, eller ord som indeholder søgestrengen et vilkårligt sted i ordet. For eksempel vil søgestrengen ved søgning efter "RAIN" i begyndelsen finde elementer med ordet "RAINBOW". Søgning efter vilkårlige steder i ord vil også returnere elementer som indeholder ordet "TRAIN". DE Beim Suchen nach Mediendateien können Sie den Server anweisen, nur am Wortanfang nach Zeichenfolgen zu suchen oder an einer beliebigen Stelle im Wort. Beispiel: Wenn Sie den Wortanfang nach 'RAIN' durchsuchen, werden auch Einträge mit dem Wort 'RAINBOW' gefunden. Wird innerhalb des Wortes gesucht, werden auch Wörter wie 'TRAIN' gefunden. Bitte beachten Sie, dass die Einstellung ignoriert wird, wenn die Volltextsuche aktiviert ist. EN When you search for media files, you can have your server find matches for items that contain words that begin with the same letters in your search string or contain words that have the search string anywhere in the word. For example, searching the beginnings of words for "RAIN" in would find items with the word "RAINBOW". Searching within words would also return item containing the word "TRAIN". PLEASE NOTE: if you're using the Fulltext Search plugin, this flag does not apply. @@ -9142,7 +9142,7 @@ SETUP_IGNOREDARTICLES ZH_CN 进行排序时应忽略的词汇 SETUP_IGNOREDARTICLES_DESC - CS Seznam členů („the", „les", „los" atd.) na začátku jména interpreta, skladby nebo alba, které se budou při řazení ignorovat. Více členů oddělte mezerami nebo nechte tento seznam prázdný, čímž se tato funkce vypne. Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. + CS Seznam členů („the“, „les“, „los“ atd.) na začátku jména interpreta, skladby nebo alba, které se budou při řazení ignorovat. Více členů oddělte mezerami nebo nechte tento seznam prázdný, čímž se tato funkce vypne. Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. DA En liste med artikler ("the", "les", "los" (og evt. andre ord)) der skal ignoreres ved sortering af kunstnere, numre og albumnavne. De enkelte ord skal adskilles af mellemrum, og hvis du ikke vil benytte funktionen, skal listen være tom. Hvis du ændrer denne indstilling, bliver dit musikbibliotek gennemsøgt igen. DE Eine Liste von Artikeln ("die", "the", "los", "la" usw..), die bei Sortieren am Anfang des Namens von Interpreten, Titeln oder Alben ignoriert werden sollen. Trennen Sie verschiedene Artikel durch Leerzeichen oder lassen Sie die Liste leer, um diese Option nicht zu nutzen. Wenn Sie diese Einstellung ändern, wird die Musiksammlung erneut durchsucht. EN A list of articles ("the", "les", "los", etc.) to ignore at the beginning of artist, song or album names when sorting. Separate multiple articles by spaces or leave this list blank to disable this behavior. Changing this setting will start a rescan of your music library. @@ -9176,7 +9176,7 @@ SETUP_SPLITLIST SV Avgränsare för flera objekt i taggar SETUP_SPLITLIST_DESC - CS Lyrion Music Server může z tagů ve vašich hudebních souborech získat více interpretů, názvů alb a žánrů. Pokud ve vašich tagech najde některé ze slov nebo znaků uvedených níže, vytvoří pro každou položku jednotlivé výpisy. Pokud například do seznamu níže vložíte středník, skladba s tagem interpreta „J. S. Bach;Michael Tilson Thomas" se objeví v oblasti interpretů pro „J. S. Bach" i „Michael Tilson Thomas". Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. + CS Lyrion Music Server může z tagů ve vašich hudebních souborech získat více interpretů, názvů alb a žánrů. Pokud ve vašich tagech najde některé ze slov nebo znaků uvedených níže, vytvoří pro každou položku jednotlivé výpisy. Pokud například do seznamu níže vložíte středník, skladba s tagem interpreta „J. S. Bach;Michael Tilson Thomas“ se objeví v oblasti interpretů pro „J. S. Bach“ i „Michael Tilson Thomas“. Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. DA Lyrion Music Server kan udtrække flere kunstnere, albumtitler og genre fra mærkerne i dine musikfiler. Hvis Lyrion Music Server finder nogle af de ord eller symboler nedenunder, vil der blive oprettet individuelle oversiger for hvert element. Hvis du for eksempel har indtastet et semikolon i listen nedenunder, vil numre med kunstnermærke "J. S. Bach;Michael Tilson Thomas" medføre at der oprettes to kunstnere, "J. S. Bach" og "Michael Tilson Thomas". Ændring af denne indstilling medfører at dit musikbibliotek bliver genindlæst. DE Lyrion Music Server kann mehrere Interpreten, Albumtitel und Stilrichtungen in den Tags von Musikdateien erkennen. Findet Lyrion Music Server folgende Wörter oder Zeichen in den Tags, wird für jeden Eintrag eine andere Liste erstellt. Beispiel: Wenn Sie einen Strichpunkt als Trennzeichen definieren, wird ein Titel mit dem Interpreten-Tag 'J. S. Bach;Michael Tilson Thomas' sowohl unter 'J. S. Bach' als auch 'Michael Tilson Thomas' aufgelistet. Wenn Sie diese Einstellung ändern, wird die Musiksammlung erneut durchsucht. EN Lyrion Music Server can extract multiple artist, album titles and genres from the tags inside your music files. If it finds any of the words or characters below in your tags, it will create individual listings for each item. For example, if you put a semicolon in the list below, a song with an artist tag of "J. S. Bach;Michael Tilson Thomas" will appear in the artists area for both "J. S. Bach" and "Michael Tilson Thomas". Changing this setting will start a rescan of your music library. @@ -9210,7 +9210,7 @@ SETUP_ARTISTS_BROWSE_MODES SV Bläddra efter artister SETUP_ARTISTS_BROWSE_MODES_DESC - CS Zvolte, zda chcete použít jeden konfigurovatelný seznam interpretů, nebo dva seznamy „Interpreti alba" a „Všichni interpreti". „Interpreti alba" je seznam, ve kterém je Interpret alba jediným interpretem na albu nebo interpretem uvedeným v tagu ALBUMARTIST. „Všichni interpreti" je seznam všech interpretů, kteří jsou uvedeni v tagu role přispěvatele (ARTIST, COMPOSER atd.). Jednotný konfigurovatelný seznam interpretů naproti tomu umožňuje určit, které role přispěvatelů mají být součástí nabídky Interpret. + CS Zvolte, zda chcete použít jeden konfigurovatelný seznam interpretů, nebo dva seznamy „Interpreti alba“ a „Všichni interpreti“. „Interpreti alba“ je seznam, ve kterém je Interpret alba jediným interpretem na albu nebo interpretem uvedeným v tagu ALBUMARTIST. „Všichni interpreti“ je seznam všech interpretů, kteří jsou uvedeni v tagu role přispěvatele (ARTIST, COMPOSER atd.). Jednotný konfigurovatelný seznam interpretů naproti tomu umožňuje určit, které role přispěvatelů mají být součástí nabídky Interpret. DA Vælg om du vil bruge en samlet konfigurerbar kunstnerliste, eller to separate lister for Album kunstner og Alle kunstnere. Album kunstner er en liste hvor kunstneren er den eneste på albumet eller hvor kunstneren er specificeret i ALBUMARTIST mærket. Alle kunstnere er en liste hvor samtlige kunstnere som er i en bidragsrolle (ARTIST, COMPOSER etc.) er inkluderet. Hvis du vælger en samlet liste, definerer du selv hvilke roller der skal inkluderes i listen. DE Wählen Sie, ob Sie eine einzelne, konfigurierbare Liste von Interpreten haben wollen, oder eine für Album-Interpreten und eine für Alle Interpreten. Album-Interpreten führt nur Künstler auf, welche für ein Album alleine gespeichert sind, oder im ALBUMARTIST Tag vermerkt sind. Alle Interpreten listet alle Künstler aller Rollen auf (ARTIST, COMPOSER etc.). Die konfigurierbare Interpretenliste lässt Sie festlegen, welche Rollen berücksichtigt werden sollen. EN Choose whether you want to use a single, configurable artists list, or two lists for Album Artists and All Artists. Album Artists is a list where Album Artist is the sole artist on an album or is the artist specified in the ALBUMARTIST tag. All Artists is a list of every artist that appears in a contributor role tag (ARTIST, COMPOSER etc.). The single, configurable list of artists on the other hand lets you define which contributor roles should be part of the Artists menu. @@ -9498,7 +9498,7 @@ SETUP_ENHANCEDHTTP NL Streammethode voor HTTP(S) SETUP_ENHANCEDHTTP_DESC - CS Pokud dojde k selhání připojení HTTP(S) k serveru, Lyrion Music Server ukončí přehrávání. Může se také pokusit o jeho opětovné otevření (Trvalý režim) nebo může ukládat datové proudy (Režim mezipaměti) definované délky (podcasty, jednotlivé skladby) do vyrovnávací paměti v souborech na disku. Ty budou po přehrání datového proudu odstraněny. To může zlepšit spolehlivost u některých serverů, které očekávají stahování skladeb, nikoliv přehrávání datového proudu, a proto uzavírají dlouhá spojení. Zároveň to ale způsobuje větší množství zápisu do souborového systému, což může potenciálně opotřebovat např. karty SD. Pokud máte dostatek místa pro ukládání souborů do vyrovnávací paměti, pak je režim „Mezipaměti" správnou cestou + CS Pokud dojde k selhání připojení HTTP(S) k serveru, Lyrion Music Server ukončí přehrávání. Může se také pokusit o jeho opětovné otevření (Trvalý režim) nebo může ukládat datové proudy (Režim mezipaměti) definované délky (podcasty, jednotlivé skladby) do vyrovnávací paměti v souborech na disku. Ty budou po přehrání datového proudu odstraněny. To může zlepšit spolehlivost u některých serverů, které očekávají stahování skladeb, nikoliv přehrávání datového proudu, a proto uzavírají dlouhá spojení. Zároveň to ale způsobuje větší množství zápisu do souborového systému, což může potenciálně opotřebovat např. karty SD. Pokud máte dostatek místa pro ukládání souborů do vyrovnávací paměti, pak je „Režim mezipaměti“ správnou cestou. DA Når en HTTP(S) forbindelse til en server fejler, vil Lyrion Music Server afslutte afspilningen. LMS kan forsøge at genåbne (Persistent mode) eller buffere (Cache mode) streams af forudefineret længde (podcasts, enkelte numre) til en disk fil. Disse bliver fjernet når afspilningen er afsluttet. Dette kan forbedre pålideligheden med nogle servere som forventer numrene downloades i stedet for at blive streamet og som derfor lukker langvarige forbindelser. Det kan medføre mere skrivning til filsystemet, hvilket potentielt kan forårsage slidtage på f.eks. SD kort. Hvis du har plads nok til at cache filerne, er det den bedste løsning DE Wenn eine HTTP(S)-Verbindung zu einem Server fehlschlägt, beendet Lyrion Music Server die Wiedergabe (Normaler Modus). Er kann auch versuchen, die Verbindung wieder zu öffnen (Persistenter Modus), oder er kann Streams von bestimmter Länge (Podcasts, einzelne Tracks) auf der Festplatte zwischenspeichern (Cache Modus). Diese Dateien werden entfernt, sobald der Stream abgespielt wurde. Dies erhöht die Zuverlässigkeit mit einigen Anbietern, kann aber das Dateisystem zusätzlich belasten (z.B. wenn eine SD Karte verwendet wird). EN When a HTTP(S) connection to a server fails, Lyrion Music Server terminates playback. It can also try to re-open it (Persistent mode) or it can buffer streams (Cache mode) of defined length (podcasts, single tracks) on disk files. These will be removed once the stream has been played. This can improve the reliability with some servers that expect tracks to be downloaded, not streamed and thus close long connections. But it also does cause more writing to the file system, which could potentially wear out e.g. SD cards. If you have enough space for buffering files, then "Cache" mode is the way to go. @@ -9516,7 +9516,7 @@ SETUP_ENABLE_PERSISTENTHTTP NL Persistent-modus SETUP_ENABLE_BUFFEREDHTTP - CS Ukládat datové proudy HTTP(S) do mezipaměti na disk + CS Ukládání datových proudů HTTP(S) na disk (Režim mezipaměti) DA Cache HTTP(S) streams til disk DE HTTP(S) Datenströme zwischenspeichern (Cache Modus) EN Cache HTTP(S) streams on disk @@ -9905,7 +9905,7 @@ SETUP_CORS_ALLOWED_HOSTS SV Tillåtna CORS servrar SETUP_CORS_ALLOWED_HOSTS_DESC - CS Cross-Origin Resource Sharing (CORS) je mechanismus, který používá dodatečné hlavičky HTTP k tomu, aby prohlížeči sdělil, že webová aplikace spuštěná v jednom původu (doméně) má povolení k přístupu k vybraným prostředkům ze serveru v jiném původu.

    Zadejte čárkou oddělený seznam názvů hostitelů, kterým chcete poskytnout přístup k Lyrion Music Serveru. Položky musí obsahovat protokol (např. „http"), plný název hostitele („www.example.com") a číslo portu, pokud je toto číslo nestandardní. Ve většině případů by mělo stačit něco jako „https://www.example.com". + CS Cross-Origin Resource Sharing (CORS) je mechanismus, který používá dodatečné hlavičky HTTP k tomu, aby prohlížeči sdělil, že webová aplikace spuštěná v jednom původu (doméně) má povolení k přístupu k vybraným prostředkům ze serveru v jiném původu.

    Zadejte čárkou oddělený seznam názvů hostitelů, kterým chcete poskytnout přístup k Lyrion Music Serveru. Položky musí obsahovat protokol (např. „http“), plný název hostitele („www.example.com“) a číslo portu, pokud je toto číslo nestandardní. Ve většině případů by mělo stačit něco jako „https://www.example.com“. DA Cross-Origin Resource Sharing (CORS) er en mekaniske som gør det muligt for en web-browser at tillade en web-server i et domæne at anvende web-ressourcer fra en server i et andet domæne.

    Definér en komma-separeret liste med web-servere som tillades at få adgang til din Lyrion Music Server. Hver server skal have en protokol (f.eks. "http") angivet, samt hele servernavnet ("www.example.com") og et port nummer, hvis det er non-standard. Normalt vil noget i retning af "https://www.example.com" være tilstrækkeligt. DE Cross-Origin Resource Sharing (CORS) ist ein Mechanismus, der Webbrowsern oder auch anderen Webclients Cross-Origin-Requests ermöglicht.

    Definieren Sie eine Komma separierte Liste von Hostnamen, die auf ihren Lyrion Music Server zugreifen dürfen. Es müssen Protokoll (z.B. "http"), voller Hostname ("www.example.com"), und allenfalls Port angegeben werden, wenn letzterer nicht dem Standard entspricht. In den meisten Fällen reicht ein Eintrag wie "https://www.example.com". EN Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin.

    Enter a comma separated list of hostnames you want to give access to your Lyrion Music Server. The entries need to have the protocol (eg. "http"), full host name ("www.example.com"), plus the port number, should the latter be non-standard. In most cases something like "https://www.example.com" should be good enough. @@ -9933,7 +9933,7 @@ SETUP_CSRFPROTECTIONLEVEL ZH_CN CSRF保护程度 SETUP_CSRFPROTECTIONLEVEL_DESC - CS Jako ochranu proti útokům typu "Podvržení požadavku mezi různými stránkami (Cross Site Request Forgery - CSRF)" Lyrion Music Server používá speciální kontrolu požadavků HTTP na funkce, které mohou provádět změny ve vašem systému nebo manipulovat se seznamy skladeb nebo přehrávači. Můžete si zvolit úroveň kontroly, kterou bude Lyrion Music Server používat. Výchozí úroveň je Žádná. Další podrobnosti naleznete v nápovědě. + CS Jako ochranu proti útokům typu „Podvržení požadavku mezi různými stránkami (Cross Site Request Forgery - CSRF)“ Lyrion Music Server používá speciální kontrolu požadavků HTTP na funkce, které mohou provádět změny ve vašem systému nebo manipulovat se seznamy skladeb nebo přehrávači. Můžete si zvolit úroveň kontroly, kterou bude Lyrion Music Server používat. Výchozí úroveň je Žádná. Další podrobnosti naleznete v nápovědě. DA Som en beskyttelse mod såkaldte CSRF-sikkerhedstrusler (Cross Site Request Forgery, dvs. falske krydshenvisninger), undersøger Lyrion Music Server alle HTTP-anmodninger om funktioner som kan ændre dit system eller dine afspilningslister, ekstra grundigt. Du kan selv indstille hvilket sikkerhedsniveau Lyrion Music Server skal benytte. Standard er Ingen. Der er flere oplysninger i hjælpen. DE Zum Schutz gegen 'Cross Site Request Forgery' (CSRF)-Sicherheitsrisiken prüft Lyrion Music Server HTTP-Anforderungen auf Funktionen, die das System ändern oder Wiedergabelisten oder Player beeinträchtigen können. Sie können die Schutzstufe für Lyrion Music Server festlegen. Standardmäßig ist kein Wert festgelegt. Weitere Informationen finden Sie in der Hilfe. EN To protect against "Cross Site Request Forgery" (CSRF) security threats, Lyrion Music Server applies special scrutiny to HTTP requests for functions that can make changes to your system or manipulate playlists or players. You may choose the level of scrutiny for Lyrion Music Server to use. The default is None. See Help Section for more details. @@ -9971,7 +9971,7 @@ SETUP_INSECURE_HTTPS2 NL Uitschakelen van certificaatverificatie bij HTTPS verbindingen SETUP_INSECURE_HTTPS_DESC - CS Povolením možnosti „Nezabezpečené HTTPS" se vypne ověřování certifikátů, pokud Lyrion Music Server funguje jako klient HTTPS. Povolení této možnosti se nedoporučuje! Vypnutí ověřování certifikátů je špatnou praxí, ale za určitých okolností může být nezbytné, např. když nelze aktualizovat knihovny. + CS Povolením možnosti „Nezabezpečené HTTPS“ se vypne ověřování certifikátů, pokud Lyrion Music Server funguje jako klient HTTPS. Povolení této možnosti se nedoporučuje! Vypnutí ověřování certifikátů je špatnou praxí, ale za určitých okolností může být nezbytné, např. když nelze aktualizovat knihovny. DA Aktivering af "Usikker HTTPS" betyder, at certifikat verifikation deaktiveres når Lyrion Music Server er en HTTPS klient. Aktivering af denne option anbefales ikke! Grundlæggende bør certifikater altid verificeres, men det kan være nødvendigt under visse omstændigheder, f.eks. hvis et onlinebibliotek ikke kan opdateres. DE "Unsicheres HTTPS" bedeutet, dass Lyrion Music Server Zertifikate von entfernten Servern nicht mehr auf ihre Gültigkeit überprüft. Es wird nicht empfohlen, diese Option zu aktivieren!. Grundsätzlich sollten Zertifikate immer überprüft werden. Allerdings kann dies unter Umständen fehlschlagen, wenn etwa eine Bibliothek nicht aktualisiert werden kann. EN Enabling "Insecure HTTPS" switches off certificate verification when Lyrion Music Server acts as an HTTPS client. Enabling this option is discouraged! It is bad practice to disable certificate verification, but can be necessary under certain circumstances, eg. when the libraries can't be updated. @@ -10143,7 +10143,7 @@ SETUP_BAD_VALUE ZH_CN 指定价值无效: %s SETTINGS_INVALIDVALUE - CS Neplatná hodnota „%s" pro %s + CS Neplatná hodnota „%s“ pro %s DA Værdien "%s" for %s er ugyldig DE "%s" ist kein gültiger Wert für %s EN Invalid value "%s" for %s @@ -10215,7 +10215,7 @@ SETUP_AUTHORIZE ZH_CN 密码保护 SETUP_AUTHORIZE_DESC - CS Můžete si zvolit ochranu heslem pro dálkové ovládání Lyrion Music Serveru. Zvolte „Ochrana heslem" níže a zadejte uživatelské jméno a heslo, potom klikněte na Změnit. Od tohoto okamžiku budete muset při používání dálkového ovládání Lyrion Music Serveru zadávat toto uživatelské jméno a heslo ve svém webovém prohlížeči. + CS Můžete si zvolit ochranu heslem pro dálkové ovládání Lyrion Music Serveru. Zvolte „Ochrana heslem“ níže a zadejte uživatelské jméno a heslo, potom klikněte na Změnit. Od tohoto okamžiku budete muset při používání dálkového ovládání Lyrion Music Serveru zadávat toto uživatelské jméno a heslo ve svém webovém prohlížeči. DA Du kan vælge at beskytte adgangen til Lyrion Music Servers fjernbetjening med en adgangskode. Vælg Beskyt med adgangskode, angiv et brugernavn og en adgangskode, og klik på Skift. Når du herefter ønsker at bruge Lyrion Music Servers fjernbetjening, skal du angive brugernavnet og adgangskoden i browseren. DE Sie können Lyrion Music Server Remote Control mit einem Kennwort schützen. Klicken Sie unten auf 'Kennwortschutz', geben Sie einen Benutzernamen und ein Kennwort ein, und klicken Sie auf 'Ändern'. Wenn Sie dann Lyrion Music Server Remote Control aufrufen, müssen Sie diesen Benutzernamen und das Kennwort eingeben. EN You can choose to password protect Lyrion Music Server Remote Control. Choose "Password protection" below and enter a username and password, then click Change. From that point on when you use Lyrion Music Server Remote Control, you'll need to enter this username and password in your web browser. @@ -10400,7 +10400,7 @@ SETUP_RELEASE_TYPES_INCLUDE PT Tipos de lançamentos para serem incluídos na Lista de albuns SETUP_RELEASE_TYPES_DESC - CS Můžete určit, jaké typy vydání chcete zahrnout do seznamu alb (viz MusicBrainz). Pokud vydání nemá definovaný typ, předpokládá se „Album". Alba nelze z tohoto seznamu vyloučit. + CS Můžete určit, jaké typy vydání chcete zahrnout do seznamu alb (viz MusicBrainz). Pokud vydání nemá definovaný typ, předpokládá se „Album“. Alba nelze z tohoto seznamu vyloučit. DA Du kan specificere hvilke udgivelsestypper som ønskes inkluderet i Album listen (se MusicBrainz). Hvis en udgivelse ikke har en typespecifikation, bliver "Album" antaget og de kan ikke bortfiltreres fra listen. DE Sie können angeben, welche Veröffentlichungstypen (siehe MusicBrainz) in der Albenliste mit aufgeführt werden sollen. Falls für eine Veröffentlichung kein Typ definiert wurde, so wird "Album" angenommen. Diese können nicht ausgeschlossen werden. EN You can specify what release types you want to include in the albums list (see MusicBrainz). If a release doesn't have a type defined, "Album" is assumed. Albums can't be excluded from that list. @@ -10420,7 +10420,7 @@ SETUP_RELEASE_TYPES_COMPOSER_ALBUM_GROUP_OPTIONS PT Opções para Compositor do album SETUP_RELEASE_TYPES_COMPOSER_ALBUM_GROUP_OPTIONS_DESC - CS Vytvořit skupinu Alba skladatele – vždy, nikdy nebo pro určité žánry. Pokud kvůli tomuto nastavení nejsou některé skladatelské role zahrnuty do skupiny Alba skladatele, zobrazí se místo toho v samostatné skupině „Kompozice", která bude obsahovat seznam jednotlivých skladeb, nikoli alb. Seznam žánrů by měl být oddělen čárkou. + CS Vytvořit skupinu Alba skladatele – vždy, nikdy nebo pro určité žánry. Pokud kvůli tomuto nastavení nejsou některé skladatelské role zahrnuty do skupiny Alba skladatele, zobrazí se místo toho v samostatné skupině „Kompozice“, která bude obsahovat seznam jednotlivých skladeb, nikoli alb. Seznam žánrů by měl být oddělen čárkou. DA Opret en Komponistalbum gruppe - altid, aldrig, eller for bestemte genrer. Når visse komponist roller ikke inkluderes i Composer Albums pga. denne indstilling, vil de i stedet dukke op i en separat "Compositions" gruppe, som lister individuelle numre, ikke albums. Listen over genrer skal være komma-separeret. EN Create a Composer Albums group - always, never, or for certain genres. If due to this setting, certain composer roles are not included in the Composer Albums group, they will appear in a separate "Compositions" group instead, which will list individual tracks, not albums. The genre list should be comma separated. FR Créer un groupe "Albums du compositeur" : toujours, jamais ou pour des genres spécifiques. Si, en raison de ce paramètre, certaines œuvres du compositeur ne sont pas incluses dans le groupe "Albums du compositeur", elles apparaîtront à la place dans un groupe "Compositions" distinct, qui répertoriera les morceaux individuels, pas les albums. (Par exemple, un morceau avec un tag "ARTIST" différent du tag "COMPOSER" se retrouvera dans le groupe "Compositions".) Les genres de la liste doivent être séparés par des virgules. @@ -10450,7 +10450,7 @@ SETUP_RELEASE_TYPES_COMPOSER_ROLE_GROUPING_1 ES Crear siempre un grupo de Álbum de compositor SETUP_RELEASE_TYPES_COMPOSER_ROLE_GROUPING_2 - CS Vytvoření skupiny Skladatelské album pro „Moje žánry pro díla a skladatelská alba" (výše) + CS Vytvoření skupiny Skladatelské album pro „Moje žánry pro díla a skladatelská alba“ (výše) DA Opret en komponistalbumgruppe for "Mine genrer til værker og komponistalbums" (ovenfor) DE Erstellen einer Komponistenalbengruppe für "Genres für Werke und Komponistenalben" (oben) EN Create a Composer Album group for "My work and composer album genres" (above) @@ -10480,7 +10480,7 @@ SETUP_IGNORE_RELEASE_TYPES_1 PT Ignore o tipo de lançamento dos albuns SETUP_CLEANUP_RELEASE_TYPES - CS Zkusit automaticky rozpoznat EP a singly, pokud je informace o typu vydání „album" nebo chybí. + CS Zkusit automaticky rozpoznat EP a singly, pokud je informace o typu vydání „album“ nebo chybí. DA Forsøg at genkende EPs og singler automatisk, når udgivelsestype informationen er "Album" eller mangler. DE Versuchen, EPs und Singles ohne definierten Veröffentlichungstypen, oder die als Album deklariert sind, selber zu erkennen. EN Try to recognize EPs and singles automatically when release type information is "album" or is missing. @@ -10540,7 +10540,7 @@ SETUP_GROUPDISCS ZH_CN 组合光碟 SETUP_GROUPDISCS_DESC - CS Můžete zadat, aby vícediskové sady byly považovány za jedno album (s jedním názvem) nebo za více alb, každé se svým názvem pro disk, například „Název alba (disk 2 ze 3)". Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. + CS Můžete zadat, aby vícediskové sady byly považovány za jedno album (s jedním názvem) nebo za více alb, každé se svým názvem pro disk, například „Název alba (disk 2 ze 3)“. Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. DA Du kan angive om album med flere cd'er skal opfattes som et enkelt album (med et enkelt navn), eller som flere album med et unikt navn for hver cd, fx Albumtitel (cd 1 af 3). Hvis du ændrer denne indstilling, bliver dit musikbibliotek gennemsøgt igen. DE Sie können angeben, ob mehrere CDs eines Albums als ein Album (unter dem gleichen Namen) oder als getrennte Alben (z.B. 'Albumtitel (CD 1 von 2)' angezeigt werden sollen. Wenn Sie diese Einstellung ändern, wird die Musiksammlung erneut durchsucht. EN You can specify if multiple disc sets are treated as a single album (with a single name) or as multiple albums, each with a unique name per disc, for example "Album Title (Disc 2 of 3)". Changing this setting will start a rescan of your music library. @@ -10608,7 +10608,7 @@ SETUP_SIGNOUT NL Afmelden SETUP_NO_JAVASCRIPT - CS Před přístupem k Lyrion Music Serveru se prosím ujistěte, že používáte poslední prohlížeč (Firefox®, Apple Safari®, Microsoft® Internet Explorer 10, Opera 25 nebo vyšší), a že je na vašem prohlížeči povolen JavaScript. Alternativně můžete používat jednodušší vzhled, např.Klasický. + CS Před přístupem k Lyrion Music Serveru se prosím ujistěte, že používáte poslední prohlížeč (Firefox®, Apple Safari®, Microsoft® Internet Explorer 10, Opera 25 nebo vyšší), a že je na vašem prohlížeči povolen JavaScript. Alternativně můžete používat jednodušší vzhled, např.Classic. DA Du skal bruge en forholdsvis ny browser for at få adgang til Lyrion Music Server (Firefox®, Apple Safari®, Microsoft® Internet Explorer 10+, Opera 25 eller senere), og JavaScript skal være aktiveret i browseren. Alternativt kan du benytte et enklere layout, fx Klassisk. DE Für den Zugriff auf Lyrion Music Server benötigen Sie eine aktuelle Version eines Browsers (Firefox®, Apple Safari®, Microsoft® Internet Explorer 10, Opera 25 oder höher). Außerdem muss im Browser JavaScript aktiviert sein. Sie können auch eine einfachere Benutzeroberfläche wie Classic wählen. EN In order to access Lyrion Music Server, please make sure you are using a recent browser (Firefox®, Apple Safari®, Microsoft® Internet Explorer 10, Opera 25 or later), and JavaScript is enabled in your browser. Alternatively you can use a simpler skin, such as Classic. @@ -15268,7 +15268,7 @@ FILENAME_WARNING SV Namnet innehåller otillåtna tecknet. Ändra namnet. RENAME_WARNING - CS Název, který jste zvolili, byl již vybrán. Zvolte prosím pro svůj seznam skladeb jiný název nebo zaškrtnutím „Potvrdit přepsání" přepište stávající seznam skladeb. + CS Název, který jste zvolili, byl již vybrán. Zvolte prosím pro svůj seznam skladeb jiný název nebo zaškrtnutím „Potvrdit přepsání“ přepište stávající seznam skladeb. DA Navnet du angav, er allerede i brug. Giv afspilningslisten et andet navn, eller vælg at overskrive den eksisterende. DE Dieser Name ist bereits vorhanden. Wählen Sie einen anderen für die Wiedergabeliste oder aktivieren Sie 'Überschreiben bestätigen'. EN The name you chose is already taken. Please choose another name for your playlist, or check 'confirm overwrite' to replace your existing playlist. @@ -15288,7 +15288,7 @@ RENAME_WARNING ZH_CN 您选择的名字已被使用。请选择其它的播放表名字,或选择《确定重写》替换您现有的播放表。 DELETE_WARNING - CS Jste si jisti, že je chcete odstranit? Zaškrtněte políčko „Potvrdit odstranění", chcete-li odstranit svůj seznam skladeb. + CS Jste si jisti, že je chcete odstranit? Zaškrtněte políčko „Potvrdit odstranění“, chcete-li odstranit svůj seznam skladeb. DA Vil du slette? Du skal markere "bekræft sletning" for at slette afspilningslisten. DE Wirklich löschen? Aktivieren Sie 'Löschen bestätigen', um die Wiedergabeliste zu löschen. EN Are you sure you want to delete? Check 'confirm delete' to delete your playlist. @@ -15961,7 +15961,7 @@ DEBUG_DEFAULT SV Återställ loggningsinställningar SETUP_GROUP_DEBUG_DESC - CS Lyrion Music Server má řadu nastavení protokolování, která lze použít pro zapsání podrobných informací o provozu serveru a prohledávání. Každá kategorie protokolů má určitou závažnost pro protokolování. Volba „Ladění" je nejvíce informativní, volba „Vypnuto" nejméně. + CS Lyrion Music Server má řadu nastavení protokolování, která lze použít pro zapsání podrobných informací o provozu serveru a prohledávání. Každá kategorie protokolů má určitou závažnost pro protokolování. Volba „Ladění“ je nejvíce informativní, volba „Vypnuto“ nejméně. DA Lyrion Music Server har en række indstillinger til logføring som kan bruges til at registrere detaljerede oplysninger om serveren og søgninger. Hver logføringskategori kan indstilles til at registrere flere eller færre oplysninger. Fejlsøgning giver flest detaljer og Fra ingen. DE Lyrion Music Server enthält eine Reihe von Protokolleinstellungen, mit denen Sie umfangreiche Angaben über Lyrion Music Server- und Scanner-Vorgänge aufzeichnen können. Jede Protokollkategorie unterliegt einer Begrenzung in der Protokollierung ("Debug" mit der höchsten Wortanzahl, "Off" mit der niedrigsten). EN Lyrion Music Server has a number of logging settings that can be used to record detailed information about server and scanner operation. Each logging category has a severity for logging. With "Debug" being the most verbose, and "Off" being the least. @@ -17001,7 +17001,7 @@ NEED_PLAYLIST_PATH ZH_CN 您必须指定存有播放表目录的路径。 CSRF_ERROR_INFO - CS Chcete-li si tuto adresu URL vyžádat ze záložky/oblíbené stránky nebo jiným způsobem než pomocí odkazu z webového rozhraní serveru Lyrion Music Server, musíte použít adresu URL s bezpečnostním parametrem \"cauth\". Pokud jste tuto chybu obdrželi při následování odkazu z webového rozhraní serveru Lyrion Music Server, měli byste se ujistit, že software vašeho webového prohlížeče (včetně proxy serverů a softwaru pro ochranu soukromí a spywaru) umožňuje odesílání hlaviček \"Referer\". Níže je uvedena příslušná adresa URL pro adresu URL, na které jste se pokusili přejít. + CS Chcete-li si tuto adresu URL vyžádat ze záložky/oblíbené stránky nebo jiným způsobem než pomocí odkazu z webového rozhraní serveru Lyrion Music Server, musíte použít adresu URL s bezpečnostním parametrem „cauth“. Pokud jste tuto chybu obdrželi při následování odkazu z webového rozhraní serveru Lyrion Music Server, měli byste se ujistit, že software vašeho webového prohlížeče (včetně proxy serverů a softwaru pro ochranu soukromí a spywaru) umožňuje odesílání hlaviček „Referer“. Níže je uvedena příslušná adresa URL pro adresu URL, na které jste se pokusili přejít. DA Hvis du vil åbne siden som denne adresse henviser til, fra et bogmærke/en favorit, eller på andre måder end ved at klikke på et link fra Lyrion Music Servers webbaserede brugerflade, skal adressen rumme sikkerhedsparameteren "cauth". Hvis denne fejl opstod da du klikkede på et link i Lyrion Music Servers webbaserede brugerflade, skal du sikre dig at din browser (herunder indstillinger for proxyservere og antispywareprogrammer m.v.) tillader headere med henvisninger (Referer). Nedenfor er den rigtigt konfigurerede adresse som du forsøgte at få adgang til. DE Damit Sie diese URL aus einem Favoriten/Lesezeichen oder einem anderen Verfahren als aus der Lyrion Music Server-Web-Benutzeroberfläche aufrufen können, müssen Sie eine URL mit dem Sicherheitsparameter 'cauth' verwenden. Trat dieser Fehler beim Klicken auf einen Link in der Lyrion Music Server-Web-Benutzeroberfläche auf, sollten Sie prüfen, ob der Browser (sowie Proxyserver und Spyware-/Firewall-Software) das Senden von 'Referer'-Kopfzeilen zulässt. Dies ist die korrekte URL für die gewünschte Verbindung: EN In order to request this URL from a Bookmark/Favorite, or some means other than following a link from the Lyrion Music Server web interface, you will need to use a URL with a \"cauth\" security parameter. If you received this error when following a link from the Lyrion Music Server web interface, you will want to make sure your web browser software (including proxy servers and spyware/privacy software) is allowing \"Referer\" headers to be sent. Below is the appropriate URL for the URL you attempted. @@ -17020,7 +17020,7 @@ CSRF_ERROR_INFO ZH_CN 如果要从Bookmark/Favorite或其他方法请求这URL(从Lyrion Music Server网界面跟随链接除外),您将需要使用以\"cauth \"为安全参数的URL。如果您从Lyrion Music Server网界面跟随链接而出现错误,您需要确定您的浏览器软件(包括网代理伺服器和spyware/privacy软件)允许发送\"Referer\"倒坠。下面是您试图访问的URL的正确的URL。 CSRF_ERROR_MEDIUM - CS

    Jelikož je vaše úroveň ochrany CSRF nastavena na „STŘEDNÍ", můžete použít stejnou hodnotu ";cauth=" pro libovolnou adresu URL; to znamená, že byste měli být opatrnější, s kým sdílíte své adresy URL.

    + CS

    Jelikož je vaše úroveň ochrany CSRF nastavena na „Střední“, můžete použít stejnou hodnotu „;cauth=“ pro libovolnou adresu URL; to znamená, že byste měli být opatrnější, s kým sdílíte své adresy URL.

    DA

    Da CSRF-beskyttelsesnivauet er sat til Mellem, kan du anvende den samme værdi for cauth= i alle internetadresser. Det betyder at du skal være forsigtig med hvem du deler dine adresser med.

    DE

    Da Ihr CSRF-Schutzniveau auf 'Medium' (Mittel) gesetzt ist, können Sie denselben ';cauth' Wert für beliebige URLs verwenden. Dies bedeutet aber, dass Sie beim Austausch dieser URLs vorsichtig vorgehen sollten.

    EN

    Because your CSRF protection level is set at 'MEDIUM', you can use the same ";cauth=" value for any URL; this means you should be more careful who you share your URLs with.

    @@ -18163,7 +18163,7 @@ RADIO_TUNEIN_NOW ZH_CN 现在调谐 RADIO_TUNEIN_DESC - CS Pokud již znáte adresu URL stanice, kterou chcete poslouchat, zadejte ji zde a klikněte na tlačítko „Naladit". Můžete zadat adresu URL buď samotného radiového proudu (např. http://62.49.59.50:8000) nebo souboru seznamu skladeb, který k proudu odkazuje (např. http://www.hitzradio.com/hitzradio.pls). + CS Pokud již znáte adresu URL stanice, kterou chcete poslouchat, zadejte ji zde a klikněte na tlačítko „Naladit“. Můžete zadat adresu URL buď samotného radiového proudu (např. http://62.49.59.50:8000) nebo souboru seznamu skladeb, který k proudu odkazuje (např. http://www.hitzradio.com/hitzradio.pls). DA Hvis du allerede kender stationens internetadresse, kan du angive den her og klikke på Stil ind. Du kan angive adressen til selve radiostreamen (fx http://62.49.59.50:8000) eller til en afspilningsliste der henviser til den (fx http://www.hitzradio.com/hitzradio.pls). DE Falls Sie die URL eines Internet-Radiosenders bereits kennen, können Sie diese hier eingeben und auf 'Sender wählen' klicken. Sie können entweder die URL des Datenstroms (z.B. http://62) oder die Wiedergabeliste, die auf den Datenstrom zeigt (z.B. http://www.hitzradio.com/hitzradio.pls) eingeben. EN If you already know the URL of the station you would like to listen to, enter it here and click on the "Tune In" button. You can enter the URL of either the radio stream itself (e.g. http://62.49.59.50:8000) or the playlist file that is pointing to the stream (e.g. http://www.hitzradio.com/hitzradio.pls). @@ -20004,7 +20004,7 @@ SETUP_VARIOUSARTISTS ZH_CN 合辑 SETUP_VARIOUSARTISTAUTOIDENTIFICATION_DESC - CS Můžete si zvolit, aby se sbírky alb zobrazily společně pod „Různí interpreti" nebo aby se zobrazily pod každým interpretem ve sbírce. + CS Můžete si zvolit, aby se sbírky alb zobrazily společně pod „Různí interpreti“ nebo aby se zobrazily pod každým interpretem ve sbírce. DA Du kan vælge at vise kompilationsalbum samlet under Diverse kunstnere, eller under hver kunstner på kompilationen. DE Sie können Kompilationen (Alben mit mehreren Interpreten) zusammen unter 'Diverse Interpreten' aufführen oder die einzelnen Lieder unter den einzelnen Interpreten. EN You can choose to have compilation albums appear together under "Various Artists" or have them appear under each artist in the compilation. @@ -20058,7 +20058,7 @@ SETUP_VARIOUSARTISTAUTOIDENTIFICATION_0 ZH_CN 把合辑发表在个别艺人中 SETUP_VARIOUSARTISTSSTRING_DESC - CS Pokud jsou sbírky seskupeny dohromady, zobrazí se standardně pod názvem „Různí interpreti". Tento název můžete změnit níže. + CS Pokud jsou sbírky seskupeny dohromady, zobrazí se standardně pod názvem „Různí interpreti“. Tento název můžete změnit níže. DA Når numrene på kompilationsalbum grupperes, vises de som standard under Diverse. Du kan ændre navnet nedenfor. DE Gruppierte Kompilationen werden standardmäßig unter 'Diverse Interpreten' angezeigt. Sie können diesen Namen unten ändern. EN When compilation albums are grouped together, they appear under "Various Artists" by default. You can change that name below. @@ -20153,7 +20153,7 @@ UNSYNC ZH_CN 非同步 SETUP_USEBANDASALBUMARTIST_DESC - CS Alba obsahující skladby, které jsou označené tagem skupiny, mohou být u tohoto alba uvedena buď pod jménem skupiny nebo s ostatními interprety. Tag skupiny se nazývá také TPE2 a v některých programech se může zobrazovat jako „Interpret alba". + CS Alba obsahující skladby, které jsou označené tagem skupiny, mohou být u tohoto alba uvedena buď pod jménem skupiny nebo s ostatními interprety. Tag skupiny se nazývá také TPE2 a v některých programech se může zobrazovat jako „Interpret alba“. DA Album der indeholder numre som er mærket med navnet på et band, kan vises under dette bands navn eller sammen med de andre kunstnere som optræder på albummet. Bandmærket kaldes også TPE2 og vises som "album artist" i nogle programmer. DE Alben, die Lieder enthalten, die mit einem Band-Tag versehen sind, können unter diesem Interpreten oder bei den übrigen Interpreten des Albums aufgeführt werden. Der Band-Tag (auch TPE2 genannt) wird in bestimmten Anwendungen auch als 'Album Artist' (Albuminterpret) bezeichnet. EN Albums that contain songs that are tagged with a band may be listed under that band name or with the other artists for that album. The band tag is also known as TPE2 and may appear as the "album artist" in some software. @@ -20170,7 +20170,7 @@ SETUP_USEBANDASALBUMARTIST_DESC SV Album som innehåller låtar som taggats med ett bandnamn kan listas under bandnamnet eller tillsammans med de andra artisterna på albumet. Bandtaggen kallas också TPE2, och visas i vissa program som Albumartist. SETUP_USETPE2ASALBUMARTIST_DESC - CS Formát MP3 tagů neposkytuje standardní způsob, jak definovat Interpreta alba. Některé nástroje pro MP3 tagy používají pro Interpreta alba pole TPE2 (iTunes, Winamp, Windows Media Player), jiné je mohou používat pro zamýšlený význam „Skupina/orchestr". Zvolte význam, který má Lyrion Music Server používat. Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. + CS Formát MP3 tagů neposkytuje standardní způsob, jak definovat Interpreta alba. Některé nástroje pro MP3 tagy používají pro Interpreta alba pole TPE2 (iTunes, Winamp, Windows Media Player), jiné je mohou používat pro zamýšlený význam „Skupina/orchestr“. Zvolte význam, který má Lyrion Music Server používat. Změna tohoto nastavení spustí nové prohledání vaší hudební knihovny. DA MP3-mærkeformatet er en standardiseret metode til at definere en kunstner og dennes album. Nogle programmer til at håndtere mp3-mærker benytter feltet TPE2 til Albumkunstner (iTunes, Winamp, Windows Media Player) mens andre benytter det til den intenderede betydning af Band/orkester. Du skal vælge hvilken model der skal bruges i Lyrion Music Server. Hvis du ændrer indstillingen, bliver hele musikbiblioteket gennemsøgt igen. DE Das MP3-Tag-Format bietet keine Standardmöglichkeit zum Definieren des Interpreten des Albums. Manche MP3-Anwendungen (iTunes, Winamp, Windows Media Player) nutzen das Feld TPE2 für den Interpreten des Albums, andere nutzen es für den eigentlichen Zweck (Band/Orchester). Wählen Sie die gewünschte Bedeutung. Wenn Sie diese Einstellung ändern, wird die Musiksammlung erneut durchsucht. EN The MP3 tag format does not provide a standard way of defining an Album Artist. Some MP3 tagging tools use the TPE2 field for Album Artist (iTunes, Winamp, Windows Media Player) while others may use it for the intended meaning of "Band/orchestra". Select the meaning you would like Lyrion Music Server to use. Changing this setting will start a rescan of your music library. @@ -20399,7 +20399,7 @@ ARTWORK ZH_CN 封面图 ONE_BY_ONE_ARTWORK - CS Obaly alb „jeden po druhém" + CS Obaly alb „jeden po druhém“ DA Albumcover 1-til-1 DE Plattenhüllen einzeln EN 1-by-1 Artwork @@ -21426,7 +21426,7 @@ SETUP_WORDCLOCKOUTPUT ZH_CN S/PDIF输出产生字形时钟信息 SETUP_WORDCLOCKOUTPUT_DESC - CS Při použití digitálních vstupů může Transporter být nadřízeným generátorem taktu („clock master") a vysílat taktovací signál (word clock) do svých výstupů S/PDIF. Tuto funkci je nutno povolit pouze tehdy, když zdrojové zařízení zajišťuje vstup taktovacího signálu (word clock) a kabel je připojen. + CS Při použití digitálních vstupů může Transporter být nadřazeným generátorem taktu („Clock Master“) a vysílat taktovací signál („Word Clock“) do svých výstupů S/PDIF. Tuto funkci je nutno povolit pouze tehdy, když zdrojové zařízení zajišťuje vstup taktovacího signálu („Word Clock“) a kabel je připojen. DA Ved brug af de digitale indgange, kan Transporter virke som clock-master og sende et såkaldt Wordclock-signal via S/PDIF-udgangene. Denne funktion må kun aktiveres hvis kilde-enheden sender et Wordclock-signal, og kablet er forbundet. DE Wenn die digitalen Eingänge verwendet werden, kann Transporter das Signal direkt durchschleifen oder an den S/PDIF-Ausgängen ein Word Clock-Signal erzeugen. EN When using the digital inputs, Transporter can be the clock master, and transmit a word clock signal on its S/PDIF outputs. This feature must only be enabled if the source device provides a word clock input and the cable is connected. @@ -21442,7 +21442,7 @@ SETUP_WORDCLOCKOUTPUT_DESC SV När du använder de digitala ingångarna kan Transporter användas som huvudklocka. En word clock-signal sänds då ut via S/PDIF-utgångarna på Transporter. Aktivera den här funktionen endast om källenheten ger en word clock-insignal och kabeln är ansluten. WORDCLOCKOUTPUT_DISABLED - CS Výstup taktovacího signálu (Word clock) je vypnutý (zdroj je nadřízený) + CS Výstup taktovacího signálu (Word Clock) je vypnutý (zdroj je nadřazený) DA Wordclock-udgangssignal er deaktiveret (kilden er master) DE Wordclock-Ausgabe ist deaktiviert (Quelle ist Master) EN Word clock output is disabled (Source is master) @@ -21458,7 +21458,7 @@ WORDCLOCKOUTPUT_DISABLED SV Word clock-utsignal avaktiverad. (Källan styr.) WORDCLOCKOUTPUT_ENABLED - CS Výstup taktovacího signálu (Word clock) je povolen (Transporter je nadřazený) + CS Výstup taktovacího signálu (Word Clock) je povolen (Transporter je nadřazený) DA Wordclock-udgangssignal er aktiveret (Transporter er master) DE Wordclock-Ausgabe aktiviert (Transporter ist Master) EN Word clock output is enabled (Transporter is master) @@ -21698,7 +21698,7 @@ SETUP_ANALOGOUTMODE SV Utgång SETUP_ANALOGOUTMODE_DESC - CS Zvolte funkci portu sluchátka/sub out Boomu. Volba Sluchátka vypne vnitřní reproduktory. Volba „Vždy zapnuto" ponechá vnitřní reproduktory zapnuté i při připojených sluchátkách. + CS Zvolte funkci portu sluchátka/sub out Boomu. Volba Sluchátka vypne vnitřní reproduktory. Volba „Vždy zapnuto“ ponechá vnitřní reproduktory zapnuté i při připojených sluchátkách. DA Vælg hvad der skal ske når noget sluttes til udgangsstikket til hovedtelefoner/subwoofer på Boom. Når der tilsluttes hovedtelefoner, bliver de indbyggede højtalere slået fra. Hvis du vælger Altid slået til, forbliver de indbyggede højtalere slået til, også selvom der tilsluttes hovedtelefoner. DE Wählen Sie die Funktion des Kopfhörer/Sub Out-Anschlusses von Boom. 'Kopfhörer' deaktiviert die internen Lautsprecher. Mit 'Immer Aktiv' bleiben die internen Lautsprecher aktiv, auch wenn Kopfhörer angeschlossen sind. EN Choose the function of Boom headphone/sub out port. Headphone option will shut off the internal speakers. "Always On" will keep the internal speakers enabled, even while headphones are plugged in. @@ -25479,7 +25479,7 @@ CONTROLPANEL_PORTBLOCKED_APPS SV Följande program kan blockera anslutningen: CONTROLPANEL_CONFLICT_CISCOVPNSTATEFULINSPECTION - CS Pokud se vyskytnou problémy s připojením k Lyrion Music Serveru, ujistěte se, že je vypnuta funkce „Stateful Firewall (Always On)" + CS Pokud se vyskytnou problémy s připojením k Lyrion Music Serveru, ujistěte se, že je vypnuta funkce „Stateful Firewall (Always On)“ DA Hvis der er problemer med forbindelsen til og fra Lyrion Music Server, skal du kontrollere at "Stateful Firewall (Always On)" er slået fra DE Wenn es Verbindungsprobleme mit Lyrion Music Server gibt, vergewissern Sie sich, dass die Option "Statusbehaftete Firewall (immer aktiv)" deaktiviert ist. EN If you encounter connectivity issues with Lyrion Music Server, please make sure "Stateful Firewall (Always On)" is turned off @@ -25832,7 +25832,7 @@ CONTROLPANEL_NO_STATUS SV Det finns ingen statusinformation. Tänk på att statusinformationen inte kan visas när Lyrion Music Server inte körs. CONTROLPANEL_NEED_ADMINISTRATOR - CS Nemáte práva instalovat nebo spouštět/zastavovat procesy Lyrion Music Serveru na pozadí. Spusťte ovládací panel z nabídky Start systému Windows prostřednictvím kontextové nabídky vyvolané pravým klepnutím tlačítka, a klikněte na možnost „Spustit jako správce". + CS Nemáte práva instalovat nebo spouštět/zastavovat procesy Lyrion Music Serveru na pozadí. Spusťte ovládací panel z nabídky Start systému Windows prostřednictvím kontextové nabídky vyvolané pravým klepnutím tlačítka, a klikněte na možnost „Spustit jako správce“. DA Du har ikke rettigheder til at installere eller starte/stoppe baggrundstjenesten Lyrion Music Server. Start kontrolpanelet fra Startmenuen i Windows – via højrekliksmenuen klikker du på "Kør som administrator". DE Sie sind nicht dazu berechtigt, den Lyrion Music Server-Hintergrunddienst zu installieren oder zu starten bzw. anzuhalten. Öffnen Sie die Systemsteuerung im Windows-Startmenü über das Kontextmenü und wählen Sie 'Als Administrator ausführen'. EN You don't have privileges to install or start/stop the Lyrion Music Server background service. Please start the control panel from the Windows Start Menu, via the right click context menu, and click "Run as Administrator". @@ -25882,7 +25882,7 @@ RUN_AT_LOGIN SV Kör automatiskt vid inloggning RUN_FAILSAFE - CS Spustit bez zásuvných modulů („Bezpečný režim") + CS Spustit bez zásuvných modulů („Bezpečný režim“) DA Kør uden udvidelsesmoduler (fejlsikret tilstand) DE Ohne Benutzererweiterungen ausführen ("Abgesicherter Modus") EN Run with no user extensions ("Safe Mode") @@ -26121,7 +26121,7 @@ INTERNET_RADIO SV Radio HOWTO_INTERNET_RADIO - CS Přejděte na položku „Nejoblíbenější internetová rádia" a stiskněte tlačítko DOPRAVA. + CS Přejděte na položku „Nejoblíbenější internetová rádia“ a stiskněte tlačítko DOPRAVA. DA Find Det bedste fra internetradio, og tryk på højrepilen. DE Markieren Sie die Option 'Die besten Internetradiosender' und drücken Sie RECHTS. EN Scroll to "Best of Internet Radio" and press RIGHT. @@ -26138,7 +26138,7 @@ HOWTO_INTERNET_RADIO SV Bläddra till Webbradiofavoriter och tryck på högerknappen. HOWTO_INTERNET_RADIO_CONTROLLER - CS Přejděte na položku „Nejoblíbenější internetová rádia" a stiskněte středové tlačítko. + CS Přejděte na položku „Nejoblíbenější internetová rádia“ a stiskněte středové tlačítko. DA Find Det bedste fra internetradio, og tryk på midterknappen. DE Markieren Sie 'Die besten Internetradiosender' und drücken Sie die mittlere Taste. EN Scroll to "Best of Internet Radio" and press the center button. @@ -26937,7 +26937,7 @@ SETUP_WORKSSCAN_1 NL Scan de hele bibliotheek op werken SETUP_WORKSSCAN_2 - CS Omezit prohledávání děl na „Moje žánry pro díla a skladatelská alba" (výše) + CS Omezit prohledávání děl na „Moje žánry pro díla a skladatelská alba“ (výše) DE Werke auf "Genres für Werke und Komponistenalben" beschränken (oben) EN Limit works scan to "My work and composer album genres" (above) ES Limitar el escaneo de obras a "Mis géneros para las obras y álbumes de compositores" (arriba) From 946d51239455521ce9a9f7c51f80bf0794157394 Mon Sep 17 00:00:00 2001 From: Michael Herger Date: Mon, 24 Nov 2025 17:18:28 +0100 Subject: [PATCH 019/140] Changelog and .gitignore update Signed-off-by: Michael Herger --- .gitignore | 3 ++- Changelog9.html | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 5246cc88216..7b198c53e5f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ Slim/Utils/OS/Custom.pm # Ignore cache, logs and prefs files Cache/* Logs/* -prefs/* \ No newline at end of file +prefs/* +Plugins/* diff --git a/Changelog9.html b/Changelog9.html index 5cead544cf7..ebf45ec1268 100644 --- a/Changelog9.html +++ b/Changelog9.html @@ -65,7 +65,8 @@

    Version 9.1.0

  • #1414 - Make sure custom image proxy handlers are always called (fixes incompatibility with Radio Now Playing's SVG handler).
  • #1442 - Avoid log flood when player discovery JSON is empty (@mikecappella).
  • #1444 - Fix search using terms with quotes in the Default skin (@darrell-k).
  • -
  • #1445 - Fix search result count (@darrell-k).
  • +
  • #1444 - Fix search using terms with quotes in the Default skin (@darrell-k).
  • +
  • #1460 - Don't close HTTP when 1.1, unless explicit asked (@philippe44).

  • @@ -75,6 +76,7 @@

    Version 9.1.0

  • Remove more left-overs from removed picture/video scanning.
  • Remove more left-overs from removed MySqueezebox integration.
  • Remove support for MySQL. Existing configurations using it will log an error.
  • +
  • #1458 - Add devcontainer configuration with Dockerfile and docker-compose setup (@LMSSonos).

  • From e898312cb7f1be2782c1a62c7c6ccd88f3b2fb56 Mon Sep 17 00:00:00 2001 From: darrell-k Date: Mon, 24 Nov 2025 18:52:27 +0000 Subject: [PATCH 020/140] fix wide characters in cache key Signed-off-by: darrell-k --- Slim/Control/Queries.pm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Slim/Control/Queries.pm b/Slim/Control/Queries.pm index 8aaa5904ffc..27560562511 100644 --- a/Slim/Control/Queries.pm +++ b/Slim/Control/Queries.pm @@ -6800,11 +6800,12 @@ sub _buildCacheKey { my ($sql, $p, $search, $client) = @_; # Slim::Utils::Text::ignoreCase (amongst other useful things) will remove the leading quote from a search phrase, so put it back. - return md5_hex($sql + return md5_hex(Encode::encode("UTF-8", + $sql . Slim::Utils::Unicode::utf8on(join( ':', @$p )) . Slim::Music::VirtualLibraries->getLibraryIdForClient($client) . ($search =~ /^"/ ? '"' : '') . Slim::Utils::Text::ignoreCase($search, 1) - ); + )); } =head1 SEE ALSO From 9d0e1ca8ad8daea9a6b9e94813d1c54525b8eb27 Mon Sep 17 00:00:00 2001 From: Sam Y Date: Mon, 24 Nov 2025 14:12:48 -0500 Subject: [PATCH 021/140] Fix error calling getMetaDataFor () without valid $client Slim::Control::Request::execute (1884) Error: While trying to run function coderef [Slim::Control::Queries::playlistsTracksQuery]: [Can't call method "playingSong" on an undefined value at /usr/share/perl5/Slim/Player/Protocols/HTTP.pm line 1049. ] Signed-off-by: Sam Y --- Slim/Control/Queries.pm | 66 ++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/Slim/Control/Queries.pm b/Slim/Control/Queries.pm index 8aaa5904ffc..d911586cfce 100644 --- a/Slim/Control/Queries.pm +++ b/Slim/Control/Queries.pm @@ -5823,42 +5823,42 @@ sub _songData { my $song; if ( my $client = $request->client ) { $song = $client->currentSongForUrl($url); - } - if ( $isRemote ) { - my $handler = Slim::Player::ProtocolHandlers->handlerForURL($url); + if ( $isRemote ) { + my $handler = Slim::Player::ProtocolHandlers->handlerForURL($url); - if ( $handler && $handler->can('getMetadataFor') ) { - # Don't modify source data - $remoteMeta = Storable::dclone( - $handler->getMetadataFor( $request->client, $url ) - ); + if ( $handler && $handler->can('getMetadataFor') ) { + # Don't modify source data + $remoteMeta = Storable::dclone( + $handler->getMetadataFor( $client, $url ) + ); - $remoteMeta->{a} = $remoteMeta->{artist}; - $remoteMeta->{A} = $remoteMeta->{artist}; - $remoteMeta->{E} = $remoteMeta->{extid}; - $remoteMeta->{l} = $remoteMeta->{album}; - $remoteMeta->{i} = $remoteMeta->{disc}; - $remoteMeta->{K} = $remoteMeta->{cover}; - $remoteMeta->{d} = ( $remoteMeta->{duration} || $remoteMeta->{secs} || 0 ) + 0; - $remoteMeta->{Y} = $remoteMeta->{replay_gain}; - $remoteMeta->{o} = $remoteMeta->{type}; - $remoteMeta->{r} = $remoteMeta->{bitrate}; - $remoteMeta->{B} = $remoteMeta->{buttons}; - $remoteMeta->{L} = $remoteMeta->{info_link}; - $remoteMeta->{t} = $remoteMeta->{tracknum}; - $remoteMeta->{y} = $remoteMeta->{year}; - $remoteMeta->{T} = $remoteMeta->{samplerate}; - $remoteMeta->{I} = $remoteMeta->{samplesize}; - $remoteMeta->{W} = $remoteMeta->{releasetype}; - $remoteMeta->{b} = $remoteMeta->{work}; - $remoteMeta->{h} = $remoteMeta->{grouping}; - $remoteMeta->{'1'} = $remoteMeta->{performance}; - $remoteMeta->{z} = $remoteMeta->{subtitle}; - - # Distance from the live edge of live remote stream. -1 is not live, 0 is live at the edge, >0 is distance in seconds from the live edge. - # $remoteMeta->{live_edge} contains distance from live edge. Will only be populated by 3rd party handlers that support dynamic adaptive live streams. - $remoteMeta->{V} = $remoteMeta->{live_edge} // ($song && $song->isLive() ? 0 : -1); + $remoteMeta->{a} = $remoteMeta->{artist}; + $remoteMeta->{A} = $remoteMeta->{artist}; + $remoteMeta->{E} = $remoteMeta->{extid}; + $remoteMeta->{l} = $remoteMeta->{album}; + $remoteMeta->{i} = $remoteMeta->{disc}; + $remoteMeta->{K} = $remoteMeta->{cover}; + $remoteMeta->{d} = ( $remoteMeta->{duration} || $remoteMeta->{secs} || 0 ) + 0; + $remoteMeta->{Y} = $remoteMeta->{replay_gain}; + $remoteMeta->{o} = $remoteMeta->{type}; + $remoteMeta->{r} = $remoteMeta->{bitrate}; + $remoteMeta->{B} = $remoteMeta->{buttons}; + $remoteMeta->{L} = $remoteMeta->{info_link}; + $remoteMeta->{t} = $remoteMeta->{tracknum}; + $remoteMeta->{y} = $remoteMeta->{year}; + $remoteMeta->{T} = $remoteMeta->{samplerate}; + $remoteMeta->{I} = $remoteMeta->{samplesize}; + $remoteMeta->{W} = $remoteMeta->{releasetype}; + $remoteMeta->{b} = $remoteMeta->{work}; + $remoteMeta->{h} = $remoteMeta->{grouping}; + $remoteMeta->{'1'} = $remoteMeta->{performance}; + $remoteMeta->{z} = $remoteMeta->{subtitle}; + + # Distance from the live edge of live remote stream. -1 is not live, 0 is live at the edge, >0 is distance in seconds from the live edge. + # $remoteMeta->{live_edge} contains distance from live edge. Will only be populated by 3rd party handlers that support dynamic adaptive live streams. + $remoteMeta->{V} = $remoteMeta->{live_edge} // ($song && $song->isLive() ? 0 : -1); + } } } From 945c6a782097057166a91e7df76a08dd972d7b46 Mon Sep 17 00:00:00 2001 From: Sam Y Date: Mon, 24 Nov 2025 16:03:19 -0500 Subject: [PATCH 022/140] Fix problem in the HTTP protocol handler Remove $client dependency in HTTP.pm getMetaDataFor() and back out previous commit change to Queries.pm. Signed-off-by: Sam Y --- Slim/Control/Queries.pm | 66 +++++++++++++++++------------------ Slim/Player/Protocols/HTTP.pm | 2 +- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Slim/Control/Queries.pm b/Slim/Control/Queries.pm index bb065b73779..27560562511 100644 --- a/Slim/Control/Queries.pm +++ b/Slim/Control/Queries.pm @@ -5823,42 +5823,42 @@ sub _songData { my $song; if ( my $client = $request->client ) { $song = $client->currentSongForUrl($url); + } - if ( $isRemote ) { - my $handler = Slim::Player::ProtocolHandlers->handlerForURL($url); + if ( $isRemote ) { + my $handler = Slim::Player::ProtocolHandlers->handlerForURL($url); - if ( $handler && $handler->can('getMetadataFor') ) { - # Don't modify source data - $remoteMeta = Storable::dclone( - $handler->getMetadataFor( $client, $url ) - ); + if ( $handler && $handler->can('getMetadataFor') ) { + # Don't modify source data + $remoteMeta = Storable::dclone( + $handler->getMetadataFor( $request->client, $url ) + ); - $remoteMeta->{a} = $remoteMeta->{artist}; - $remoteMeta->{A} = $remoteMeta->{artist}; - $remoteMeta->{E} = $remoteMeta->{extid}; - $remoteMeta->{l} = $remoteMeta->{album}; - $remoteMeta->{i} = $remoteMeta->{disc}; - $remoteMeta->{K} = $remoteMeta->{cover}; - $remoteMeta->{d} = ( $remoteMeta->{duration} || $remoteMeta->{secs} || 0 ) + 0; - $remoteMeta->{Y} = $remoteMeta->{replay_gain}; - $remoteMeta->{o} = $remoteMeta->{type}; - $remoteMeta->{r} = $remoteMeta->{bitrate}; - $remoteMeta->{B} = $remoteMeta->{buttons}; - $remoteMeta->{L} = $remoteMeta->{info_link}; - $remoteMeta->{t} = $remoteMeta->{tracknum}; - $remoteMeta->{y} = $remoteMeta->{year}; - $remoteMeta->{T} = $remoteMeta->{samplerate}; - $remoteMeta->{I} = $remoteMeta->{samplesize}; - $remoteMeta->{W} = $remoteMeta->{releasetype}; - $remoteMeta->{b} = $remoteMeta->{work}; - $remoteMeta->{h} = $remoteMeta->{grouping}; - $remoteMeta->{'1'} = $remoteMeta->{performance}; - $remoteMeta->{z} = $remoteMeta->{subtitle}; - - # Distance from the live edge of live remote stream. -1 is not live, 0 is live at the edge, >0 is distance in seconds from the live edge. - # $remoteMeta->{live_edge} contains distance from live edge. Will only be populated by 3rd party handlers that support dynamic adaptive live streams. - $remoteMeta->{V} = $remoteMeta->{live_edge} // ($song && $song->isLive() ? 0 : -1); - } + $remoteMeta->{a} = $remoteMeta->{artist}; + $remoteMeta->{A} = $remoteMeta->{artist}; + $remoteMeta->{E} = $remoteMeta->{extid}; + $remoteMeta->{l} = $remoteMeta->{album}; + $remoteMeta->{i} = $remoteMeta->{disc}; + $remoteMeta->{K} = $remoteMeta->{cover}; + $remoteMeta->{d} = ( $remoteMeta->{duration} || $remoteMeta->{secs} || 0 ) + 0; + $remoteMeta->{Y} = $remoteMeta->{replay_gain}; + $remoteMeta->{o} = $remoteMeta->{type}; + $remoteMeta->{r} = $remoteMeta->{bitrate}; + $remoteMeta->{B} = $remoteMeta->{buttons}; + $remoteMeta->{L} = $remoteMeta->{info_link}; + $remoteMeta->{t} = $remoteMeta->{tracknum}; + $remoteMeta->{y} = $remoteMeta->{year}; + $remoteMeta->{T} = $remoteMeta->{samplerate}; + $remoteMeta->{I} = $remoteMeta->{samplesize}; + $remoteMeta->{W} = $remoteMeta->{releasetype}; + $remoteMeta->{b} = $remoteMeta->{work}; + $remoteMeta->{h} = $remoteMeta->{grouping}; + $remoteMeta->{'1'} = $remoteMeta->{performance}; + $remoteMeta->{z} = $remoteMeta->{subtitle}; + + # Distance from the live edge of live remote stream. -1 is not live, 0 is live at the edge, >0 is distance in seconds from the live edge. + # $remoteMeta->{live_edge} contains distance from live edge. Will only be populated by 3rd party handlers that support dynamic adaptive live streams. + $remoteMeta->{V} = $remoteMeta->{live_edge} // ($song && $song->isLive() ? 0 : -1); } } diff --git a/Slim/Player/Protocols/HTTP.pm b/Slim/Player/Protocols/HTTP.pm index 0b5ffdf82e8..0e02fb61ff7 100644 --- a/Slim/Player/Protocols/HTTP.pm +++ b/Slim/Player/Protocols/HTTP.pm @@ -1046,7 +1046,7 @@ sub getMetadataFor { # Check for parsed WMA metadata, this is here because WMA may # use HTTP protocol handler. Check for container and track - my $song = $client->playingSong(); + my $song = $client->playingSong() if $client; my $current = ($song->track->url eq $url || $song->currentTrack->url eq $url) if $song; if ( $current ) { From 23f4b2e47ac70350642fcc15c1e7ac7f28e33337 Mon Sep 17 00:00:00 2001 From: Michael Herger Date: Tue, 25 Nov 2025 10:46:56 +0100 Subject: [PATCH 023/140] There's no need to repeatedly fetch the client object Signed-off-by: Michael Herger --- Slim/Control/Queries.pm | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Slim/Control/Queries.pm b/Slim/Control/Queries.pm index 27560562511..968efb82623 100644 --- a/Slim/Control/Queries.pm +++ b/Slim/Control/Queries.pm @@ -5820,10 +5820,8 @@ sub _songData { my $isRemote = _notLocalTrackAndRemoteUrl($track); my $url = $track->url; - my $song; - if ( my $client = $request->client ) { - $song = $client->currentSongForUrl($url); - } + my $client = $request->client; + my $song = $client->currentSongForUrl($url) if $client; if ( $isRemote ) { my $handler = Slim::Player::ProtocolHandlers->handlerForURL($url); @@ -5831,7 +5829,7 @@ sub _songData { if ( $handler && $handler->can('getMetadataFor') ) { # Don't modify source data $remoteMeta = Storable::dclone( - $handler->getMetadataFor( $request->client, $url ) + $handler->getMetadataFor( $client, $url ) ); $remoteMeta->{a} = $remoteMeta->{artist}; From a158693e40bbf5ad5fd7c00a0c3b2063ac206c5e Mon Sep 17 00:00:00 2001 From: Michael Herger Date: Tue, 25 Nov 2025 10:58:19 +0100 Subject: [PATCH 024/140] Add some sanity checking before using the client object in `getMetadataFor()` handlers Signed-off-by: Michael Herger --- Slim/Player/Protocols/SqueezePlayDirect.pm | 6 +-- Slim/Plugin/NetTest/ProtocolHandler.pm | 6 +-- Slim/Plugin/RemoteLibrary/ProtocolHandler.pm | 48 +++++++++---------- .../UPnP/MediaRenderer/ProtocolHandler.pm | 2 +- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Slim/Player/Protocols/SqueezePlayDirect.pm b/Slim/Player/Protocols/SqueezePlayDirect.pm index b11b1fd95fc..7780ff91098 100644 --- a/Slim/Player/Protocols/SqueezePlayDirect.pm +++ b/Slim/Player/Protocols/SqueezePlayDirect.pm @@ -120,7 +120,7 @@ sub getSeekData { sub getMetadataFor { my ($class, $client, $url) = @_; - if (my $song = $client->currentSongForUrl($url)) { + if ($client && (my $song = $client->currentSongForUrl($url))) { my $ret = { artist => $song->pluginData('artist'), @@ -143,7 +143,7 @@ sub getMetadataFor { my ($key, $val) = $param =~ /(.*?)=(.*)/; $params{$key} = decode_base64($val) || $val; } - + return { # omit title here as it prevents connecting status being displayed artist => $params{artist}, @@ -152,6 +152,6 @@ sub getMetadataFor { icon => $params{icon}, type => $params{type}, }; -} +} 1; diff --git a/Slim/Plugin/NetTest/ProtocolHandler.pm b/Slim/Plugin/NetTest/ProtocolHandler.pm index c44ed29c89c..530532487b7 100644 --- a/Slim/Plugin/NetTest/ProtocolHandler.pm +++ b/Slim/Plugin/NetTest/ProtocolHandler.pm @@ -93,13 +93,13 @@ sub sysread { return length $_[1]; } -sub currentrate { +sub currentrate { my $self = shift; return ${*$self}{'rate'}; } -sub testrate { +sub testrate { my $self = shift; return ${*$self}{'testrate'}; @@ -108,7 +108,7 @@ sub testrate { sub getMetadataFor { my ($self, $client, $url) = @_; - my $fd = $client->controller()->songStreamController() ? $client->controller()->songStreamController()->streamHandler() : undef; + my $fd = ($client && $client->controller()->songStreamController()) ? $client->controller()->songStreamController()->streamHandler() : undef; if ($fd && $fd->isa(__PACKAGE__)) { return { diff --git a/Slim/Plugin/RemoteLibrary/ProtocolHandler.pm b/Slim/Plugin/RemoteLibrary/ProtocolHandler.pm index 6124ff9a726..8d9c350fd1f 100644 --- a/Slim/Plugin/RemoteLibrary/ProtocolHandler.pm +++ b/Slim/Plugin/RemoteLibrary/ProtocolHandler.pm @@ -20,7 +20,7 @@ sub new { my $args = shift; my $client = $args->{client}; - + my $song = $args->{'song'}; my $streamUrl = $song->streamUrl() || return; @@ -68,41 +68,41 @@ sub scanUrl { sub getNextTrack { my ( $class, $song, $successCb, $errorCb ) = @_; - + my $url = $song->track()->url; my ($baseUrl, $uuid, $id, $file) = _parseUrl($url); $url = $baseUrl . join('/', 'music', $id, $file); - + main::DEBUGLOG && $log->is_debug && $log->debug("Setting streaming URL: $url"); - + $song->streamUrl($url); - + $successCb->(); } sub getMetadataFor { my ( $class, $client, $url, $forceCurrent ) = @_; - + my $meta = $cache->get('remotelibrary_' . $url); - my $song = $client->playingSong(); + my $song = $client->playingSong() if $client; my ($baseUrl, $uuid, $id, $file) = _parseUrl($url); if ($song && $song->streamUrl && $song->streamUrl eq $url) { $song->streamUrl($baseUrl . join('/', 'music', $id, $file)); } - - if ( !$meta && !$client->pluginData('fetchingMetadata') ) { + + if ( !$meta && $client && !$client->pluginData('fetchingMetadata') ) { $client->pluginData( fetchingMetadata => 1 ); # Go fetch metadata for all tracks on the playlist without metadata my $need = { $id => $url }; - + my $request; - + # we'll have to use one songinfo query per remote track if ( $id =~ /^-/ ) { $request = ['songinfo', 0, 999, 'track_id:' . $id, 'tags:acdgilortyY']; @@ -119,11 +119,11 @@ sub getMetadataFor { } } } - + $request = ['titles', 0, 999, sprintf('search:sql=tracks.id IN (%s)', join(',', keys %$need)), 'tags:acdgilortyY']; } - Slim::Plugin::RemoteLibrary::LMS->remoteRequest($uuid, + [ '', $request ], \&_gotMetadata, sub {}, @@ -133,7 +133,7 @@ sub getMetadataFor { }, ); } - + if ($meta && ref $meta && keys %$meta) { $song->duration($meta->{duration}) if $song && $meta->{duration}; @@ -144,25 +144,25 @@ sub getMetadataFor { $song->bitrate($bitrate) if $song && $bitrate; } } - + return $meta || {}; } sub _gotMetadata { my ($result, $args) = @_; - + my $client = $args->{client}; my $idUrlMap = $args->{idUrlMap}; - + if ( !($result && ($result->{titles_loop} || $result->{songinfo_loop})) ) { $log->error( 'Unexpected response data: ' . Data::Dump::dump($result) ); - + # fill in some fake metadata to prevent looping lookups $result->{titles_loop} = [ map { id => $_ }, keys %$idUrlMap ]; } - + my @trackInfo; if ($result->{titles_loop}) { @trackInfo = @{$result->{titles_loop}}; @@ -178,7 +178,7 @@ sub _gotMetadata { foreach my $meta ( @trackInfo ) { next unless $meta->{id} && (my $url = $idUrlMap->{$meta->{id}}); - + if ($meta->{coverid}) { my (undef, $remote_library) = _parseUrl($url); $meta->{cover} = Slim::Plugin::RemoteLibrary::LMS->proxiedImageUrl({ @@ -188,7 +188,7 @@ sub _gotMetadata { $cache->set('remotelibrary_' . $url, $meta); } - + if ($client) { $client->pluginData( fetchingMetadata => 0 ); @@ -196,16 +196,16 @@ sub _gotMetadata { # Update the playlist time so the web will refresh, etc $client->currentPlaylistUpdateTime( Time::HiRes::time() ); - + Slim::Control::Request::notifyFromArray( $client, [ 'newmetadata' ] ); } sub _parseUrl { my $url = shift; - + my ($uuid, $id, $file) = $url =~ m|lms://(.*?)/music/([\-\d]+?)/(.*)|; my $baseUrl = Slim::Plugin::RemoteLibrary::LMS->baseUrl($uuid); - + return ($baseUrl || '', $uuid, $id, $file); } diff --git a/Slim/Plugin/UPnP/MediaRenderer/ProtocolHandler.pm b/Slim/Plugin/UPnP/MediaRenderer/ProtocolHandler.pm index 19eb6923936..865cc09d117 100644 --- a/Slim/Plugin/UPnP/MediaRenderer/ProtocolHandler.pm +++ b/Slim/Plugin/UPnP/MediaRenderer/ProtocolHandler.pm @@ -79,7 +79,7 @@ sub getMetadataFor { # convert protocal handler $url =~ s/^upnp/http/; - my $pd = $client->pluginData(); + my $pd = ($client && $client->pluginData()) || {}; my $meta = $pd->{avt_AVTransportURIMetaData_hash}; my $res = $meta->{res}; my $currentUri = $res->{uri}; From 09a50181c9cfc8652c87335512c846954fe781ab Mon Sep 17 00:00:00 2001 From: Michael Herger Date: Wed, 26 Nov 2025 09:44:12 +0100 Subject: [PATCH 025/140] Let the image proxy tell the upstream server what image file formats we support. This is to prevent receiving the increasingly popular webp images. Signed-off-by: Michael Herger --- Changelog9.html | 1 + Slim/Web/ImageProxy.pm | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Changelog9.html b/Changelog9.html index ebf45ec1268..4da72c96c30 100644 --- a/Changelog9.html +++ b/Changelog9.html @@ -58,6 +58,7 @@

    Version 9.1.0

  • Bug Fixes: