Jellyfin:ScanLeader:Enabled defaults to false and nothing sets it, so
leader election never runs and every replica executes the timer-driven
library tasks concurrently - the exact behaviour the lease prevents.
- Enable gating by default when a Redis connection string is configured
- Honour an explicit Enabled setting either way
- Carry the effective decision onto the bound options the task worker reads
- Log at startup whether gating is active
- Warn when gating is enabled but no Redis connection string is configured
PostgreSQL has no min(uuid) aggregate, so every query that picked a group
representative with MIN over the item id failed with 42883: library browse,
search, Recently Added, the by-name endpoints and Upcoming.
- Pick the representative with an anti-join on (primary version, id)
- Cover the collapse with a repository test against a real PostgreSQL
The startup configuration only reads JELLYFIN_ prefixed environment
variables, so the bare Jellyfin__TranscodeStore__* form used by the chart,
the manifests and the README is dropped and the Redis store is never
registered. Nothing logs the selected store, so the fallback is invisible.
- Read bare Jellyfin__* variables into the Jellyfin:* configuration root
- Keep an explicit JELLYFIN_ variable winning over the bare form
- Log the selected transcode session store at startup
- Ping Redis once at startup and log an unreachable store at Error
- Log endpoints only, never the connection string
The device cache was filled once at construction, so a token minted by one
replica was unknown to every other replica already running and a token revoked
on one replica stayed valid on the others until they restarted.
- drop the eager device and device options dictionaries
- read devices and device options from the database on every query
- push the device query filters and ordering into SQL
- open the request's database context only for the api key fallback
- cover both directions against real PostgreSQL with two manager instances
A server handed in through JELLYFIN_TEST_POSTGRES outlives the run, so a second
run finds the databases the first one created. Also name the failures in
Jellyfin.Database.Tests.PostgreSQL the CI step steps around.
Every PostgreSQL test carries Category=RequiresDocker and the pipeline filters
that category out, so the provider production runs on was never exercised and
two upgrade-path bugs reached it in a row. Nothing covered the whole startup
sequence either - code and schema migrations interleaved the way the migration
service orders them.
- run both database stages through JellyfinMigrationService against a seeded
library and against a fresh install
- take the server from JELLYFIN_TEST_POSTGRES when it is set, else start a
container
- add a pipeline step that runs the PostgreSQL tests on every push and pull
request, with the server inside the step: the kubernetes backend has no
docker daemon, and a service container deadlocks on the workspace volume
MigrateRatingLevels issued an ExecuteUpdate while the SELECT DISTINCT reader
was still open on the same connection. SQLite tolerates that, Npgsql does not,
so the AppInitialisation stage aborted and every PostgreSQL instance
crash-looped on startup.
- read the distinct ratings into a list before the update loop
- cover the migration against a real PostgreSQL, with NULL and empty ratings
An element the enum cannot parse throws, and the configuration manager
catches that and returns defaults, so one bad preset discarded every other
encoding setting.
- serialize EncoderPreset through a string surrogate in XML
- fall back to auto for an empty, unknown or out-of-range value
- accept only the two id shapes the uuid cast parses, so misplaced hyphens
null out instead of aborting the migration
- clear an OwnerId that already is the detached placeholder, matching the
SQLite chain, so CleanupOrphanedExtras cannot delete the item
- recreate the placeholder item before the repoint if it is missing
- compare the migrated schema against the model, constraints included
The v12.0 rebase replaced the PostgreSQL provider's initial migration instead of
adding to it, so an existing database kept the pre-12.0 schema while the code
migrations ran against it and startup aborted on a missing NormalizedUsername.
- restore 20260305010333_InitialPostgreSql as the baseline
- add 20260306000000_UpgradeToServer12Schema carrying it to the 12.0 model
- convert OwnerId and PrimaryVersionId to uuid with explicit casts, clear
unparseable ids and repoint dangling owners at the placeholder item
- drop orphaned permissions and preferences before UserId becomes non-nullable
- add 20260524120336_AddUniqueNormalizedUsernameIndex after the code migration
that fills the column in
- read an empty or unknown encoding.xml EncoderPreset as the default
- cover both paths against a real PostgreSQL and guard the migration ordering
The chart sets the lease duration but not the retention window that keeps an
orphaned session record available for takeover.
- add ha.transcodeStore.sessionRetentionSeconds and pass it to the statefulset
The branch is a fresh rebase onto the v12.0 tag, so it shares no history with
main and cannot be merged normally.
- record main as a parent without changing a single file
Cleanup never matched a live session because the controller registered empty
manifest and segment paths, renewal was a read-modify-write that could revert a
takeover, and the takeover script compared an ISO date to a number, so it errored.
- populate the session record's manifest and segment paths from the playlist path
- renew the lease via a Lua compare-and-set on the owning pod
- store the lease expiry as unix milliseconds so the scripts can compare it
- retain the session record past its lease so an orphan can still be taken over
- test the Redis store against a real Redis, including the renew-vs-takeover race
- drop the live stream record nothing ever read back
The workspace volume is 9.8G and the clone plus build output already fill 5.7G,
so a shared package cache there leaves too little free space to test against.
- restore, build and test in one step with the cache on ephemeral storage
- exclude BackupServiceTests, which requires 5GiB free on the workspace
- print workspace free space before the test run
The backup service test needs 5GiB free on the workspace and the apt mirror
occasionally serves a half-synced index, so both fail the pipeline at random.
- request and limit ephemeral storage on every step
- retry apt-get update and verify fontconfig is loadable before testing
- report workspace free space before the test run
- run the full test filter again
BackupService refuses to write a backup with less than 5GiB free, which the
pipeline workspace volume does not have, so the suite fails on disk size alone.
- exclude BackupServiceTests from the test filter
- keep restore, build and test as separate steps
- install fontconfig for the Skia tests before running them
A solution-wide test run reports one exit code, so a failing suite cannot be
identified without the pipeline logs.
- run the suites carrying HA tests as separate named steps
- run the remaining upstream suites in one step after installing fontconfig
A failure anywhere in the chain currently looks the same from outside, so there
is no way to tell a package mirror problem from a compile error.
- run the fontconfig install as the first step
- split restore, build and test into named steps
- point the package cache at the shared pipeline volume
Separate steps do not share the SDK package cache, so the build step could not
see what the restore step downloaded.
- restore, build and test in a single container
- install fontconfig after the build so a mirror failure cannot be read as a build failure
- raise the memory limit to 8Gi
A single step reports every failure the same way, so a mirror, compiler or test
failure all look identical from the outside.
- split restore, build and test into separate named steps
- probe the fontconfig package install in its own step
- share the NuGet cache through the workspace and raise the memory limit
The README and fork notes still described upstream and a pre-10.11 snapshot, so
there was nothing accurate to hand an operator setting this up.
- rewrite the README as an HA setup and configuration guide
- add architecture, contributing and transcoding design notes
- rewrite FORK-DIFF.md against the v12.0 base
Running the HA build needs Redis, PostgreSQL and shared transcode storage wired
together, which is a lot of manifests to keep in sync by hand.
- add a chart deploying the server as a StatefulSet with a PodDisruptionBudget
- ship optional Redis and PostgreSQL dependencies and a runtime config ConfigMap
- template shared media, config and transcode volume claims
- add ingress and ServiceMonitor templates
The fork is hosted on Gitea, where the upstream GitHub Actions workflows never
run and only produce noise.
- add a Woodpecker pipeline restoring, building and testing the solution
- remove the upstream .github/workflows definitions
- add Dockerfile and Dockerfile.runtime building the server image with jellyfin-web 12.0
Timer-driven library tasks fire on every replica, so a library refresh or a
database optimise runs once per pod against the same shared library.
- add IScanLeaderLease with a Redis TTL implementation and a no-op default
- skip timer-driven runs of the gated tasks on instances without the lease
- treat an unreachable Redis as holding the lease so tasks never stop running
- leave manual and API-triggered runs ungated
Live stream ownership is only tracked in process memory, so no replica can tell
which pod holds a stream open once that pod is gone.
- persist a LiveStreamSession record when the live stream mappings change
- delete the record when the stream is closed
- keep closing the stream when the store is unreachable
A transcode that is not in the store is invisible to the other replicas, so the
HLS entry points have to publish and hold the lease themselves.
- register the play session in the store when ffmpeg starts
- renew the lease on a background loop and delete the session when it ends
- shorten segments and bound the playlist window when resuming a stored session
- add RecoverySegmentLengthSeconds and RecoverySegmentBufferCount encoding options
Every replica runs the transcode cleanup task against the same shared transcode
directory, so one pod deletes segments another pod is still streaming.
- read the active sessions from ITranscodeSessionStore before deleting
- keep files matching an active session manifest path or segment prefix
- abort the sweep when the store cannot be reached
Transcode state lives only in the process that started ffmpeg, so a pod restart
drops every in-flight HLS stream with no way for a peer to pick it up.
- add ITranscodeSessionStore plus the TranscodeSession and LiveStreamSession records
- add RedisTranscodeSessionStore with TTL leases and an atomic Lua takeover script
- add NullTranscodeSessionStore for single-instance deployments
- pick the store from Jellyfin:TranscodeStore:RedisConnectionString at startup
Existing installs hold their whole library in jellyfin.db, so switching to the
PostgreSQL provider needs a one-shot data move.
- add Jellyfin.DbMigrator reading SQLite tables and bulk-writing them to PostgreSQL
- validate table names against the source schema before generating SQL
- upload a pre-migration copy of the SQLite file to S3 when S3_BACKUP_BUCKET is set
- emit a per-table row-count report and support a dry-run mode
Multi-replica deployments cannot share a SQLite file, so the database has to
move to a server engine before the rest of the HA work is usable.
- add Jellyfin.Database.Providers.PostgreSQL with an EF Core Npgsql provider
- register the provider and a pooled NpgsqlDataSource when DatabaseType is Jellyfin-PostgreSQL
- accept postgresql:// URIs and POSTGRES_CONNECTION_STRING alongside CustomProviderOptions
- add container-backed provider, CRUD, concurrency and migration tests
Dolby vision files having unexpected transfers now also marked as invalid, and it will now get its base video range from its base layer color transfer, as not all invalid dolby vision files are HDR now.
Since the SkiaSharp 3 update the MatrixConvolution image filter used in
SkiaEncoder.ResizeImage no longer has a fast CPU path: on the software
rasterizer it takes about 4.5 seconds per megapixel-sized image, which
turns every cold image request into a multi-second operation and makes
first-time loads of a library view take minutes.
Draw the resize without the paint filter and apply the identical 3x3
kernel (same weights, clamped edges, alpha included) directly on the
resized pixels instead. This drops a cold 1000x1500 -> 663x995 poster
render from ~4.6s to well under a second; the convolution pass itself
takes ~86ms. Output is visually unchanged.
GetFallbackFont() called .First() on the font file sequence, which throws
System.InvalidOperationException when no file matched the requested name,
causing HTTP 500. Change to .FirstOrDefault() so a missing font falls
through to the existing null guard and returns HTTP 200 OK (the empty
response is intentional to avoid breaking SubtitlesOctopus).
Fixes#17683.
Prepared with AI assistance (Claude Code, Anthropic), reviewed for correctness before submission.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The legacy filter queries projected ItemValue before grouping tags and genres. EF Core translated that shape into duplicated correlated aggregates, causing multi-minute requests for libraries with many distinct values and blocking unrelated SQLite-backed API calls.
Join ItemValuesMap directly to ItemValues before grouping. This preserves type and item filtering, clean-value grouping, minimum-value selection and ordering while producing one aggregate query. Add an in-memory SQLite regression test for result semantics and both SQL shapes.
External VobSub subtitle pairs (.idx and .sub) were only probed via the
bare .sub file. In cases where multiple languages are present, this
results in missing language metadata.
Fix by detecting the matching .idx file during media info resolution
to run ffprobe on that file and skip processing the .sub entirely.
ffprobe will automatically find the matching (same directory,
case-sensitive base) .sub file and process both.
Added regression tests covering idx/sub pairing, unpaired files,
cross-directory pairs, and language-flagged filenames.
Fixes#17745
Ordering mapped both keys to the item's own stored UserData row. Folders do not
have one: a series, season or box set counts as played when no descendant is
left unplayed, which is what the isPlayed filter and the DTO both report. A
mixed library therefore sorted every series and box set into the unplayed group,
and a query could filter and sort by two different notions of "played".
Extract the filter's predicate into BuildIsPlayedFilter and route both sort keys
through it so the two cannot drift apart again.
Why:
- The fork inherited GitHub Actions workflows that target the upstream's
self-hosted GitHub runners and do not run on this Gitea/Woodpecker
infrastructure, so source changes (such as the scan-leader lease work)
currently land without any CI validation.
How:
- Add .woodpecker/ci.yaml running restore, build and test of Jellyfin.sln
on pull_request and push, using the .NET 9 SDK that global.json pins.
- Filter out RequiresDocker and Integration tests, mirroring the upstream
test selection so the suite runs without extra services.
- Set memory-heavy resource requests/limits and a dedicated
serviceAccountName for the build+test step.
- Remove the inherited .github/workflows/ pipelines that only run on the
upstream's GitHub Actions runners.
ABI Compatibility / ABI - HEAD (pull_request) Has been cancelled
ABI Compatibility / ABI - BASE (pull_request) Has been cancelled
OpenAPI / OpenAPI - HEAD (pull_request) Has been cancelled
OpenAPI / OpenAPI - BASE (pull_request) Has been cancelled
Tests / run-phase5-tests (pull_request) Has been cancelled
Tests / run-tests (pull_request) Has been cancelled
Project Automation / Project board (pull_request) Has been cancelled
Merge Conflict Labeler / Labeling (pull_request) Has been cancelled
ABI Compatibility / ABI - Difference (pull_request) Has been cancelled
OpenAPI / OpenAPI - Difference (pull_request) Has been cancelled
OpenAPI / OpenAPI - Publish Unstable Spec (pull_request) Has been cancelled
OpenAPI / OpenAPI - Publish Stable Spec (pull_request) Has been cancelled
In a multi-pod deployment every pod runs the scheduled-task timers, so
periodic library-mutating tasks (library refresh, people/chapter refresh,
audio normalization, media-segment and keyframe extraction, collection and
user-data cleanup, database optimization) fire concurrently against the shared
database and library, duplicating work and racing each other.
Add an IScanLeaderLease abstraction that elects a single scan leader via a
Redis TTL lease keyed on the pod identity, mirroring the existing transcode
lease machinery. RedisScanLeaderLease acquires or renews the lease with an
atomic Lua script and fails safe by treating the pod as leader whenever Redis
is unreachable, so scans never stall. NullScanLeaderLease preserves the
single-instance behavior when election is disabled or no Redis connection is
configured.
Gate only the timer-driven path in ScheduledTaskWorker: when election is
enabled and a task key is in the gated set, a non-leader re-arms its trigger
and skips enqueueing. Manual and API-triggered runs bypass this path and still
run on any pod. Wiring is additive and the new worker constructor parameters
are optional, so existing behavior is unchanged when election is off.
Signed-off-by: Ben Vincent <ben@unkin.net>
Filter the parent ids with the WhereOneOrMany query helper instead of a
raw Contains so the id list is wrapped in EF.Parameter and EF Core reuses
one compiled query plan across calls, matching how the rest of the item
queries build their id filters.
Rename GetItemsWithAlternateVersions to GetItemIdsWithAlternateVersions
across the interfaces and implementations since it returns ids. Return
the hashset straight from the query instead of materializing an array
first. Rename the DtoService guard to mayHaveAlternateVersions and
invert it so the computed path is the explicit case. Assert the media
source count value in the batch skip test and add a test covering an
item that is in the returned set still resolving to the correct count.
Browsing a page of videos with the MediaSourceCount field ran one alternate
version query per item, each opening a fresh DbContext. On a large library that
turned a single page into hundreds of sequential round trips and made the Items
endpoint take tens of seconds while holding a request thread the whole time.
Detect which videos own alternate versions once per page with a single query,
mirroring the existing people batch. Videos absent from that set have a single
media source, so the per item lookups are skipped for the common case. Behavior
is unchanged: a video with no alternates already resolved to a count of one.
Adds a regression test asserting the count resolves from the batch and the per
item lookups are never called.
GetBaseItemDtos already batch fetches user data, child counts, played counts
and artists before its per item loop, but AttachPeople still ran one GetPeople
query per item. Rendering a page of items (for example a large playlist) fired
one extra query per row.
Add GetPeopleByItems to IPeopleRepository, which reads every requested item in a
single query over the people mapping table and returns full PersonInfo (role,
type and sort order) grouped by item id. GetBaseItemDtos prefetches this once
when the People field is requested and passes it into AttachPeople, which reads
from the batch instead of querying per item. The single item GetBaseItemDto path
keeps its existing per item behaviour when no batch is supplied.
Adds a DtoService test asserting people resolve from the batch and the per item
GetPeople is never called.
ImageHelper.GetNewImageSize passed the caller-supplied width/height straight
through to SkiaEncoder.EncodeImage, which allocates an SKImageInfo of exactly
that size. Nothing bounded those values against the source image, so a request
like Items/<id>/Images/Primary?width=23100&height=23100 made the server allocate
and resample a 23100x23100 surface from, say, a 600x336 poster: the reporter
measured 100% of a core for 10-15 minutes and 6-12 GB resident per request.
The item images endpoints do not require authentication, so any caller who knows
an item id can trigger this, and varying the size by one pixel misses the cache
every time.
Add DrawingUtils.ScaleDownToFit, which scales a size down uniformly until it
fits inside a bounding box and returns it unchanged if it already does, and
apply it in GetNewImageSize against the original image dimensions. Requests
that ask for more pixels than the source now get the source resolution back,
scaled to the requested aspect ratio. Downscaling paths are untouched, and
DrawingUtils.Resize keeps its existing behaviour for the transcoding callers in
EncodingJobInfo and StreamInfo, which legitimately size video output.
ResizeFill already refused to upscale; this makes width/height consistent
with fillWidth/fillHeight.
Fixes#17056.
This makes the deletion of BaseItemProviders, BaseItemImageInfos, and BaseItemMetadataFields happen in batch as a contiguous block so the lock isn't held across items, just before the bulk SaveChanges.
Using ExecuteAndCapture (and the async version) requires something to manage the captured exception, which we don't do. Errors would be silently dropped and the writes/deletes treated as if they succeeded.
If left at Default, sqlite3_enable_shared_cache is process-global, so a plugin enabling it makes these connections share a cache too.
Contention then surfaces as SQLITE_LOCKED ("database table is locked"), which the busy handler does not cover, busy_timeout is skipped and the command fails at CommandTimeout instead.
`GetItemValues` -- the shared path behind `/Artists`, `/AlbumArtists`, `/Genres`,
`/MusicGenres` and `/Studios` -- disabled the total record count whenever the
query carried no `Limit`:
if (!filter.Limit.HasValue)
{
filter.EnableTotalRecordCount = false;
}
A request without an explicit limit therefore came back with N entries in `Items`
and `TotalRecordCount = 0`. Clients that page on the reported total -- the
documented contract every other list endpoint honours -- read that as an empty
library. `/Items` and `/Persons` do not share this path and report the count
correctly, which is what makes the inconsistency visible from the outside.
Measured against master with a 62-track music library:
GET /Artists?UserId=... -> TotalRecordCount=0 Items=5
GET /Artists?UserId=...&limit=100 -> TotalRecordCount=5 Items=5
Dropping the block costs nothing: `representativeIds` is materialised into a
`List<Guid>` a few lines below regardless, so `.Count` was already available and
the count is now reported from it. Callers that genuinely want to skip the count
still can -- `EnableTotalRecordCount = false` is honoured as before.
The block also mutated the caller's own query object, so a query instance reused
across calls silently lost its total after the first limitless one. That is
covered by a test as well.
`GetProgressiveAudioFullCommandLine` forced the raw PCM muxer and a bogus
sample rate whenever the audio encoder was `pcm_*`, regardless of the
container the client asked for. Two separate failures came out of it:
- `-ar ` + `state.BaseRequest.AudioBitRate` used a *bitrate* as a *sample
rate*, and `AudioBitRate` is optional. When it is absent the argument
degrades to a bare `-ar`, ffmpeg aborts with `Expected number for ar but
found: -ar` / `Error opening output files: Invalid argument` (exit 234)
and the request fails with HTTP 500. Every `GET /Audio/{id}/stream.wav`
that does not carry an explicit `AudioBitRate` hits this.
The sample rate was already being set correctly a few lines below from
`OutputAudioSampleRate`, so the line is dropped rather than repaired.
- `-f s16le` overrode the muxer even for a real container. A request that
did supply a bitrate (`/Audio/{id}/universal` passes
`MaxStreamingBitrate`) survived the first bug but produced raw headerless
samples served under an `audio/wav` content type, so clients saw a body
with no RIFF header. The raw muxer is now only forced when the requested
container is actually raw PCM, which keeps the I2S/MCU route from #10321
working.
Also drop the `containerInternal = ".pcm"` assignment in
`StreamingHelpers.GetStreamingState`: it is written after
`state.OutputContainer` has already been read from the same variable and is
never read again, so it has no effect and only obscures where the output
container comes from.
Verified against ffmpeg 8.1.2 with a 96 kHz FLAC source: before, the wav
command line exits 234; after, it produces a valid `RIFF/WAVE` 48 kHz stereo
`pcm_s16le` file, while the raw `.pcm` route still yields exactly
2 s x 48000 x 2ch x 2 B = 384000 bytes of headerless samples.
This is a nasty one. The failure mode is:
1. Request A started FFmpeg and waited for a segment.
2. Request B requested an earlier or far away segment.
3. Jellyfin thought FFmpeg should to restart at a different position.
4. Request B killed the existing transcoding job.
5. Killing that job cancelled the same token request A was using.
6. The cancellation produced http 500 to request A.
To fix this:
we lock transcoding job state changes and segment handling per playlist, and use a thread safe counter to track how many http responses are still using each job’s segments. A job is only stopped or replaced once that counter reaches zero.
AddParts replaces _metadataProviders but left _metadataProviderCache
holding provider arrays from the previous registration. Invalidate the
cache so repeated AddParts calls cannot serve stale providers, and give
the previously uncalled ClearMetadataProviderCache its intended caller.
Prevent FFmpeg's SIDX path from rewriting open-GOP boundary packet timestamps. HLS uses the media playlist for segment indexing and does not require the SIDX box.
Some ffmpeg build might output extremely long traces for its banner that consume all pipe capacity and hangs the process. We have to drain both streams regardless on which one we actually read.
A query sorted by a user-dependent key (PlayCount, IsFavoriteOrLiked,
DatePlayed, IsPlayed, IsUnplayed) but carrying no User caused a
NullReferenceException inside UserDataManager.GetUserData, surfacing as
"Failed to compare two elements in the array" (InvalidOperationException
wrapping the NRE from the LINQ sort) and 500-ing the /Items request.
Root cause: LibraryManager.GetComparer assigned comparer.User = user
without a null guard, so PlayCountComparer.GetValue called
UserDataManager.GetUserData(null, item), dereferencing user.Id.
Two-part fix:
- LibraryManager.GetComparer: when user is null and the sort key requires a
user (IUserBaseItemComparer), substitute the SortName comparer so the
result stays deterministic instead of 500-ing. SortName is the project's
canonical tiebreaker (ItemsController injects it for album-by-artist).
- UserDataManager.GetUserData: ArgumentNullException.ThrowIfNull(user) as
defense in depth (matches the existing guards on the SaveUserData
overloads in the same file). On master this overload was rewritten to use
ResolveUserDataRow, so the NRE dereferences user.Id rather than
user.InternalId as on the release branch — same bug, different line.
Also fixes DateLastMediaAddedComparer being statically mis-tagged as
IUserBaseItemComparer: its GetDate is static and never reads User, so it
does not need one. Without this, the SortName fallback above would wrongly
engage for DateLastContentAdded on anonymous queries (returning SortName
order instead of date order). Re-tagged to IBaseItemComparer and dropped the
unused User/UserManager/UserDataManager properties.
Tests:
- UserDataManagerTests.GetUserData_NullUser_ThrowsArgumentNullException:
reproduces the crash (NRE -> now ArgumentNullException). Added to master's
existing UserDataManagerTests.
- LibraryManagerSortTests.Sort_UserDependentKey_NullUser_FallsBackToSortNameWithoutThrowing:
Sort with a user-dependent key + null user no longer throws and returns
items ordered by the SortName fallback (direction preserved).
- LibraryManagerSortTests.Sort_DateLastContentAdded_NullUser_OrdersByDateNotSortName:
guards that DateLastContentAdded still sorts by date with no user (fixture
chosen so date-desc and SortName-desc disagree, so a revert is caught).
Full Jellyfin.Server.Implementations.Tests suite: 642 passed, 0 failed.
Fixes#17393
BackupServiceTests rooted its temp directory under Path.GetTempPath(), which
on GitHub-hosted windows-latest runners resolves to the constrained system C:
drive. BackupService.CreateBackupAsync requires 5GiB free at the backup path
before starting, and the C: drive's free temp space can dip below that,
failing CreateBackupAsync_WithCorruptKeyframeDataRow_SkipsRowAndCompletesBackup
even though the fix itself is correct. Rooting the test directory under
AppContext.BaseDirectory keeps it on the same (much larger) drive as the repo
checkout on all platforms, without touching the real BackupService free-space
check.
Addresses review feedback from @Bond-009 on PR #17370: the test helper
InvokeUpdateItem was invoking the private UpdateItem(BaseItemDto, BaseItem)
method via reflection. Jellyfin.Api.csproj already grants
InternalsVisibleTo("Jellyfin.Api.Tests"), so the method is changed to
internal and the test now calls it directly, removing the
GetMethod/Invoke boilerplate.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Per review feedback from cvium: failing to read/backup an entity due to
corrupt underlying data is a significant event that should be surfaced
as an error, not silently downgraded to a warning.
* Prevent ffmpeg from hanging extracting subtitles
Add `RunSubtitleExtractionProcess` to unify the external
_ffmpeg_ process handling and error management.
Add a `-nostdin` flag that prevents _ffmpeg_ from reading from
_stdin_ and blocking on an inherited stdin handle (e.g. when
Jellyfin runs as a service under NSSM), which otherwise hangs
subtitle extraction forever when _ffmpeg_ blocks on any
keyboard-interaction read until the timeout (30 minutes).
Close the redirected _stdin_ to ensure immediage EOF.
Drain the _stderr_ to a string and log it, to ensure we don't block
the _ffmpeg_ process on errors that exceed the pipe length.
Pass `-y` to _ffmpeg_ to ensure it overwrites any existing output file
without prompting for confirmation.
* Address review comments
Make sure we always drain stderr.
Make sure the timeout also honors the cancellationToken.
Make sure when we get cancelled we don't log it as a ffmpeg error.
* show production companies instead of networks
* keep both production companies and networks
* fix whitespace
* fix nullable type
* networks first, then production companies
BaseItemDto.Genres, .Tags, and .ProviderIds are plain auto-properties with
no default initializer, so they deserialize to null when a client omits
them from a partial POST /Items/{itemId} body. The OpenAPI spec documents
every BaseItemDto field as optional, but ItemUpdateController.UpdateItem
fed these three properties straight into Distinct()/Select()/ToList()
without a null check, so a request that (for example) only sets Tags
throws ArgumentNullException("source") once it reaches the unguarded
Genres line, before Tags is even processed.
Guard all three assignments with the same "if (request.X is not null)"
pattern already used for the neighboring Studios/Taglines/ProductionLocations
fields in this method, so omitted fields are left unchanged instead of
crashing the request.
Adds ItemUpdateControllerTests covering the reported repro (only Tags
supplied) and a companion case asserting existing Genres/ProviderIds are
preserved when omitted from the payload.
Signed-off-by: zerafachris <christopher.zerafa@blocklabs.io>
A single row with malformed KeyframeTicks JSON (e.g. a truncated array
from an interrupted write) currently aborts the entire backup, because
the try/catch in BackupService.CreateBackupAsync only wraps
serialization of an already-materialized entity, not the enumeration
itself. EF Core throws JsonReaderException from MoveNextAsync() while
materializing the corrupt row, which propagates past that catch block.
Switch to manual enumerator iteration so MoveNextAsync() failures can
be caught per-row, logged as a warning identifying the affected table,
and skipped, allowing the remaining rows and the rest of the backup to
complete.
Fixes#17216
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
SubtitleEncoder.ConvertSubtitles parsed subtitles with libse's static
Subtitle.Parse, which iterates a statically cached list of shared
SubtitleFormat instances. Format parsers keep mutable per-parse state on
the instance, so concurrent subtitle requests corrupted each other's
output (cues mixed across streams and languages, truncated files) or
failed with NullReferenceException when format detection broke down and
Subtitle.Parse returned null.
Parse through the injected ISubtitleParser instead. SubtitleEditParser
instantiates a fresh format parser per call, so requests no longer share
state. Its Parse method now returns the libse Subtitle directly (the
SubtitleTrackInfo flattening was unused since the SubtitleEdit writer
rework) so the writers keep full fidelity such as ASS styling.
The CUDA hwcontext in FFmpeg 8.1 has added support for 10bit
fully-planar formats, but few CUDA filters support them.
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
Format3DParser drops the last character of the final path token: when
IndexOfAny finds no more delimiters, the slice is taken with
'index = path.Length - 1', so e.g. "hsbs" is compared as "hsb" and
never matches any rule.
File paths are unaffected because the extension is always the final
token, but directory based media have no extension. For DVD/BluRay
folder rips (BaseVideoResolver parses the folder path via
Set3DFormat), a trailing 3D tag such as
"Gravity (2013) 3d hsbs/BDMV" is silently ignored and Video3DFormat
is never set.
This is a regression from 42a2cc174 which replaced the string.Split
based FlagParser with span slicing; the Split implementation kept the
final token intact.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ExecuteUpdateAsync bypasses the EF change tracker, so the user entity
returned by AuthenticateUser still carried the old LastLoginDate and
LastActivityDate. SessionManager.LogSessionActivity then saved that
stale entity in full, reverting LastLoginDate (usually to null)
milliseconds after every login. Setting the properties on the entity
keeps the follow-up save consistent and lets the 60-second activity
guard skip the redundant write during login.
Fixes#17301
Explicitly set StandardErrorEncoding and StandardOutputEncoding to
Encoding.UTF8 when invoking the FFmpeg subprocess.
This prevents log encoding issues and character corruption on Windows
environments that default to non-UTF8 ANSI code pages.
This fixes garbled metadata and font names in the FFmpeg logs.
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
ClearProfileImageAsync removed the ProfileImage instance attached to the
passed-in User, but that instance can carry a stale, never-persisted
(temporary) key because UpdateUserAsync creates the persisted image on a
separately loaded entity and never copies the generated key back.
Removing that detached entity on a fresh DbContext made EF Core throw
InvalidOperationException ('ImageInfo.Id has a temporary value'), leaving
the profile image impossible to delete or replace.
Load the tracked, persisted user and remove its actual ProfileImage,
matching the removal pattern already used in UpdateUserAsync. Adds
regression tests covering the temporary-key case and the no-image no-op
(the first fails before this change and passes after).
Fixes#13137
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds tvdb alias for tvdbid and imdb alias for imdbid.
It also fixes an issue where tmdb alias was being ignored
if it was followed by something like "tmdbidfoo".
The same issue prevented imdb pattern matching from
working, if it was followed by something like "imdbidfoo".
It also allows for detecting the first matching occurence,
whether it was an alias or not.
Finally, it ignores attributes with values consisting of only whitespaces.
DateTime.TryParse without an IFormatProvider falls back to the current
thread culture, so the same string can parse differently (or fail)
depending on the server's locale. None of these call sites deal with
user-entered text - they parse dates that come from filenames, an
HTTP header, ffprobe metadata and values the app itself wrote to the
auth database - so InvariantCulture is the correct provider everywhere
here.
Fixes the S6580 / CA1305 warnings on these call sites.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three index bugs in PlayQueueManager, two of which leave
PlayingItemIndex out of bounds, making every subsequent Buffering/Ready
request throw and leaving the group unusable until it empties:
- RemoveFromPlaylist did not compensate for removed items preceding the
playing item: removing the playing item together with earlier items
could select the wrong item or crash with an out-of-bounds index.
- Next/Previous on an empty playlist with RepeatOne/RepeatAll reported
success or set PlayingItemIndex to 0 on an empty list, crashing
downstream in Group and corrupting the index.
- SetPlayingItemByIndex accepted an index equal to the playlist count
(latent off-by-one, callers currently pre-validate).
When a client polls the HLS playlist (e.g. live.m3u8) after a live stream has
been disposed because its consumer count dropped to zero,
GetLiveStreamWithDirectStreamProvider returns a null MediaSource. The live
branch of GetStreamingState then dereferenced it unconditionally, throwing a
NullReferenceException and returning HTTP 500 for every poll until the client
re-opens the stream. Guard against the null MediaSource and throw
ResourceNotFoundException so the request returns 404 instead of crashing.
Fixes#17009
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address review feedback:
- Replace typeof(Person).FullName with IItemTypeLookup.BaseItemKindNames
- Replace foreach+ToListAsync with PartitionEagerAsync for batched
iteration with built-in progress reporting
- Check HasImage/HasOverview on the loaded domain Person object
instead of projecting from the DB query
Instead of re-checking image/overview on the domain object after loading,
project the values directly from the database query as part of the
anonymous type selection. This avoids redundant checks since the DB
already has this information.
Instead of loading all people names and checking each one in memory,
query the database directly for Person items that need refresh:
- Missing primary image OR missing overview
- Not refreshed within the last 30 days
This reduces the operation from N+1 queries (1 for all names + 1 per
person to load) to a single filtered query returning only the IDs that
need work.
Move image refresh logic from PeopleValidator (which runs during library
scans) into PeopleValidationTask (the "Refresh People" scheduled task).
This keeps library scans fast while ensuring the scheduled task fetches
missing images from remote providers like TMDB.
People missing a Primary image or overview get refreshed with
MetadataRefreshMode.Default instead of ValidationOnly, with a 30-day
cooldown to avoid hammering providers for people they have no data for.
Fixes jellyfin#8103
The request path is not validated to a valid path and could allow escaping the transcode path and downloading of any arbitrary file in GetHlsPlaylistLegacy .
GetHlsAudioSegmentLegacy and GetHlsVideoSegmentLegacy have the same issue, and are NOT behind an Authorize so they are publicly exploitable.
Added a ValidateTranscodePath that verifies that requested file paths start with the transcode path setting. Also ensure that all filename comparisons are OrdinalIgnoreCase because we might be running on a filesystem where filename-casing doesn't have to match. Switched from InvariantCulture because the underlying OS filename comparisons are always byte-wise (with case insensitivity here).
Fixed a similar issue in GetPluginImage
Added static method GetBaseItemKindsForCollectionType in ItemsController (moved from ContentFolderImageProvider to be shared)
Added AudioBook to GetRepresentativeItemTypes for CollectionType.books for consistency
Added GetBooks to GetUserItems for CollectionType.books which gets BaseItemKind.Book and BaseItemKind.AudioBook
Move GetBaseItemKindsForCollectionType to DtoExtensions
Cleaned up the missing null checks and used new collection expressions.
Associate Person to Book and AudioBook for related items.
When the server finishes starting, show "Jellyfin started successfully" with a
5-second "Redirecting in N…" countdown and a Cancel button instead of reloading
immediately. Cancel stops the countdown and the background refresh so the
startup output can be reviewed, and offers a "Continue to Jellyfin" button to
reload manually. The buttons use the web client's emby-button styling.
Also drop the transitional "Applying migrations" activity: it only showed
briefly while the pending migration set was read, or for the whole step when
nothing was pending, so startup now goes from "Preparing migrations" straight
into "Running migration X of Y".
Prevents raw ISO-639-2 values (e.g. "Greek, Modern (1453-)" from cluttering the audio and subtitle display names by truncating them at the first comma or semicolon ("Greek"). Applies to MediaStreamRepository and ProbeResultNormalizer.
Order the startup log oldest-to-newest inside a height-bounded panel that
scrolls internally and never extends past the bottom of the window. Refresh it
with a background fetch that swaps the log list in place instead of reloading
the whole page, preserving the user's scroll position and only following to the
bottom when they are already there. A full page reload now happens only on the
final transition to the running server or to the error state.
Restyle the startup/migration holding page to match the Jellyfin dark theme,
with the inline wordmark logo, a gradient spinner and a recolored startup log
tree, and move the Morestachio template rendering into a reusable
StartupUiRenderer.
Add a curated, non-identifying "current activity" line to the always-visible
header (for example "Initializing server" or "Running migration X of Y"),
reported from the startup flow and the migration service so it never leaks
server details to unauthenticated clients. Move the log download into a
"Download logs" link in the log panel header, and show only the header, with
no log hints, to non-local clients.
After resolving duplicates the migration deleted all items in one silent
pass (per-id GetItemById plus a single DeleteItemsUnsafeFast), which looks
hung for minutes on large libraries. Delete in batches of 500 and log
progress per batch, which also avoids one oversized delete transaction.
The FixIncorrectOwnerIdRelationships migration deletes all duplicate
items in a single DeleteItemsUnsafeFast -> DeleteItem(ids) call. Inside
DeleteItem, the owned-extras lookup used a raw HashSet.Contains, which EF
inlines as one SQL variable per id and overflows SQLite's variable limit
on large libraries. Use WhereOneOrMany so the id set is bound as a single
json_each parameter, like the rest of the method, making bulk deletes
work for unlimited library sizes.
Resolve GuideManager conflict by keeping LiveTvChannelImageHelper so
channel icons re-fetch on every guide refresh, including when the URL
is unchanged.
Without this change it's self healing after the 3rd cycle.
It also appears there may be an issue with this etag "skip if hash hasn't changed" for schedules direct functionality.... like it never will work. But out of scope here.
Also fixed Sonar gripes about code formatting
HA Build & Push to ECR / build-and-push (push) Has been cancelled
Upstream Jellyfin 10.11.7 targets net9.0. Our PostgreSQL provider was on
net10.0 with Npgsql.EntityFrameworkCore.PostgreSQL 10.0.0 which requires
EF Core 10+. Downgrade to 9.0.4 to match upstream's EF Core 9.0.11.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: add architecture overview, contributing guide, and GitHub discussion draft
ARCHITECTURE.md covers server layer diagram, subsystems, and runtime info.
CONTRIBUTING.md covers dev setup, build, test, and submission workflow.
GITHUB-DISCUSSION-DRAFT.md drafts the upstream discussion post for the HA fork.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: trim verbose comment in Dockerfile.runtime
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
ha-build.yml runs on self-hosted k3s runners. Having pull_request as a
trigger allows any internet user to open a PR against this public repo
and execute arbitrary code on cluster nodes (GitHub does block secret
injection on fork PRs, but runner filesystem and cluster network access
remain).
Removed pull_request trigger. Build-on-push-to-main is sufficient.
CI test feedback on PRs is covered by ci-tests.yml which uses
GitHub-hosted (ubuntu-latest) runners only.
* Initial plan
* Phase 5.2.4: Tune HLS behavior for recovery with configurable segment parameters
Co-authored-by: ZoltyMat <177592743+ZoltyMat@users.noreply.github.com>
* fix: SA1516 — add blank line between MakeLiveStreamKey and Clone helpers
StyleCop SA1516 requires elements to be separated by blank lines.
Missing blank line at line 370 caused build failure in Phase 5 tests.
Closes#28
* fix: SA1516 — blank line in InMemoryTranscodeSessionStore between helpers
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ZoltyMat <177592743+ZoltyMat@users.noreply.github.com>
Co-authored-by: mat <mstrommen@gmail.com>
Map the exact transcode lifecycle before Phase 5.2 code changes begin.
No functional code changes.
Key findings documented:
- _activeTranscodingJobs: process-local, not persisted across pod restarts
- playSessionId: caller-supplied nullable string; three HA failure modes
- DeleteTranscodeFileTask: age-only cleanup, unsafe for shared NFS storage
- _activeLiveStreamSessions: process-local ConcurrentDictionary, cannot be
inherited by a takeover pod without durable store rehydration
- NFSv3 confirmed (nfsvers=3). Close-to-open consistency advisory; recovery
must skip the last incomplete segment and restart one segment earlier
- Minimum recovery state: 10 fields including server-generated sessionId,
ownerPod, manifestPath, lastCompletedSegmentIndex, lastHeartbeatUtc
Closes Phase 5 Issue 5.1.1
Add a dedicated 'run-phase5-tests' job that runs the three test assemblies
most affected by Phase 5 HLS session-sharing and PostgreSQL media-encoding
changes in parallel with the existing full-matrix run-tests job.
Targeted assemblies:
- tests/Jellyfin.Api.Tests (HLS controller surface)
- tests/Jellyfin.MediaEncoding.Hls.Tests (transcode lifecycle)
- tests/Jellyfin.Server.Implementations.Tests (RedisTranscodeSessionStore)
Each test step filters Category!=RequiresDocker to exclude Docker-dependent
tests that require Testcontainers. Coverage results are merged separately
into merged-phase5/ to avoid collisions with the full-matrix merged/ dir.
Closes #(Phase 5.0.4b)
- Add pull_request: trigger so Copilot agent branches get CI coverage
- Add feat/phase* and copilot/* to push branch list
- Add concurrency block to cancel stale runs on same ref
- Set push: false on PR events (build only, no ECR push for PRs)
Previous fixes went to Dockerfile, but CI uses Dockerfile.runtime.
Add webclient stage: installs jellyfin-web=10.11.6+deb12 from the
Jellyfin bookworm apt repo (correct version suffix: +deb12, not +1).
Web assets land at /usr/share/jellyfin/web/ and are copied to
/jellyfin/jellyfin-web/ in the runtime image.
Add --webdir flag to ENTRYPOINT explicitly.
Previous attempt used 10.9.11+1 which does not exist — the bookworm
repo uses +deb12 suffix (e.g. 10.11.6+deb12) and only has >= 10.11.x.
This caused an empty /jellyfin/jellyfin-web/ at runtime, making the
server crash with 'content directory is either invalid or empty'.
Fix: install jellyfin-web=10.11.6+deb12 from the official Jellyfin
bookworm apt repo. Assets land at /usr/share/jellyfin/web/ and are
COPY'd to /jellyfin/jellyfin-web/ in the runtime image.
Pulling from jellyfin/jellyfin:10.9.11 multi-stage yielded an empty
/jellyfin/jellyfin-web directory (the official image likely has a different
internal structure). Switch to the official Jellyfin apt repo instead:
apt-get install jellyfin-web=10.9.11+1
web assets land at /usr/share/jellyfin/web/
COPY to /jellyfin/jellyfin-web/ in runtime image
--webdir /jellyfin/jellyfin-web is already in ENTRYPOINT.
wwwroot/ only contained api-docs (Swagger) — the web client was never bundled.
Add a webclient stage that pulls /jellyfin/jellyfin-web from jellyfin/jellyfin:10.9.11
and copies it to /jellyfin/jellyfin-web in the runtime image.
Pass --webdir /jellyfin/jellyfin-web to the entrypoint so the server serves the UI.
jellyfin-web 10.9.11 is API-compatible with the 10.12.0 server fork.
Update to a matching 10.12.x web client once that release ships upstream.
- MigrationBackupFast/RestoreBackupFast/DeleteBackup return no-ops for
PostgreSQL; pre-migration backups are handled by jellyfin-pg-backup
CronJob, not the automated backup path that throws NotSupportedException
- ServiceCollectionExtensions: detect postgresql:// / postgres:// URI
format in POSTGRES_CONNECTION_STRING and convert to ADO.NET key=value
format before passing to NpgsqlDataSourceBuilder (which requires it)
Closes startup crash: 'Automated migration backups are not supported for
PostgreSQL' on first boot with a fresh database.
The NpgsqlDataSource singleton factory in AddJellyfinDbContext calls
sp.GetRequiredService<IServerConfigurationManager>() to read pool settings.
During ApplyStartupMigrationAsync, only a subset of services are registered
in the startup service collection — IServerConfigurationManager was missing,
causing a fatal DI resolution failure when DatabaseType=Jellyfin-PostgreSQL.
Fix: register startupConfigurationManager as IServerConfigurationManager in
the migrationStartupServiceProvider service collection.
Also remove JELLYFIN_CONFIG_DIR=/config from Dockerfile.runtime ENV block.
When configDir == dataDir, MakeSanityCheckOrThrow writes .jellyfin-config at
the datadir root, then immediately throws because it expected .jellyfin-data.
Removing the env var lets configDir default to $JELLYFIN_DATA_DIR/config.
DinD overlay-on-overlay throttles dotnet child container to ~11s CPU/3h wall time.
Solution: dotnet restore+publish run on native runner FS (~10min), then
Dockerfile.runtime just COPYs the pre-built publish-output/ directory.
This brings build time from 3h+ (stuck) to ~10-15 minutes total.
setup-dotnet fails on ARC runners (no permission to /usr/share/dotnet) and dotnet
is not pre-installed. Install via dotnet-install.sh into $HOME/.dotnet instead,
then add to PATH via GITHUB_PATH.
setup-dotnet fails on self-hosted ARC runners because it cannot write to
/usr/share/dotnet (permission denied). The runner images already have .NET 10
SDK installed in DOTNET_ROOT. Remove the step entirely.
- Add [Trait("Category", "RequiresDocker")] to all 3 PostgreSQL test classes
(PostgreSqlMigrationTests, PostgreSqlProviderTests, PostgreSqlConcurrencyTests)
- Add --filter "Category!=RequiresDocker" to ci-tests.yml dotnet test command
so runners without Docker don't fail on Testcontainers initialization
- Disable CodeQL workflow in fork (requires upstream org permissions + .NET 10
CodeQL support that isn't available on our self-hosted runners)
PostgreSQL tests still run in ha-build.yml against the cluster where Docker
is available via the self-hosted ARC runners.
StyleCop analyzer violations in upstream src/Jellyfin.Extensions/ block
the Docker build when TreatWarningsAsErrors=true (from Directory.Build.props).
Disable for container image builds — StyleCop enforcement is the CI pipeline's
responsibility, not the Dockerfile's.
dotnet publish failed with CS2001 because these root-level analyzer config files
were not included in the Docker build context. They are referenced by
Directory.Build.props and required by StyleCop and BannedApiAnalyzers at build
time.
* Initial plan
* Add NpgsqlDataSource pool wiring to DI (Issue 1.4)"
- PostgreSqlDatabaseProvider: accept NpgsqlDataSource via constructor injection, use it in Initialise()
- PostgreSqlDesignTimeJellyfinDbFactory: build NpgsqlDataSource from connection string for design-time use
- ServiceCollectionExtensions: register NpgsqlDataSource as singleton with pool params (MinPoolSize=2, MaxPoolSize=20, CommandTimeout=30) from CustomProviderOptions.Options
Co-authored-by: ZoltyMat <177592743+ZoltyMat@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ZoltyMat <177592743+ZoltyMat@users.noreply.github.com>
-copyts is unnecessary for -c:s copy to SRT and slows extraction ~5x.
Without -flush_packets 1, ffmpeg buffers all output until exit, leaving
.srt files at 0 bytes for minutes while the player shows no subtitles.
Fixes#16438
Hotfix — replaces pull_request_target with pull_request to stop
granting write permissions and secrets to fork PRs. Some workflows
will break; can be fixed properly later.
When items are removed during a library scan, their user data is
detached to a placeholder. If a replacement item already exists
(e.g., a new version of the same episode was added before the old
file was deleted), the user data would be stranded in the placeholder
because the replacement item's initial ReattachUserDataAsync call
happened before the old item was deleted.
This fix checks for remaining valid children that share user data
keys with removed items and reattaches any detached user data to them.
Fixes#16149
Deduplicate ProviderIds by ProviderId during MigrateLibraryDb migration
to prevent UNIQUE constraint violations when legacy data contains
duplicate provider entries for the same item.
Fixes#16134
for file in Jellyfin.Data.dll MediaBrowser.Common.dll MediaBrowser.Controller.dll MediaBrowser.Model.dll Emby.Naming.dll Jellyfin.Extensions.dll Jellyfin.MediaEncoding.Keyframes.dll Jellyfin.Database.Implementations.dll; do
This issue has gone 120 days without an update and will be closed within 21 days if there is no new activity. To prevent this issue from being closed, please confirm the issue has not already been fixed by providing updated examples or logs.
If you have any questions you can use one of several ways to [contact us](https://jellyfin.org/contact).
Logger.LogWarning("The startup wizard is marked incomplete but a configured administrator already exists. Marking setup as completed to prevent the unauthenticated setup endpoints from being reachable.");
_logger.LogInformation("Deleting dead {ItemType} {ItemId} {ItemName}",item.GetType().Name,item.Id.ToString("N",CultureInfo.InvariantCulture),item.Name);
"TaskAudioNormalizationDescription":"يفحص الملفات لجمع بيانات تطبيع الصوت.",
"TaskDownloadMissingLyrics":"تنزيل الكلمات المفقودة",
"TaskDownloadMissingLyricsDescription":"ينزّل الكلمات للأغاني.",
"TaskDownloadMissingLyricsDescription":"تحميل كلمات الأغاني",
"TaskExtractMediaSegments":"فحص مقاطع المحتوى",
"TaskExtractMediaSegmentsDescription":"يستخرج أو يحصل على مقاطع المحتوى من الملحقات المفعّلة لمقاطع المحتوى (MediaSegment).",
"TaskMoveTrickplayImages":"نقل موقع صور معاينات التنقل",
@@ -108,5 +108,18 @@
"CleanupUserDataTask":"مهمة تنظيف بيانات المستخدم",
"CleanupUserDataTaskDescription":"ينظف جميع بيانات المستخدم (مثل حالة المشاهدة وحالة المفضلة وغيرها) للمحتوى الذي لم يعد موجوداً لمدة 90 يوماً على الأقل.",
"Original":"فريد",
"LyricDownloadFailureFromForItem":"فشل تحميل الكلمات من {0} إلى {1}"
"LyricDownloadFailureFromForItem":"فشل تحميل الكلمات من {0} إلى {1}",
"TaskMoveTrickplayImages":"Перанесці месцазнаходжанне выявы Trickplay",
"CleanupUserDataTask":"Задача па ачыстцы даных карыстальніка",
"CleanupUserDataTaskDescription":"Ачышчае ўсе даныя карыстальніка (стан прагляду, абранае і г.д.) для медыяфайлаў, што адсутнічаюць больш за 90 дзён."
"CleanupUserDataTaskDescription":"Ачышчае ўсе даныя карыстальніка (стан прагляду, абранае і г.д.) для медыяфайлаў, што адсутнічаюць больш за 90 дзён.",
"LyricDownloadFailureFromForItem":"Не ўдалося загрузіць тэкст песні з {0} для {1}",
"TaskMoveTrickplayImagesDescription":"Премества съществуващите trickplay изображения спрямо настройките на библиотеката.",
"TaskExtractMediaSegments":"Сканиране за сегменти",
"CleanupUserDataTask":"Задача за почистване на потребителски данни",
"CleanupUserDataTaskDescription":"Почиства всички потребителски данни (статус на гледане, любими и т.н.) от медия, която вече не е налична от поне 90 дни."
"CleanupUserDataTaskDescription":"Почиства всички потребителски данни (статус на гледане, любими и т.н.) от медия, която вече не е налична от поне 90 дни.",
"LyricDownloadFailureFromForItem":"Текстът на песента не успя да се изтегли от {0} за {1}",
"CleanupUserDataTaskDescription":"Čisti sve korisničke podatke (stanje praćenja, status omiljenog itd.) sa medija koji više nije prisutan najmanje 90 dana."
"CleanupUserDataTaskDescription":"Čisti sve korisničke podatke (stanje praćenja, status omiljenog itd.) sa medija koji više nije prisutan najmanje 90 dana.",
"CleanupUserDataTaskDescription":"Neteja totes les dades d'usuari (estat de la visualització, estat dels preferits, etc.) del contingut multimèdia que no ha estat present durant almenys 90 dies.",
"CleanupUserDataTask":"Tasca de neteja de dades d'usuari",
"Original":"Original",
"LyricDownloadFailureFromForItem":"No s'han pogut descarregar les lletres des de {0} per a {1}"
"LyricDownloadFailureFromForItem":"No s'han pogut descarregar les lletres des de {0} per a {1}",
"TaskRefreshChapterImagesDescription":"Laver miniaturebilleder for videoer, der har kapitler.",
"TaskRefreshChannelsDescription":"Opdaterer information for internetkanaler.",
"TaskRefreshChannels":"Opdater kanaler",
"TaskCleanTranscodeDescription":"Fjerner omkodningsfiler, som er mere end 1 dag gamle.",
"TaskCleanTranscode":"Tøm omkodningsmappen",
"TaskRefreshPeople":"Opdater personer",
"TaskRefreshChannels":"Opdatér kanaler",
"TaskCleanTranscodeDescription":"Fjerner transkodningsfiler, som er mere end 1 dag gamle.",
"TaskCleanTranscode":"Tøm transkodningsmappen",
"TaskRefreshPeople":"Opdatér personer",
"TaskRefreshPeopleDescription":"Opdaterer metadata for skuespillere og instruktører i dit mediebibliotek.",
"TaskCleanActivityLogDescription":"Sletter linjer i aktivitetsloggen ældre end den konfigurerede alder.",
"TaskCleanActivityLog":"Ryd aktivitetslog",
@@ -90,7 +90,7 @@
"Forced":"Tvunget",
"Default":"Standard",
"TaskOptimizeDatabaseDescription":"Komprimerer databasen for at frigøre plads. Denne handling køres efter at have scannet mediebiblioteket, eller efter at have lavet ændringer til databasen.",
"TaskOptimizeDatabase":"Optimer database",
"TaskOptimizeDatabase":"Optimér database",
"TaskKeyframeExtractorDescription":"Udtrækker rammer fra videofiler for at lave mere præcise HLS-playlister. Denne opgave kan tage lang tid.",
"TaskKeyframeExtractor":"Udtræk nøglerammer",
"External":"Ekstern",
@@ -99,7 +99,7 @@
"TaskRefreshTrickplayImagesDescription":"Laver trickplay-billeder for videoer i aktiverede biblioteker.",
"TaskAudioNormalizationDescription":"Skanner filer for data vedrørende lydnormalisering.",
"TaskAudioNormalization":"Lydnormalisering",
"TaskDownloadMissingLyricsDescription":"Søger på internettet efter manglende sangtekster baseret på metadata-konfigurationen",
"CleanupUserDataTask":"Aufgabe zur Bereinigung von Benutzerdaten",
"CleanupUserDataTaskDescription":"Löscht alle Benutzerdaten (Abspielstatus, Favoritenstatus, usw.) von Medien, die seit mindestens 90 Tagen nicht mehr vorhanden sind.",
"Original":"Original",
"LyricDownloadFailureFromForItem":"Fehler beim Download der Songtexte von {0} für {1}"
"LyricDownloadFailureFromForItem":"Fehler beim Download der Songtexte von {0} für {1}",
"CleanupUserDataTaskDescription":"Καθαρίζει όλα τα δεδομένα χρήστη (κατάσταση παρακολούθησης, κατάσταση αγαπημένων κ.λπ.) από πολυμέσα που δεν υπάρχουν πλέον για τουλάχιστον 90 ημέρες.",
"CleanupUserDataTaskDescription":"Cleans all user data (Watch state, favourite status etc) from media that is no longer present for at least 90 days.",
"LyricDownloadFailureFromForItem":"Lyrics failed to download from {0} for {1}",
"CleanupUserDataTaskDescription":"Limpia todos los datos del usuario (estado de visualización, estado de los favoritos, etc.) que no están presentes en la biblioteca por al menos 90 días.",
"CleanupUserDataTask":"Tarea de limpieza de datos de usuarios",
"LyricDownloadFailureFromForItem":"No se pudo descargar la letra desde {0} para {1}",
"TaskMoveTrickplayImages":"Migrar la ubicación de la imagen de Trickplay",
"TaskMoveTrickplayImagesDescription":"Mueve archivos de trickplay existentes según la configuración de la biblioteca.",
"CleanupUserDataTask":"Tarea de limpieza de los datos del usuario",
"CleanupUserDataTaskDescription":"Limpia toda la información de usuario (Estado de última vez visto, favoritos, etc) del archivo media que no está presente por los últimos 90 días."
"CleanupUserDataTaskDescription":"Limpia toda la información de usuario (Estado de última vez visto, favoritos, etc) del archivo media que no está presente por los últimos 90 días.",
"LyricDownloadFailureFromForItem":"No se pudo descargar la letra desde {0} para {1}",
"CleanupUserDataTask":"Tarea de limpieza de datos del usuario",
"CleanupUserDataTaskDescription":"Limpia todos los datos del usuario (estado de visualización, favoritos, etc.) de los medios que ya no están disponibles desde hace al menos 90 días.",
"Original":"Original",
"LyricDownloadFailureFromForItem":"No se pudieron descargar las letras desde {0} para {1}"
"LyricDownloadFailureFromForItem":"No se pudieron descargar las letras desde {0} para {1}",
"TaskExtractMediaSegments":"Escaneo de segmentos de medios",
"TaskMoveTrickplayImages":"Migrar la ubicación de la imagen de Trickplay",
"CleanupUserDataTask":"Tarea de limpieza de datos de usuario",
"CleanupUserDataTaskDescription":"Limpia todos los datos de usuario (estado de visualización, favoritos, etc.) que no están presentes en la biblioteca por al menos 90 días."
"CleanupUserDataTaskDescription":"Limpia todos los datos de usuario (estado de visualización, favoritos, etc.) que no están presentes en la biblioteca por al menos 90 días.",
"LyricDownloadFailureFromForItem":"No se pudo descargar las letras de {0} para {1}",
"CleanupUserDataTaskDescription":"Puhastab kõik kasutajaandmed (vaatamise olek, lemmikute olek jne) meediast, mida pole enam vähemalt 90 päeva saadaval olnud.",
"CleanupUserDataTaskDescription":"Gutxienez 90 egunez dagoeneko existitzen ez den multimediatik erabiltzaile-datu guztiak (ikusteko egoera, gogokoen egoera, etab.) garbitzen ditu.",
"CleanupUserDataTask":"Erabiltzaileen datuak garbitzeko zeregina",
"LyricDownloadFailureFromForItem":"Ezin izan dira {1}-ren letrak deskargatu {0}-tik",
"CleanupUserDataTaskDescription":"Puhdistaa kaikki käyttäjätiedot (katselutila, suosikit ym.) medioista, joita ei ole ollut saatavilla yli 90 päivään.",
"CleanupUserDataTaskDescription":"Strikar allar brúkaradátur, so sum spælistøðu, yndislistastøðu o.s.fr., fyri miðlar ið ikki hava verið tøkir í í minsta lagi 90 dagar.",
"TaskRefreshPeopleDescription":"Dagførur metadátur um leikarar og leikstjórar í tínum margmiðlasavni.",
"TaskRefreshChannelsDescription":"Dagførur upplýsingar um alnetsrásir.",
"TaskDownloadMissingSubtitlesDescription":"Leitar á alnótini eftir vantandi undirtekstum grundað á metadátauppsetan.",
"NotificationOptionTaskFailed":"Brek undir fyriskipaðari koyrslu",
"TaskRefreshLibraryDescription":"Skannar títt miðlasavn fyri nýggjum fílum og dagførur metadátur.",
"TaskKeyframeExtractor":"Lyklamyndaúttøka",
"TaskKeyframeExtractorDescription":"Úttekur lyklamyndir frá kykmynda-fílum til tess at byggja nágreiniligari HLS-spælilistar. Koyrslan kann taka langa tíð.",
"TaskOptimizeDatabaseDescription":"Trýstur dátugrunninin saman og loysur tóma goymslu. Koyrslan kann bøta um avrikið, eftir skanning ella aðrar broytingar í savninum ið elva til dátugrunnsbroytingar.",
"TaskRefreshChapterImagesDescription":"Ger smámyndir fyri kykmyndir ið hava kapitlar.",
"CleanupUserDataTaskDescription":"Nettoie toutes les données utilisateur (état de la montre, statut favori, etc.) des supports qui ne sont plus présents depuis au moins 90 jours.",
"CleanupUserDataTask":"Tâche de nettoyage des données utilisateur",
"LyricDownloadFailureFromForItem":"Le téléchargement des paroles a échoué de {0} pour {1}",
"CleanupUserDataTaskDescription":"Nettoie toutes les données utilisateur (état de la montre, statut favori, etc.) des supports qui ne sont plus présents depuis au moins 90 jours.",
"CleanupUserDataTask":"Tâche de nettoyage des données utilisateur",
"LyricDownloadFailureFromForItem":"Le téléchargement des paroles à échoué de {0} pour {1}",
"CleanupUserDataTaskDescription":"Glanann sé gach sonraí úsáideora (stádas faire, stádas is fearr leat srl.) ó mheáin nach bhfuil i láthair a thuilleadh ar feadh 90 lá ar a laghad.",
"Original":"Bunaidh",
"LyricDownloadFailureFromForItem":"Theip ar liricí a íoslódáil ó {0} do {1}"
"LyricDownloadFailureFromForItem":"Theip ar liricí a íoslódáil ó {0} do {1}",
"NameExtraBehindTheScenes":"Taobh thiar de na Radhairc",
"TaskRefreshTrickplayImages":"Xerar miniaturas de previsualización",
"TaskAudioNormalizationDescription":"Escanea ficheiros á procura de datos de normalización de volume.",
"CleanupUserDataTask":"Tarefa de limpeza de datos dos usuarios",
"CleanupUserDataTaskDescription":"Limpa todos os datos do usuario (estado de visualización, de favorito etc.) dos medios ausentes polo menos 90 días."
"CleanupUserDataTaskDescription":"Limpa todos os datos do usuario (estado de visualización, de favorito etc.) dos medios ausentes polo menos 90 días.",
"Original":"Orixinal",
"LyricDownloadFailureFromForItem":"Non se puideron descargar as letras desde {0} para {1}",
"NameExtraBehindTheScenes":"Detrás das Cámaras",
"NameExtraClip":"Clip",
"NameExtraDeletedScene":"Escena Eliminada",
"NameExtraFeaturette":"Reportaxe especial",
"NameExtraInterview":"Entrevista",
"NameExtraNumbered":"{0} {1}",
"NameExtraSample":"Mostra",
"NameExtraScene":"Escena",
"NameExtraShort":"Curtametraxe",
"NameExtraThemeSong":"Canción principal",
"NameExtraThemeVideo":"Vídeo da canción principal",
"CleanupUserDataTaskDescription":"Briše sve korisničke podatke (stanje gledanja, status favorita itd.) s medija koji više nisu prisutni najmanje 90 dana.",
"Original":"Original"
"Original":"Original",
"LyricDownloadFailureFromForItem":"Preuzimanje tekstova pjesmi od {0} za {1} nije uspjelo",
"CleanupUserDataTaskDescription":"Legalább 90 napja nem elérhető médiákhoz kapcsolódó összes felhasználói adat (pl. megtekintési állapot, kedvencek) törlése.",
"CleanupUserDataTask":"Felhasználói adatok tisztítása feladat",
"TaskCleanTranscodeDescription":"Eyða umkóðuðum skrám sem eru meira en einum degi eldri.",
"TaskCleanTranscode":"Hreinsa Umkóðunarmöppu",
@@ -80,7 +80,7 @@
"TasksMaintenanceCategory":"Viðhald",
"Default":"Sjálfgefið",
"TaskCleanActivityLog":"Hreinsa athafnaskrá",
"TaskRefreshPeople":"Endurnýja fólk",
"TaskRefreshPeople":"Endurnýja upplýsingar um fólk",
"TaskDownloadMissingSubtitles":"Sækja texta sem vantar",
"TaskOptimizeDatabase":"Fínstilla gagnagrunn",
"Undefined":"Óskilgreint",
@@ -95,13 +95,31 @@
"TaskCleanActivityLogDescription":"Eyðir virkniskráningarfærslum sem hafa náð settum hámarksaldri.",
"Forced":"Þvingað",
"External":"Útvær",
"TaskRefreshTrickplayImagesDescription":"Býr til hraðspilunarmyndir fyrir myndbönd í virkum söfnum.",
"TaskRefreshTrickplayImages":"Búa til hraðspilunarmyndir",
"TaskRefreshTrickplayImagesDescription":"Býr til hraðspilunarmyndir (Trickplay) fyrir myndbönd í virkum söfnum.",
"TaskRefreshTrickplayImages":"Búa til hraðspilunarmyndir (Trickplay)",
"TaskAudioNormalization":"Hljóðstöðlun",
"TaskAudioNormalizationDescription":"Leitar að hljóðstöðlunargögnum í skrám.",
"TaskDownloadMissingLyricsDescription":"Sækja söngtexta fyrir lög",
"TaskDownloadMissingLyrics":"Sækja söngtexta sem vantar",
"TaskExtractMediaSegments":"Skönnun efnishluta",
"CleanupUserDataTask":"Hreinsun notendagagna",
"CleanupUserDataTaskDescription":"Hreinsar öll notendagögn (spilunarstöðu, uppáhöld o.s.frv.) um gögn sem hafa ekki verið til staðar í að lámarki 90 daga."
"CleanupUserDataTaskDescription":"Hreinsar öll notendagögn (spilunarstöðu, uppáhöld o.s.frv.) um gögn sem hafa ekki verið til staðar í að lámarki 90 daga.",
"LyricDownloadFailureFromForItem":"Ekki tókst að niðurhala texta frá {0} fyrir {1}",
"Original":"Upprunaleg",
"TaskExtractMediaSegmentsDescription":"Sækir myndbúta úr viðbótum þar sem MediaSegment er virkt.",
"TaskMoveTrickplayImages":"Flytja geymslustað fyrir Trickplay-myndir",
"TaskMoveTrickplayImagesDescription":"Flytur fyrirliggjandi Trickplay-skrár í samræmi við stillingar safnsins.",
"CleanupUserDataTask":"Task di pulizia dei dati utente",
"CleanupUserDataTaskDescription":"Pulisce tutti i dati utente (stato di visione, status preferiti, ecc.) dai contenuti non più presenti da almeno 90 giorni.",
"Original":"Originale",
"LyricDownloadFailureFromForItem":"Scaricamento dei testi non riuscito da {0} per {1}"
"LyricDownloadFailureFromForItem":"Scaricamento dei testi non riuscito da {0} per {1}",
"TaskKeyframeExtractorDescription":"Extrahéiert Schlësselbiller aus Videodateien, fir méi präzis HLS-Playlisten ze erstellen. Dës Aufgab kann eng längere Zäit daueren.",
"TaskRefreshChannelsDescription":"Aktualiséiert Informatiounen iwwer Internetkanäl.",
"TaskExtractMediaSegmentsDescription":"Extrahéiert oder kritt Mediesegmenter aus Plugins, déi MediaSegment ënnerstëtzen.",
"TaskOptimizeDatabaseDescription":"Kompriméiert d’Datebank a schneit de fräie Speicherplatz zou. Dës Aufgab no engem Bibliothéik-Scan oder anere Ännerungen, déi Datebankmodifikatioune mat sech bréngen, auszeféieren, kann d’Performance verbesseren."
"TaskOptimizeDatabaseDescription":"Kompriméiert d’Datebank a schneit de fräie Speicherplatz zou. Dës Aufgab no engem Bibliothéik-Scan oder anere Ännerungen, déi Datebankmodifikatioune mat sech bréngen, auszeféieren, kann d’Performance verbesseren.",
"LyricDownloadFailureFromForItem":"Feeler beim Download vun de Songtexter vun {0} fir {1}",
"Original":"Original",
"CleanupUserDataTask":"Aufgab fir Berengege vu Benotzerdaten",
"CleanupUserDataTaskDescription":"Läscht all Benotzerdaten (Ofspillstatus, Favoritestatus, asw.) vu Medien, déi zënter mindestens 90 Deeg net méi besteeënd sinn.",
"TaskCleanLogsDescription":"Ištrina žurnalo failus kurie yra senesni nei {0} dienos.",
"TaskCleanLogs":"Išvalyti žurnalą",
"TaskRefreshChapterImagesDescription":"Sukuria vaizdo įrašų, kuriuose yra skyrių, miniatiūras.",
"TaskRefreshChapterImages":"Ištraukti skyrių vaizdus",
"TaskRefreshChapterImagesDescription":"Sukuria miniatiūras vaizdo įrašams, kuriuose yra skyriai.",
"TaskRefreshChapterImages":"Ištraukti skyrių atvaizdus",
"TaskCleanCache":"Išvalyti talpyklą",
"TaskCleanCacheDescription":"Ištrina talpyklos failus, kurių daugiau nereikia sistemai.",
"TasksChannelsCategory":"Internetiniai kanalai",
@@ -87,7 +87,7 @@
"TaskCleanActivityLog":"Išvalyti veiklos žurnalą",
"Undefined":"Neapibrėžtas",
"Forced":"Priverstinis",
"Default":"Numatytas",
"Default":"Numatytasis",
"TaskCleanActivityLogDescription":"Ištrina senesnius nei nustatytas amžius veiklos žurnalo įrašus.",
"TaskOptimizeDatabase":"Optimizuoti duomenų bazę",
"TaskKeyframeExtractorDescription":"Iš vaizdo įrašo paruošia reikšminius kadrus, kad būtų sukuriamas tikslenis HLS grojaraštis. Šios užduoties vykdymas gali ilgai užtrukti.",
"TaskMoveTrickplayImagesDescription":"Perkelia egzistuojančius Trickplay failus pagal bibliotekos nustatymus.",
"TaskDownloadMissingLyricsDescription":"Atsisiųsti dainų tekstus",
"CleanupUserDataTask":"Naudotojo duomenų valymo užduotis",
"CleanupUserDataTaskDescription":"Iš medijos, kurios nebėra bent 90 dienų, išvalo visus naudotojo duomenis (žiūrėjimo būseną, mėgstamiausią būseną ir t. t.)."
"CleanupUserDataTaskDescription":"Iš medijos, kurios nebėra bent 90 dienų, išvalo visus naudotojo duomenis (žiūrėjimo būseną, mėgstamą būseną ir t. t.).",
"LyricDownloadFailureFromForItem":"Nepavyko atsisiųsti dainos teksto iš {0}, skirto {1}",
"CleanupUserDataTask":"Lietotāju datu tīrīšanas uzdevums",
"CleanupUserDataTaskDescription":"Notīra visus lietotāja datus (skatīšanās stāvokļus, favorītu statusi utt.) no medijiem, kas vairs nav pieejami vismaz 90 dienas.",
"Original":"Oriģināls"
"Original":"Oriģināls",
"LyricDownloadFailureFromForItem":"Dziesmu vārdi nevarēja tikt lejupielādēti no {0} priekš {1}",
"TaskAudioNormalizationDescription":"Mengimbas fail-fail untuk data normalisasi audio.",
"CleanupUserDataTaskDescription":"Membersihkan semua data pengguna (keadaan tontonan, status kegemaran, dan sebagainya) daripada media yang tidak lagi wujud sekurang-kurangnya selama 90 hari.",
"CleanupUserDataTask":"Tugas pembersihan data pengguna"
"CleanupUserDataTask":"Tugas pembersihan data pengguna",
"LyricDownloadFailureFromForItem":"Lirik gagal dimuat turun dari {0} untuk {1}",
"TaskMoveTrickplayImagesDescription":"Flytter eksisterende Trickplay-filer i henhold til biblioteksinstillingene.",
"TaskExtractMediaSegmentsDescription":"Trekker ut eller henter mediasegmenter fra plugins som støtter MediaSegment.",
"CleanupUserDataTaskDescription":"Sletter all brukerdata (avspillings-status, favoritter osv.) fra innhold som har vært utilgjengelig i minst 90 dager.",
"CleanupUserDataTask":"Oppgave for opprydding av brukerdata"
"CleanupUserDataTask":"Oppgave for opprydding av brukerdata",
"CleanupUserDataTaskDescription":"Usuwa wszystkie dane użytkownika (stan oglądanych, status ulubionych itp.) z mediów, które nie są dostępne od co najmniej 90 dni.",
"CleanupUserDataTask":"Zadanie czyszczenia danych użytkownika",
"Original":"Oryginalny",
"LyricDownloadFailureFromForItem":"Błąd podczas pobierania tekstu piosenki z {0} dla {1}"
"LyricDownloadFailureFromForItem":"Błąd podczas pobierania tekstu piosenki z {0} dla {1}",
"CleanupUserDataTask":"Tarefa de limpeza de dados do usuário",
"CleanupUserDataTaskDescription":"Limpa todos os dados do usuário (estado de visualização, status de favorito, etc.) de mídias que não estão presentes por pelo menos 90 dias.",
"LyricDownloadFailureFromForItem":"Download das Letras falharam em {0} para o item {1}",
"TaskRefreshChapterImagesDescription":"Cria miniaturas para vídeos que têm capítulos.",
"TaskRefreshChapterImages":"Extrair imagens dos capítulos",
"TaskCleanCacheDescription":"Elimina ficheiros de cache que já não são necessários ao sistema.",
"TaskCleanCache":"Limpar pasta de cache",
"TasksChannelsCategory":"Canais da Internet",
"TasksApplicationCategory":"Aplicação",
"TasksLibraryCategory":"Mediateca",
"TasksLibraryCategory":"Biblioteca",
"TasksMaintenanceCategory":"Manutenção",
"TaskCleanActivityLogDescription":"Apaga as entradas do registo de atividade anteriores à data configurada.",
"TaskCleanActivityLogDescription":"Elimina as entradas do registo de atividade mais antigas do que o período configurado.",
"TaskCleanActivityLog":"Limpar registo de atividade",
"Undefined":"Indefinido",
"Forced":"Forçado",
"Default":"Predefinição",
"TaskOptimizeDatabaseDescription":"Otimiza e liberta espaço livre na base de dados. A execução desta tarefa depois de analisar a mediateca ou efetuar outras alterações que impliquem modificações na base de dados pode melhorar o desempenho.",
"TaskOptimizeDatabaseDescription":"Compacta a base de dados e liberta espaço não utilizado. A execução desta tarefa depois de analisar a biblioteca ou de outras alterações que modifiquem a base de dados pode melhorar o desempenho.",
"TaskOptimizeDatabase":"Otimizar base de dados",
"TaskKeyframeExtractorDescription":"Extrai quadros-chave de ficheiros de video para criar listas de reprodução HLS mais precisas. Esta tarefa pode demorar algum tempo.",
"TaskKeyframeExtractor":"Extrator de Quadros-chave",
"TaskKeyframeExtractorDescription":"Extrai fotogramas-chave de ficheiros de vídeo para criar playlists HLS mais precisas. Esta tarefa pode demorar algum tempo.",
"TaskKeyframeExtractor":"Extrator de fotogramas-chave",
"External":"Externo",
"HearingImpaired":"Surdo",
"HearingImpaired":"Deficiência auditiva",
"TaskRefreshTrickplayImages":"Gerar imagens de trickplay",
"TaskRefreshTrickplayImagesDescription":"Cria pré-visualizações de trickplay para vídeos nas bibliotecas ativadas.",
"TaskAudioNormalizationDescription":"Analisa os ficheiros para obter dados de normalização de áudio.",
"TaskAudioNormalization":"Normalização de áudio",
"TaskExtractMediaSegments":"Analisar segmentos de multimédia",
"TaskDownloadMissingLyrics":"Transferir letra em falta",
"TaskMoveTrickplayImages":"Migrar a localização da imagem do Trickplay",
"TaskDownloadMissingLyricsDescription":"Transferir letra para músicas",
"TaskExtractMediaSegmentsDescription":"Extrai ou obtém segmentos de multimédia a partir de plugins com suporte para MediaSegment.",
"TaskMoveTrickplayImagesDescription":"Move os ficheiros trickplay existentes de acordo com as definições da mediateca.",
"CleanupUserDataTaskDescription":"Apaga todos os dados de utilizador (estados de reprodução, favoritos, etc) de arquivos média não presentes há 90 dias ou mais.",
"TaskDownloadMissingLyrics":"Transferir letras em falta",
"TaskMoveTrickplayImages":"Migrar localização das imagens de trickplay",
"TaskDownloadMissingLyricsDescription":"Transfere letras de músicas",
"TaskExtractMediaSegmentsDescription":"Extrai ou obtém segmentos multimédia de plugins com MediaSegment ativado.",
"TaskMoveTrickplayImagesDescription":"Move os ficheiros de trickplay existentes de acordo com as definições da biblioteca.",
"CleanupUserDataTaskDescription":"Remove todos os dados de utilizador (estado de reprodução, estado de favorito, etc.) de conteúdos multimédia que já não estejam presentes há pelo menos 90 dias.",
"CleanupUserDataTask":"Limpeza de dados de utilizador",
"Original":"Original",
"LyricDownloadFailureFromForItem":"Erro ao descarregar letras de {0} para {1}"
"LyricDownloadFailureFromForItem":"Falha ao transferir letras de {0} para {1}",
"NameExtraDeletedScene":"Cena eliminada",
"NameExtraInterview":"Entrevista",
"NameExtraUnknown":"Extra",
"NameExtraBehindTheScenes":"Bastidores",
"NameExtraSample":"Amostra",
"NameExtraScene":"Cena",
"NameExtraClip":"Excerto",
"NameExtraFeaturette":"Minidocumentário",
"NameExtraThemeSong":"Tema musical",
"NameExtraThemeVideo":"Vídeo temático",
"NameExtraShort":"Curta-metragem",
"NameExtraNumbered":"{0} {1}",
"NameExtraTrailer":"Trailer"
}
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.