From 6530d2d7d8e0c1662a8fa5b03c3d3563bf38ae86 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Wed, 23 Oct 2024 17:13:16 -0400 Subject: [PATCH 1/5] Fix playing episodes when additional parts exist --- src/components/playback/playbackmanager.js | 58 ++++++++++++---------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index d3d74bdfc2..177fc34988 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -2039,12 +2039,12 @@ export class PlaybackManager { self.translateItemsForPlayback = translateItemsForPlayback; self.getItemsForPlayback = getItemsForPlayback; - self.play = function (options) { + self.play = async function (options) { normalizePlayOptions(options); if (self._currentPlayer) { if (options.enableRemotePlayers === false && !self._currentPlayer.isLocalPlayer) { - return Promise.reject(); + throw new Error('Remote players are disabled'); } if (!self._currentPlayer.isLocalPlayer) { @@ -2056,29 +2056,35 @@ export class PlaybackManager { loading.show(); } - if (options.items) { - return translateItemsForPlayback(options.items, options) - .then((items) => getAdditionalParts(items)) - .then(function (allItems) { - const flattened = allItems.flatMap(i => i); - return playWithIntros(flattened, options); - }); - } else { + let { items } = options; + // If items were not passed directly, fetch them by ID + if (!items) { if (!options.serverId) { throw new Error('serverId required!'); } - return getItemsForPlayback(options.serverId, { + items = (await getItemsForPlayback(options.serverId, { Ids: options.ids.join(',') - }).then(function (result) { - return translateItemsForPlayback(result.Items, options) - .then((items) => getAdditionalParts(items)) - .then(function (allItems) { - const flattened = allItems.flatMap(i => i); - return playWithIntros(flattened, options); - }); - }); + })).Items; } + + // Prepare the list of items + items = await translateItemsForPlayback(items, options); + // Add any additional parts for movies or episodes + items = await getAdditionalParts(items); + // Adjust the start index for additional parts added to the queue + if (options.startIndex) { + let adjustedStartIndex = 0; + for (let i = 0; i < options.startIndex; i++) { + adjustedStartIndex += items[i].length; + } + + options.startIndex = adjustedStartIndex; + } + // getAdditionalParts returns an array of arrays of items, so flatten it + items = items.flat(); + + return playWithIntros(items, options); }; function getPlayerData(player) { @@ -2217,20 +2223,22 @@ export class PlaybackManager { } const getAdditionalParts = async (items) => { - const getOneAdditionalPart = async function (item) { - let retVal = [item]; - if (item.PartCount && item.PartCount > 1 && (item.Type === 'Movie' || item.Type === 'Episode')) { + const getItemAndParts = async function (item) { + if ( + item.PartCount && item.PartCount > 1 + && [ BaseItemKind.Episode, BaseItemKind.Movie ].includes(item.Type) + ) { const client = ServerConnections.getApiClient(item.ServerId); const user = await client.getCurrentUser(); const additionalParts = await client.getAdditionalVideoParts(user.Id, item.Id); if (additionalParts.Items.length) { - retVal = [item, ...additionalParts.Items]; + return [ item, ...additionalParts.Items ]; } } - return retVal; + return [ item ]; }; - return Promise.all(items.flatMap(async (item) => getOneAdditionalPart(item))); + return Promise.all(items.map(getItemAndParts)); }; function playWithIntros(items, options) { From 571b28099e6a5def39afd8516a24679ec33bd25c Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Thu, 24 Oct 2024 01:35:04 -0400 Subject: [PATCH 2/5] Fix unhandled promises --- src/apps/experimental/components/library/PlayAllButton.tsx | 7 +++++-- src/apps/experimental/components/library/QueueButton.tsx | 6 +++++- src/apps/experimental/components/library/ShuffleButton.tsx | 4 +++- .../details/components/buttons/MoreCommandsButton.tsx | 6 +++++- .../details/components/buttons/PlayOrResumeButton.tsx | 4 ++++ src/components/playback/playbackmanager.js | 4 ++-- src/components/playlisteditor/playlisteditor.ts | 2 ++ 7 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/apps/experimental/components/library/PlayAllButton.tsx b/src/apps/experimental/components/library/PlayAllButton.tsx index 65315d2168..9c87d0056b 100644 --- a/src/apps/experimental/components/library/PlayAllButton.tsx +++ b/src/apps/experimental/components/library/PlayAllButton.tsx @@ -27,10 +27,12 @@ const PlayAllButton: FC = ({ item, items, viewType, hasFilte SortBy: [libraryViewSettings.SortBy], SortOrder: [libraryViewSettings.SortOrder] } + }).catch(err => { + console.error('[PlayAllButton] failed to play', err); }); } else { playbackManager.play({ - items: items, + items, autoplay: true, queryOptions: { ParentId: item?.Id ?? undefined, @@ -38,7 +40,8 @@ const PlayAllButton: FC = ({ item, items, viewType, hasFilte SortBy: [libraryViewSettings.SortBy], SortOrder: [libraryViewSettings.SortOrder] } - + }).catch(err => { + console.error('[PlayAllButton] failed to play', err); }); } }, [hasFilters, item, items, libraryViewSettings, viewType]); diff --git a/src/apps/experimental/components/library/QueueButton.tsx b/src/apps/experimental/components/library/QueueButton.tsx index 3b9cca64c3..31abe4d7b2 100644 --- a/src/apps/experimental/components/library/QueueButton.tsx +++ b/src/apps/experimental/components/library/QueueButton.tsx @@ -17,10 +17,14 @@ const QueueButton: FC = ({ item, items, hasFilters }) => { if (item && !hasFilters) { playbackManager.queue({ items: [item] + }).catch(err => { + console.error('[QueueButton] failed to add to queue', err); }); } else { playbackManager.queue({ - items: items + items + }).catch(err => { + console.error('[QueueButton] failed to add to queue', err); }); } }, [hasFilters, item, items]); diff --git a/src/apps/experimental/components/library/ShuffleButton.tsx b/src/apps/experimental/components/library/ShuffleButton.tsx index dde6d56417..2a85add1f2 100644 --- a/src/apps/experimental/components/library/ShuffleButton.tsx +++ b/src/apps/experimental/components/library/ShuffleButton.tsx @@ -24,13 +24,15 @@ const ShuffleButton: FC = ({ item, items, viewType, hasFilte playbackManager.shuffle(item); } else { playbackManager.play({ - items: items, + items, autoplay: true, queryOptions: { ParentId: item?.Id ?? undefined, ...getFiltersQuery(viewType, libraryViewSettings), SortBy: [ItemSortBy.Random] } + }).catch(err => { + console.error('[ShuffleButton] failed to play', err); }); } }, [hasFilters, item, items, libraryViewSettings, viewType]); diff --git a/src/apps/experimental/features/details/components/buttons/MoreCommandsButton.tsx b/src/apps/experimental/features/details/components/buttons/MoreCommandsButton.tsx index b9c979f9f8..99db01378d 100644 --- a/src/apps/experimental/features/details/components/buttons/MoreCommandsButton.tsx +++ b/src/apps/experimental/features/details/components/buttons/MoreCommandsButton.tsx @@ -39,7 +39,7 @@ function playAllFromHere(opts: PlayAllFromHereOptions) { } if (!ids.length) { - return; + return Promise.resolve(); } if (queue) { @@ -168,6 +168,8 @@ const MoreCommandsButton: FC = ({ item: item || {}, items: items || [], serverId: item?.ServerId + }).catch(err => { + console.error('[MoreCommandsButton] failed to play', err); }); } else if (result.command === 'queueallfromhere') { playAllFromHere({ @@ -175,6 +177,8 @@ const MoreCommandsButton: FC = ({ items: items || [], serverId: item?.ServerId, queue: true + }).catch(err => { + console.error('[MoreCommandsButton] failed to play', err); }); } else if (result.deleted) { if (result?.itemId !== itemId) { diff --git a/src/apps/experimental/features/details/components/buttons/PlayOrResumeButton.tsx b/src/apps/experimental/features/details/components/buttons/PlayOrResumeButton.tsx index a52453656f..97298b3813 100644 --- a/src/apps/experimental/features/details/components/buttons/PlayOrResumeButton.tsx +++ b/src/apps/experimental/features/details/components/buttons/PlayOrResumeButton.tsx @@ -58,6 +58,8 @@ const PlayOrResumeButton: FC = ({ ); playbackManager.play({ items: [channel] + }).catch(err => { + console.error('[PlayOrResumeButton] failed to play', err); }); return; } @@ -65,6 +67,8 @@ const PlayOrResumeButton: FC = ({ playbackManager.play({ items: [item], ...playOptions + }).catch(err => { + console.error('[PlayOrResumeButton] failed to play', err); }); }, [apiContext, item, playOptions, queryClient]); diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 177fc34988..c761f7317b 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -3113,11 +3113,11 @@ export class PlaybackManager { }; self.queue = function (options, player = this._currentPlayer) { - queue(options, '', player); + return queue(options, '', player); }; self.queueNext = function (options, player = this._currentPlayer) { - queue(options, 'next', player); + return queue(options, 'next', player); }; function queue(options, mode, player) { diff --git a/src/components/playlisteditor/playlisteditor.ts b/src/components/playlisteditor/playlisteditor.ts index 3db83914e1..6297906956 100644 --- a/src/components/playlisteditor/playlisteditor.ts +++ b/src/components/playlisteditor/playlisteditor.ts @@ -145,6 +145,8 @@ function addToPlaylist(dlg: DialogElement, id: string) { playbackManager.queue({ serverId: currentServerId, ids: itemIds.split(',') + }).catch(err => { + console.error('[PlaylistEditor] failed to add to queue', err); }); dlg.submitted = true; dialogHelper.close(dlg); From a9586d412e6b2fdaf2b5c98ed4e9994a7fca515b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aldair=20Guzm=C3=A1n?= Date: Thu, 24 Oct 2024 14:27:48 +0000 Subject: [PATCH 3/5] Translated using Weblate (Spanish (Latin America)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/es_419/ --- src/strings/es_419.json | 59 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/src/strings/es_419.json b/src/strings/es_419.json index 6b1eb69d2d..4670075b69 100644 --- a/src/strings/es_419.json +++ b/src/strings/es_419.json @@ -1276,7 +1276,7 @@ "ButtonAddScheduledTaskTrigger": "Agregar disparador", "ButtonAddMediaLibrary": "Agregar biblioteca de medios", "ButtonAddImage": "Agregar imagen", - "BurnSubtitlesHelp": "Determina si el servidor debería quemar los subtítulos al transcodificar videos. Evitar esto mejorará altamente el rendimiento del servidor. Seleccione «Auto» para quemar formatos basados en imágenes (VobSub, PGS, SUB, IDX, etc.) y ciertos subtítulos ASS o SSA.", + "BurnSubtitlesHelp": "Determina si el servidor debe incrustar subtítulos. Evitar esto mejorará considerablemente el rendimiento. Selecciona \"Automático\" para incrustar formatos de imagen (VobSub, PGS, SUB, IDX, etc.) y ciertos subtítulos en ASS o SSA.", "MessageBrowsePluginCatalog": "Explora nuestro catálogo de complementos para ver los complementos disponibles.", "Browse": "Explorar", "BoxRear": "Caja (parte trasera)", @@ -1390,7 +1390,7 @@ "MediaInfoColorTransfer": "Transferencia de Color", "MediaInfoColorSpace": "Espacio de Color", "MediaInfoVideoRange": "Rango de video", - "Bwdif": "Filtro desentrelazado Bob Weaver (BWDIF)", + "Bwdif": "Filtro de desentrelazado de Bob Weaver (BWDIF)", "VideoAudio": "Audio del Video", "Video": "Vídeo", "UseDoubleRateDeinterlacingHelp": "Esta configuración utiliza la velocidad de campo al desentrelazar, a menudo denominado desentrelazado bob, que duplica la velocidad de fotogramas del video para proporcionar un movimiento completo similar al ver un video entrelazado en un televisor.", @@ -1656,7 +1656,7 @@ "Alternate": "Alternar", "AlternateDVD": "Alternar DVD", "ConfirmDeleteLyrics": "Al eliminar estas letras las eliminará tanto del sistema como de tu biblioteca de medios. ¿Estás seguro de querer continuar?", - "AllowTonemappingSoftwareHelp": "El mapeo de tonos puede transformar el rango dinámico de un video de HDR a SDR manteniendo la calidad de imagen y los colores, que son datos muy importantes para mostrar la imagen original. Actualmente solo funciona con videos HDR10 y HLG.", + "AllowTonemappingSoftwareHelp": "El mapeo de tonos puede transformar el rango dinámico de un video de HDR a SDR manteniendo los detalles y colores de la imagen, que son información muy importante para representar la escena original. Actualmente, solo funciona con videos HDR10, HLG y DoVi de 10 bits.", "BlockContentWithTagsHelp": "Ocultar medios con al menos una de las etiquetas especificadas.", "ButtonEditUser": "Editar usuario", "DeleteLyrics": "Eliminar letras", @@ -1673,5 +1673,56 @@ "AlwaysRemuxFlacAudioFilesHelp": "Si tienes archivos que tu navegador rechaza reproducir o en los que calcula los tiempos de manera incorrecta, habilita esta opción como solución alternativa.", "AlwaysBurnInSubtitleWhenTranscoding": "Incrustar siempre los subtítulos al transcodificar", "AlwaysRemuxMp3AudioFilesHelp": "Si tienes archivos en los que tu navegador calcula los tiempos de manera incorrecta, habilita esta opción como solución alternativa.", - "AndOtherArtists": "{0} y {1} otros artistas." + "AndOtherArtists": "{0} y {1} otros artistas.", + "PlaylistPublicDescription": "Permitir que esta lista de reproducción sea vista por cualquier usuario con sesión iniciada.", + "PleaseConfirmRepositoryInstallation": "Haz clic en OK para confirmar que has leído lo anterior y deseas proceder con la instalación del repositorio de plugins.", + "PreferNonstandardArtistsTagHelp": "Usar la etiqueta no estándar ARTISTS en lugar de la etiqueta ARTIST cuando esté disponible.", + "AllowEmbeddedSubtitlesHelp": "Deshabilitar los subtítulos que están empaquetados dentro de los contenedores de medios. Requiere una actualización completa de la biblioteca.", + "HeaderNextItemPlayingInValue": "Siguiente {0} reproduciéndose en {1}", + "LabelExtractTrickplayDuringLibraryScanHelp": "Generar imágenes de reproducción rápida cuando los videos se importan durante el escaneo de la biblioteca. De lo contrario, se extraerán durante la tarea programada de imágenes de reproducción rápida. Si la generación se establece como no bloqueante, esto no afectará el tiempo que tarda en completarse el escaneo de la biblioteca.", + "LabelExtractTrickplayDuringLibraryScan": "Extraer imágenes de reproducción rápida durante el escaneo de la biblioteca.", + "PlaybackError.RateLimitExceeded": "Este medio no puede reproducirse en este momento debido a límites de tasa.", + "AllowEmbeddedSubtitlesAllowAllOption": "Permitir todo", + "AllowEmbeddedSubtitlesAllowNoneOption": "No permitir ninguno", + "HeaderNextItem": "Siguiente {0}", + "HeaderNoLyrics": "No se encontraron letras", + "HeaderNewPlaylist": "Nueva lista de reproducción", + "MediaSegmentAction.None": "Ninguno", + "MediaSegmentAction.Skip": "Saltar", + "MediaSegmentType.Commercial": "Comercial", + "MediaSegmentType.Intro": "Introducción", + "MediaSegmentType.Outro": "Outro", + "MediaSegmentType.Preview": "Vista previa", + "MediaSegmentType.Recap": "Repaso", + "PlaybackError.NO_MEDIA_ERROR": "No se pudo encontrar una fuente de medios válida para reproducir.", + "PlaybackError.PLAYER_ERROR": "La reproducción falló debido a un error fatal del reproductor.", + "PlaybackError.SERVER_ERROR": "La reproducción falló debido a un error del servidor.", + "PlaybackError.NotAllowed": "La reproducción de este medio no está permitida.", + "PluginLoadRepoError": "Ocurrió un error al obtener los detalles del plugin desde el repositorio.", + "PluginUninstallError": "Ocurrió un error al desinstalar el plugin.", + "AllowEmbeddedSubtitles": "Deshabilitar diferentes tipos de subtítulos incrustados", + "AllowEmbeddedSubtitlesAllowImageOption": "Permitir imagen", + "PlaybackError.MEDIA_DECODE_ERROR": "La reproducción falló debido a un error al decodificar el medio.", + "PlaybackError.MEDIA_NOT_SUPPORTED": "La reproducción falló porque el medio no es compatible con este cliente.", + "PlaybackError.NETWORK_ERROR": "La reproducción falló debido a un error de red.", + "PlaybackErrorPlaceHolder": "Este es un marcador de posición para medios físicos que Jellyfin no puede reproducir. Por favor, inserta el disco para reproducirlo.", + "PluginLoadConfigError": "Ocurrió un error al obtener las páginas de configuración del plugin.", + "PlaylistError.AddFailed": "Error al agregar a la lista de reproducción", + "PlaylistError.CreateFailed": "Error al crear la lista de reproducción", + "PlaylistError.UpdateFailed": "Error al actualizar la lista de reproducción", + "PluginDisableError": "Ocurrió un error al deshabilitar el plugin.", + "PluginEnableError": "Ocurrió un error al habilitar el plugin.", + "PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Los extras a menudo tienen el mismo nombre incrustado que el archivo principal. Marca esta opción para usar los títulos incrustados en ellos de todos modos.", + "PreferNonstandardArtistsTag": "Preferir la etiqueta ARTISTS si está disponible", + "ContainerBitrateExceedsLimit": "El bitrate del video excede el límite", + "PlaylistPublic": "Permitir acceso público", + "HeaderLyricDownloads": "Descargas de letras de canciones", + "MediaInfoRotation": "Rotación", + "MessageCancelSeriesTimerError": "Ocurrió un error al cancelar el temporizador de la serie", + "MessageCancelTimerError": "Ocurrió un error al cancelar el temporizador", + "PlaybackError.ASS_RENDER_ERROR": "Se encontró un error en el renderizador de subtítulos ASS/SSA.", + "PlaybackError.FATAL_HLS_ERROR": "Se encontró un error fatal en la transmisión HLS.", + "PreferEmbeddedExtrasTitlesOverFileNames": "Preferir los títulos incrustados en lugar de los nombres de archivo para los extras", + "AllowVideoToolboxTonemappingHelp": "El mapeo de tonos acelerado por hardware proporcionado por VideoToolbox. Funciona con la mayoría de los formatos HDR, incluyendo HDR10, HDR10+ y HLG, pero no funciona con Dolby Vision Perfil 5. Tiene una mayor prioridad en comparación con otra implementación en Metal.", + "HeaderMediaSegmentActions": "Acciones de segmentos de medios" } From 005fcec49c15faab6eb7e333773df06ac3894c8b Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Thu, 24 Oct 2024 16:17:34 -0400 Subject: [PATCH 4/5] Fix drawer label for the dashboard metadata page --- .../components/drawer/sections/ServerDrawerSection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/dashboard/components/drawer/sections/ServerDrawerSection.tsx b/src/apps/dashboard/components/drawer/sections/ServerDrawerSection.tsx index 9d0970096f..2c4ce010c4 100644 --- a/src/apps/dashboard/components/drawer/sections/ServerDrawerSection.tsx +++ b/src/apps/dashboard/components/drawer/sections/ServerDrawerSection.tsx @@ -91,7 +91,7 @@ const ServerDrawerSection = () => { - + From 7255df6b083d976de91902773f4c05d37331ab43 Mon Sep 17 00:00:00 2001 From: Frostslayer Date: Thu, 24 Oct 2024 20:20:59 +0000 Subject: [PATCH 5/5] Translated using Weblate (Portuguese (Brazil)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/pt_BR/ --- src/strings/pt-br.json | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/strings/pt-br.json b/src/strings/pt-br.json index 056acb2b2f..dae4c4aa51 100644 --- a/src/strings/pt-br.json +++ b/src/strings/pt-br.json @@ -457,7 +457,7 @@ "LabelDateAddedBehaviorHelp": "Se um valor de metadados estiver presente, ele sempre será utilizado antes destas opções.", "LabelDateTimeLocale": "Hora local", "LabelDay": "Dia da semana", - "LabelDeathDate": "Data da morte", + "LabelDeathDate": "Data de falecimento", "LabelDefaultScreen": "Tela padrão", "LabelDefaultUser": "Usuário padrão", "LabelDefaultUserHelp": "Determina qual usuário será exibido nos dispositivos conectados. Isto pode ser ignorado para cada dispositivo usando perfis.", @@ -1494,7 +1494,7 @@ "LabelSyncPlayHaltPlayback": "Pare a reprodução local", "LabelSSDPTracingFilterHelp": "Endereço IP opcional para filtrar o tráfego SSDP registrado.", "LabelSSDPTracingFilter": "Filtro SSDP", - "LabelPublishedServerUriHelp": "Substitua o URI usado pelo Jellyfin, com base na interface ou endereço IP do cliente.", + "LabelPublishedServerUriHelp": "Substitua o URI usado pelo Jellyfin, com base na interface ou endereço IP do cliente. Por exemplo: interno=http://jellyfin.example.com, externo=https://jellyfin.example.com, ou todos=https://jellyfin.example.com", "LabelPublishedServerUri": "URIs de servidor publicados", "LabelMinAudiobookResumeHelp": "Os títulos são considerados não reproduzidos se parados antes desse tempo.", "LabelMinAudiobookResume": "Resumo mínimo do audiolivro em minutos", @@ -1775,7 +1775,7 @@ "SearchResultsEmpty": "Desculpe! Nenhum resultaod encontrado para \"{0}\"", "ForeignPartsOnly": "Apenas partes extrangeiras/forçadas", "HearingImpairedShort": "HI/SDH", - "SelectAudioNormalizationHelp": "Nivelar volume de faixas - ajusta o volume de cada faixa para que a reprodução esteja no mesmo volume. Nivelar volume de álbum - ajusta o volume de faixas em um álbum/disco, mandendo o alcance dinâmico.", + "SelectAudioNormalizationHelp": "Nivelar volume de faixas - ajusta o volume de cada faixa para que a reprodução esteja no mesmo volume. Nivelar volume de álbum - ajusta o volume de faixas em um álbum/disco, mandendo o alcance dinâmico. Alternando entre \"desligado\" e outras opções necessita o reinicio da atual reprodução.", "LabelAlbumGain": "Nivelar volume do álbum", "LabelSelectAudioNormalization": "Normalização de áudio", "LabelTrackGain": "Nivelação de volume de faixa", @@ -1832,7 +1832,7 @@ "PriorityHigh": "Alta", "LabelTrickplayAccelEncoding": "Ativar codificação MJPEG acelerada por hardware", "LabelTrickplayAccel": "Ativar decodificação por hardware", - "LabelTrickplayAccelEncodingHelp": "Atualmente disponível apenas no QSV, VAAPI e VideoToolbox, essa opção não tem efeito sobre outros métodos de aceleração por hardware.", + "LabelTrickplayAccelEncodingHelp": "Atualmente disponível apenas no QSV, VA-API e, VideoToolbox e RKMPP, essa opção não tem efeito sobre outros métodos de aceleração por hardware.", "LabelScanBehavior": "Comportamento do Escaneamento", "PriorityAboveNormal": "Acima do normal", "PriorityNormal": "Normal", @@ -1938,5 +1938,35 @@ "LabelDisableVbrAudioEncoding": "Desativar a codificação de áudio VBR", "LabelSaveTrickplayLocally": "Salvar imagens de trickplay junto à mídia", "LabelSaveTrickplayLocallyHelp": "Salvar imagens de trickplay nas pastas de mídia as colocará junto às suas mídias, para fácil migração e acesso.", - "ReplaceTrickplayImages": "Substituir imagens de trickplay existentes" + "ReplaceTrickplayImages": "Substituir imagens de trickplay existentes", + "UseCustomTagDelimitersHelp": "Separar tags de artista/gênero com caracteres personalizados.", + "DateModified": "Data de modificação", + "MessageCancelSeriesTimerError": "Um erro ocorreu enquanto cancelava o temporizador das séries", + "MessageCancelTimerError": "Um erro ocorreu enquanto cancelava o temporizador", + "UseCustomTagDelimiters": "Usar delimitador de tag customizado", + "LabelLyricDownloaders": "Baixador de legenda", + "LyricDownloadersHelp": "Habilitar e ranquear seus baixadores de legenda favoritos em ordem de prioridade.", + "LabelAudioTagSettings": "Configurações de etiqueta de áudio", + "LabelCustomTagDelimiters": "Delimitador Customizado de Tag", + "LabelCustomTagDelimitersHelp": "Caracteres para serem tratados como delimitadores para separar tags.", + "LabelDelimiterWhitelistHelp": "Itens para serem excluidos da divisão de tags. Um item por linha.", + "PreferNonstandardArtistsTag": "Preferir tag de ARTISTAS se disponível", + "LabelScreensaverTime": "Tempo da Proteção de Tela", + "LabelScreensaverTimeHelp": "Quantidade de tempo em segundos de inatividade necessária para iniciar a proteção de tela.", + "HeaderEditPlaylist": "Editar lista de reprodução", + "HeaderNewPlaylist": "Nova lista de reprodução", + "LabelAllowFmp4TranscodingContainer": "Permitir contêiner de transcodificação fMP4", + "LabelAllowStreamSharing": "Permitir compartilhamento de stream", + "LabelMediaSegmentsType": "{0} Segmentos", + "MediaSegmentAction.None": "Nenhum", + "MediaSegmentAction.Skip": "Pular", + "MediaSegmentType.Intro": "Abertura", + "MediaSegmentType.Commercial": "Comercial", + "MediaSegmentType.Preview": "Prévia", + "PlaylistError.UpdateFailed": "Erro ao atualizar a lista de reprodução", + "LabelQsvDevice": "Dispositivo QSV", + "MessageSplitVersionsError": "Um erro ocorreu enquanto separava as versões", + "AlwaysBurnInSubtitleWhenTranscoding": "Sempre incorporar legendas durante a transcodificação", + "AlwaysBurnInSubtitleWhenTranscodingHelp": "Incorporar todas as legendas quando a transcodificação for iniciada. Isso garante a sincronização das legendas após a transcodificação, ao custo de uma redução na velocidade de transcodificação.", + "HeaderMediaSegmentActions": "Ações de Segmento de Mídia" }