aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci-codeql-analysis.yml6
-rw-r--r--.github/workflows/ci-tests.yml2
-rw-r--r--.github/workflows/commands.yml2
-rw-r--r--.github/workflows/issue-template-check.yml2
-rw-r--r--Directory.Packages.props2
-rw-r--r--Emby.Server.Implementations/Collections/CollectionManager.cs2
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs2
-rw-r--r--Emby.Server.Implementations/Localization/Core/et.json14
-rw-r--r--Emby.Server.Implementations/Localization/Core/gl.json132
-rw-r--r--Emby.Server.Implementations/Localization/Core/hr.json8
-rw-r--r--Emby.Server.Implementations/Localization/Core/ur.json15
-rw-r--r--Emby.Server.Implementations/Localization/Core/ur_PK.json6
-rw-r--r--Jellyfin.Server.Implementations/Item/BaseItemRepository.cs43
-rw-r--r--Jellyfin.Server.Implementations/Item/PeopleRepository.cs6
-rw-r--r--Jellyfin.Server/Migrations/Routines/CleanMusicArtist.cs47
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs6
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalUrlProvider.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalUrlProvider.cs2
18 files changed, 193 insertions, 106 deletions
diff --git a/.github/workflows/ci-codeql-analysis.yml b/.github/workflows/ci-codeql-analysis.yml
index 6bbbbd2a8..4dd240229 100644
--- a/.github/workflows/ci-codeql-analysis.yml
+++ b/.github/workflows/ci-codeql-analysis.yml
@@ -27,11 +27,11 @@ jobs:
dotnet-version: '9.0.x'
- name: Initialize CodeQL
- uses: github/codeql-action/init@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6
+ uses: github/codeql-action/init@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8
with:
languages: ${{ matrix.language }}
queries: +security-extended
- name: Autobuild
- uses: github/codeql-action/autobuild@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6
+ uses: github/codeql-action/autobuild@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6
+ uses: github/codeql-action/analyze@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
index f2cf967e9..846835491 100644
--- a/.github/workflows/ci-tests.yml
+++ b/.github/workflows/ci-tests.yml
@@ -35,7 +35,7 @@ jobs:
--verbosity minimal
- name: Merge code coverage results
- uses: danielpalme/ReportGenerator-GitHub-Action@1978db745da4a573ca4baa2d0f67175df51a148c # v5.4.16
+ uses: danielpalme/ReportGenerator-GitHub-Action@9870ed167742d546b99962ff815fcc1098355ed8 # v5.4.17
with:
reports: "**/coverage.cobertura.xml"
targetdir: "merged/"
diff --git a/.github/workflows/commands.yml b/.github/workflows/commands.yml
index a2e37e7d5..ba12d4747 100644
--- a/.github/workflows/commands.yml
+++ b/.github/workflows/commands.yml
@@ -46,7 +46,7 @@ jobs:
- name: install python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
- python-version: '3.13'
+ python-version: '3.14'
cache: 'pip'
- name: install python packages
run: pip install -r rename/requirements.txt
diff --git a/.github/workflows/issue-template-check.yml b/.github/workflows/issue-template-check.yml
index 0c4115888..b49647d33 100644
--- a/.github/workflows/issue-template-check.yml
+++ b/.github/workflows/issue-template-check.yml
@@ -16,7 +16,7 @@ jobs:
- name: install python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
- python-version: '3.13'
+ python-version: '3.14'
cache: 'pip'
- name: install python packages
run: pip install -r main-repo-triage/requirements.txt
diff --git a/Directory.Packages.props b/Directory.Packages.props
index d387cca6d..857b1a7ef 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -4,7 +4,7 @@
</PropertyGroup>
<!-- Run "dotnet list package (dash,dash)outdated" to see the latest versions of each package.-->
<ItemGroup Label="Package Dependencies">
- <PackageVersion Include="AsyncKeyedLock" Version="7.1.6" />
+ <PackageVersion Include="AsyncKeyedLock" Version="7.1.7" />
<PackageVersion Include="AutoFixture.AutoMoq" Version="4.18.1" />
<PackageVersion Include="AutoFixture.Xunit2" Version="4.18.1" />
<PackageVersion Include="AutoFixture" Version="4.18.1" />
diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs
index 0eb387ffd..a320a774c 100644
--- a/Emby.Server.Implementations/Collections/CollectionManager.cs
+++ b/Emby.Server.Implementations/Collections/CollectionManager.cs
@@ -104,6 +104,8 @@ namespace Emby.Server.Implementations.Collections
await _libraryManager.AddVirtualFolder(name, CollectionTypeOptions.boxsets, libraryOptions, true).ConfigureAwait(false);
+ _libraryManager.RootFolder.Children = null;
+
return FindFolders(path).First();
}
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index e2d8325fe..a400cb092 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -2129,6 +2129,8 @@ namespace Emby.Server.Implementations.Library
}
}
+ item.ValidateImages();
+
_itemRepository.SaveImages(item);
RegisterItem(item);
diff --git a/Emby.Server.Implementations/Localization/Core/et.json b/Emby.Server.Implementations/Localization/Core/et.json
index 486e62dfd..b81ae459a 100644
--- a/Emby.Server.Implementations/Localization/Core/et.json
+++ b/Emby.Server.Implementations/Localization/Core/et.json
@@ -41,7 +41,7 @@
"StartupEmbyServerIsLoading": "Jellyfin server laadib. Proovi varsti uuesti.",
"User": "Kasutaja",
"Undefined": "Määratlemata",
- "TvShows": "Seriaalid",
+ "TvShows": "Sarjad",
"System": "Süsteem",
"Sync": "Sünkrooni",
"Songs": "Laulud",
@@ -123,11 +123,11 @@
"External": "Väline",
"HearingImpaired": "Kuulmispuudega",
"TaskKeyframeExtractorDescription": "Eraldab videofailidest võtmekaadreid, et luua täpsemaid HLS-i esitusloendeid. See ülesanne võib kesta pikka aega.",
- "TaskKeyframeExtractor": "Võtmekaadri ekstraktor",
- "TaskRefreshTrickplayImages": "Loo eelvaate pildid",
- "TaskRefreshTrickplayImagesDescription": "Loob eelvaated videotele, kus lubatud.",
- "TaskAudioNormalization": "Heli Normaliseerimine",
- "TaskAudioNormalizationDescription": "Skaneerib faile heli normaliseerimise andmete jaoks.",
+ "TaskKeyframeExtractor": "Võtmekaadrite eraldamine",
+ "TaskRefreshTrickplayImages": "Loo trickplay pildid",
+ "TaskRefreshTrickplayImagesDescription": "Loob trickplay eelvaated videotele lubatud meediakogudes.",
+ "TaskAudioNormalization": "Normaliseeri heli",
+ "TaskAudioNormalizationDescription": "Otsib failidest helitugevuse normaliseerimise teavet.",
"TaskCleanCollectionsAndPlaylistsDescription": "Eemaldab kogumikest ja esitusloenditest asjad, mida enam ei eksisteeri.",
"TaskCleanCollectionsAndPlaylists": "Puhasta kogumikud ja esitusloendid",
"TaskDownloadMissingLyrics": "Lae alla puuduolev lüürika",
@@ -135,7 +135,7 @@
"TaskMoveTrickplayImagesDescription": "Liigutab trickplay pildid meediakogu sätete kohaselt.",
"TaskExtractMediaSegments": "Meediasegmentide skaneerimine",
"TaskExtractMediaSegmentsDescription": "Eraldab või võtab meediasegmendid MediaSegment'i lubavatest pluginatest.",
- "TaskMoveTrickplayImages": "Migreeri trickplay piltide asukoht",
+ "TaskMoveTrickplayImages": "Muuda trickplay piltide asukoht",
"CleanupUserDataTask": "Kasutajaandmete puhastamise ülesanne",
"CleanupUserDataTaskDescription": "Puhastab kõik kasutajaandmed (vaatamise olek, lemmikute olek jne) meediast, mis pole enam vähemalt 90 päeva saadaval olnud."
}
diff --git a/Emby.Server.Implementations/Localization/Core/gl.json b/Emby.Server.Implementations/Localization/Core/gl.json
index 0e7c9dc3a..b3f137feb 100644
--- a/Emby.Server.Implementations/Localization/Core/gl.json
+++ b/Emby.Server.Implementations/Localization/Core/gl.json
@@ -1,74 +1,74 @@
{
- "Albums": "Álbumes",
+ "Albums": "Álbums",
"Collections": "Coleccións",
"ChapterNameValue": "Capítulo {0}",
"Channels": "Canles",
- "CameraImageUploadedFrom": "Cargouse unha nova imaxe da cámara desde {0}",
+ "CameraImageUploadedFrom": "Cargouse unha nova imaxe de cámara dende {0}",
"Books": "Libros",
"AuthenticationSucceededWithUserName": "{0} autenticouse correctamente",
"Artists": "Artistas",
- "Application": "Aplicativo",
- "NotificationOptionServerRestartRequired": "Necesario un reinicio do servidor",
- "NotificationOptionPluginUpdateInstalled": "Actualización do Plugin instalada",
+ "Application": "Aplicación",
+ "NotificationOptionServerRestartRequired": "Necesario o reinicio do servidor",
+ "NotificationOptionPluginUpdateInstalled": "Actualización do plugin instalada",
"NotificationOptionPluginUninstalled": "Plugin desinstalado",
"NotificationOptionPluginInstalled": "Plugin instalado",
- "NotificationOptionPluginError": "Fallo do Plugin",
+ "NotificationOptionPluginError": "Fallo do plugin",
"NotificationOptionNewLibraryContent": "Novo contido engadido",
"NotificationOptionInstallationFailed": "Fallo na instalación",
- "NotificationOptionCameraImageUploaded": "Imaxe da cámara subida",
- "NotificationOptionAudioPlaybackStopped": "Reproducción de audio parada",
+ "NotificationOptionCameraImageUploaded": "Imaxe da cámara cargada",
+ "NotificationOptionAudioPlaybackStopped": "Reproducción de audio detida",
"NotificationOptionAudioPlayback": "Reproducción de audio comezada",
"NotificationOptionApplicationUpdateInstalled": "Actualización da aplicación instalada",
"NotificationOptionApplicationUpdateAvailable": "Actualización da aplicación dispoñible",
- "NewVersionIsAvailable": "Unha nova versión do Servidor Jellyfin está dispoñible para descarga.",
+ "NewVersionIsAvailable": "Nova versión do Servidor Jellyfin dispoñible para descargar.",
"NameSeasonUnknown": "Tempada descoñecida",
"NameSeasonNumber": "Tempada {0}",
"NameInstallFailed": "{0} instalación fallida",
- "MusicVideos": "Vídeos Musicais",
+ "MusicVideos": "Vídeos musicais",
"Music": "Música",
"Movies": "Películas",
- "MixedContent": "Contido Mixto",
- "MessageServerConfigurationUpdated": "A configuración do servidor foi actualizada",
- "MessageNamedServerConfigurationUpdatedWithValue": "A sección de configuración {0} do servidor foi actualizada",
- "MessageApplicationUpdatedTo": "O servidor Jellyfin foi actualizado a {0}",
- "MessageApplicationUpdated": "O servidor Jellyfin foi actualizado",
+ "MixedContent": "Contido mixto",
+ "MessageServerConfigurationUpdated": "Actualizouse a configuración do servidor",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Actualizouse a sección de configuración {0} do servidor",
+ "MessageApplicationUpdatedTo": "O servidor Jellyfin actualizouse a {0}",
+ "MessageApplicationUpdated": "O servidor Jellyfin actualizouse",
"Latest": "Último",
- "LabelRunningTimeValue": "Tempo de execución: {0}",
+ "LabelRunningTimeValue": "Tempo en execución: {0}",
"LabelIpAddressValue": "Enderezo IP: {0}",
- "ItemRemovedWithName": "{0} foi eliminado da biblioteca",
- "ItemAddedWithName": "{0} foi engadido a biblioteca",
+ "ItemRemovedWithName": "{0} eliminouse da biblioteca",
+ "ItemAddedWithName": "{0} engadiuse á biblioteca",
"Inherit": "Herdar",
"HomeVideos": "Videos caseiros",
- "HeaderRecordingGroups": "Grupos de Grabación",
+ "HeaderRecordingGroups": "Grupos de grabación",
"HeaderNextUp": "De seguido",
"HeaderLiveTV": "TV en directo",
- "HeaderFavoriteSongs": "Cancións Favoritas",
- "HeaderFavoriteShows": "Series de TV Favoritas",
- "HeaderFavoriteEpisodes": "Episodios Favoritos",
- "HeaderFavoriteArtists": "Artistas Favoritos",
- "HeaderFavoriteAlbums": "Álbunes Favoritos",
+ "HeaderFavoriteSongs": "Cancións favoritas",
+ "HeaderFavoriteShows": "Series de TV favoritas",
+ "HeaderFavoriteEpisodes": "Episodios favoritos",
+ "HeaderFavoriteArtists": "Artistas favoritos",
+ "HeaderFavoriteAlbums": "Álbums favoritos",
"HeaderContinueWatching": "Seguir vendo",
- "HeaderAlbumArtists": "Artistas do Album",
+ "HeaderAlbumArtists": "Artistas do álbum",
"Genres": "Xéneros",
"Forced": "Forzado",
"Folders": "Cartafoles",
"Favorites": "Favoritos",
- "FailedLoginAttemptWithUserName": "Intento de incio de sesión fallido {0}",
+ "FailedLoginAttemptWithUserName": "Fallo de intento de inicio de sesión dende {0}",
"DeviceOnlineWithName": "{0} conectouse",
"DeviceOfflineWithName": "{0} desconectouse",
"Default": "Por defecto",
"AppDeviceValues": "Aplicación: {0}, Dispositivo: {1}",
- "TaskCleanLogs": "Limpar Carpeta de Rexistros",
- "TaskCleanActivityLog": "Limpar Rexistro de Actividade",
- "TasksChannelsCategory": "Canáis de Internet",
- "TaskUpdatePlugins": "Actualizar Plugins",
+ "TaskCleanLogs": "Limpar directorio de rexistros",
+ "TaskCleanActivityLog": "Limpar rexistro de actividade",
+ "TasksChannelsCategory": "Canles da Internet",
+ "TaskUpdatePlugins": "Actualizar plugins",
"User": "Usuario",
"Undefined": "Sen definir",
"TvShows": "Programas de TV",
"System": "Sistema",
"Sync": "Sincronizar",
"SubtitleDownloadFailureFromForItem": "Fallou a descarga de subtítulos para {1} dende {0}",
- "StartupEmbyServerIsLoading": "O Servidor Jellyfin está cargando. Por favor, reinténteo en breve.",
+ "StartupEmbyServerIsLoading": "O servidor Jellyfin está cargando. Por favor, ténteo axiña outra vez.",
"Songs": "Cancións",
"Shows": "Programas",
"ServerNameNeedsToBeRestarted": "{0} precisa ser reiniciado",
@@ -85,57 +85,57 @@
"UserDeletedWithName": "O usuario {0} foi borrado",
"UserCreatedWithName": "O usuario {0} foi creado",
"Plugin": "Plugin",
- "NotificationOptionVideoPlaybackStopped": "Reproducción de vídeo parada",
+ "NotificationOptionVideoPlaybackStopped": "Reproducción de vídeo detida",
"NotificationOptionVideoPlayback": "Reproducción de vídeo iniciada",
"NotificationOptionUserLockedOut": "Usuario bloqueado",
"NotificationOptionTaskFailed": "Falla na tarefa axendada",
- "TaskCleanTranscodeDescription": "Borra os arquivos de transcode anteriores a un día.",
- "TaskCleanTranscode": "Limpar Directorio de Transcode",
+ "TaskCleanTranscodeDescription": "Borra os ficheiros de transcodificación de hai más dun día.",
+ "TaskCleanTranscode": "Limpar o directorio de transcodificación",
"UserStoppedPlayingItemWithValues": "{0} rematou de reproducir {1} en {2}",
- "UserStartedPlayingItemWithValues": "{0} está reproducindo {1} en {2}",
- "TaskDownloadMissingSubtitlesDescription": "Busca en internet por subtítulos que faltan baseado na configuración de metadatos.",
+ "UserStartedPlayingItemWithValues": "{0} está a reproducir {1} en {2}",
+ "TaskDownloadMissingSubtitlesDescription": "Procura na internet os subtítulos que faltan segundo a configuración de metadatos.",
"TaskDownloadMissingSubtitles": "Descargar subtítulos que faltan",
- "TaskRefreshChannelsDescription": "Refresca a información do canle de internet.",
- "TaskRefreshChannels": "Refrescar Canles",
- "TaskUpdatePluginsDescription": "Descarga e instala actualizacións para plugins que están configurados para actualizarse automáticamente.",
- "TaskRefreshPeopleDescription": "Actualiza os metadatos dos actores e directores na túa libraría multimedia.",
- "TaskRefreshPeople": "Refrescar Persoas",
- "TaskCleanLogsDescription": "Borra arquivos de rexistro que son mais antigos que {0} días.",
- "TaskRefreshLibraryDescription": "Escanea a tua libraría multimedia buscando novos arquivos e refrescando os metadatos.",
- "TaskRefreshLibrary": "Escanear Libraría Multimedia",
- "TaskRefreshChapterImagesDescription": "Crea previsualizacións para videos que teñen capítulos.",
- "TaskRefreshChapterImages": "Extraer Imaxes dos Capítulos",
+ "TaskRefreshChannelsDescription": "Refresca a información da canle de internet.",
+ "TaskRefreshChannels": "Refrescar canles",
+ "TaskUpdatePluginsDescription": "Descarga e instala actualizacións dos plugins configurados para actualizarse automáticamente.",
+ "TaskRefreshPeopleDescription": "Actualiza os metadatos dos actores e directores na túa biblioteca de medios.",
+ "TaskRefreshPeople": "Refrescar persoas",
+ "TaskCleanLogsDescription": "Borra ficheiros de rexistro con máis de {0} días de antigüidade.",
+ "TaskRefreshLibraryDescription": "Escanea a túa biblioteca de medios á procura de novos ficheiros e refresca os metadatos.",
+ "TaskRefreshLibrary": "Escanear a biblioteca de medios",
+ "TaskRefreshChapterImagesDescription": "Crea miniaturas dos vídeos que teñen capítulos.",
+ "TaskRefreshChapterImages": "Extraer imaxes dos capítulos",
"TaskCleanCacheDescription": "Borra ficheiros da caché que xa non son necesarios para o sistema.",
- "TaskCleanCache": "Limpa Directorio de Caché",
- "TaskCleanActivityLogDescription": "Borra as entradas no rexistro de actividade anteriores á data configurada.",
+ "TaskCleanCache": "Limpar directorio de caché",
+ "TaskCleanActivityLogDescription": "Borra do rexistro de actividade as entradas anteriores á data configurada.",
"TasksApplicationCategory": "Aplicación",
"ValueSpecialEpisodeName": "Especial - {0}",
- "ValueHasBeenAddedToLibrary": "{0} foi engadido a túa libraría multimedia",
- "TasksLibraryCategory": "Libraría",
+ "ValueHasBeenAddedToLibrary": "{0} engadiuse á túa biblioteca de medios",
+ "TasksLibraryCategory": "Biblioteca",
"TasksMaintenanceCategory": "Mantemento",
"VersionNumber": "Versión {0}",
"UserPolicyUpdatedWithName": "A política de usuario foi actualizada para {0}",
"UserPasswordChangedWithName": "Cambiouse o contrasinal para o usuario {0}",
"UserOnlineFromDevice": "{0} está en liña desde {1}",
- "UserOfflineFromDevice": "{0} desconectouse desde {1}",
- "TaskOptimizeDatabaseDescription": "Compacta e libera o espazo libre da base de datos. Executar esta tarefa logo de realizar mudanzas que impliquen modificacións da base de datos ou despois de escanear a biblioteca pode traer mellorías de desempeño.",
+ "UserOfflineFromDevice": "{0} desconectouse dende {1}",
+ "TaskOptimizeDatabaseDescription": "Compacta e libera espazo na base de datos. Executar esta tarefa logo de facer cambios que muden a base de datos ou despois de escanear a biblioteca pode mellorar o rendemento.",
"TaskOptimizeDatabase": "Optimizar base de datos",
- "TaskKeyframeExtractorDescription": "Extrae fragmentos do vídeo para crear listas de reprodución HLS máis precisas. Podería levarlle bastante tempo.",
+ "TaskKeyframeExtractorDescription": "Extrae fotogramas clave dos vídeos para crear listas de reprodución HLS máis precisas. Podería levar moito tempo.",
"External": "Externo",
"HearingImpaired": "Problemas de audición",
- "TaskKeyframeExtractor": "Extractor de fragmentos",
- "TaskAudioNormalization": "Normalización do audio",
- "TaskRefreshTrickplayImagesDescription": "Crea vistas previas de reprodución con truco para vídeos en bibliotecas activadas.",
+ "TaskKeyframeExtractor": "Extractor de fotogramas clave",
+ "TaskAudioNormalization": "Normalización de volume",
+ "TaskRefreshTrickplayImagesDescription": "Crea miniaturas de previsualización para os vídeos nas bibliotecas habilitadas.",
"TaskDownloadMissingLyrics": "Descargar letras que faltan",
- "TaskDownloadMissingLyricsDescription": "Descargas de letras das cancións",
+ "TaskDownloadMissingLyricsDescription": "Descarga as letras das cancións",
"TaskCleanCollectionsAndPlaylists": "Limpar coleccións e listas de reprodución",
- "TaskCleanCollectionsAndPlaylistsDescription": "Elimina elementos de coleccións e listas de reprodución que xa non existen.",
- "TaskExtractMediaSegmentsDescription": "Extrae ou obtén segmentos multimedia de complementos habilitados para o Segmento de medios.",
- "TaskExtractMediaSegments": "Escaneo de segmentos multimedia",
- "TaskMoveTrickplayImages": "Migrar a localización da imaxe de Trickplay",
- "TaskMoveTrickplayImagesDescription": "Move os ficheiros de reprodución con trickplay existentes segundo a configuración da biblioteca.",
- "TaskRefreshTrickplayImages": "Xerar imaxes de Trickplay",
- "TaskAudioNormalizationDescription": "Analiza ficheiros para obter datos de normalización de audio.",
- "CleanupUserDataTask": "Tarefa de limpeza de datos do usuario",
- "CleanupUserDataTaskDescription": "Limpa todos os datos do usuario (Estado de visualización, estado de favorito, etc) da multimedia que leve non presente polo menos durante 90 días."
+ "TaskCleanCollectionsAndPlaylistsDescription": "Quita ítems que xa non existen das coleccións e listas de reprodución.",
+ "TaskExtractMediaSegmentsDescription": "Procura segmentos de medios cos plugins habilitados.",
+ "TaskExtractMediaSegments": "Escaneo de segmentos de medios",
+ "TaskMoveTrickplayImages": "Migrar as miniaturas de previsualización a outra ubicación",
+ "TaskMoveTrickplayImagesDescription": "Move as miniaturas de previsualización segundo a configuración da biblioteca.",
+ "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."
}
diff --git a/Emby.Server.Implementations/Localization/Core/hr.json b/Emby.Server.Implementations/Localization/Core/hr.json
index a56ef82fc..67263d3b2 100644
--- a/Emby.Server.Implementations/Localization/Core/hr.json
+++ b/Emby.Server.Implementations/Localization/Core/hr.json
@@ -125,8 +125,8 @@
"TaskKeyframeExtractor": "Izvoditelj ključnog okvira",
"TaskOptimizeDatabaseDescription": "Sažima bazu podataka i uklanja prazan prostor. Pokretanje ovog zadatka, može poboljšati performanse nakon provođenja indeksiranja biblioteke ili provođenja drugih promjena koje utječu na bazu podataka.",
"HearingImpaired": "Oštećen sluh",
- "TaskRefreshTrickplayImages": "Generiraj Trickplay Slike",
- "TaskRefreshTrickplayImagesDescription": "Kreira trickplay pretpreglede za videe u omogućenim knjižnicama.",
+ "TaskRefreshTrickplayImages": "Generiraj slike brzog pregledavanja",
+ "TaskRefreshTrickplayImagesDescription": "Stvara preglede brzog pregledavanja za videa u aktiviranim bibliotekama.",
"TaskAudioNormalization": "Normalizacija zvuka",
"TaskAudioNormalizationDescription": "Skenira datoteke u potrazi za podacima o normalizaciji zvuka.",
"TaskCleanCollectionsAndPlaylistsDescription": "Uklanja stavke iz zbirki i popisa za reprodukciju koje više ne postoje.",
@@ -135,8 +135,8 @@
"TaskDownloadMissingLyrics": "Preuzmi tekstove koji nedostaju",
"TaskDownloadMissingLyricsDescription": "Preuzmi tekstove pjesama",
"TaskExtractMediaSegmentsDescription": "Izvlači ili pribavlja dijelove medija iz omogućenih media pluginova.",
- "TaskMoveTrickplayImages": "Preseli lokaciju Trickplay slika",
- "TaskMoveTrickplayImagesDescription": "Preseli lokaciju Trickplay slika prema postavkama zbirke.",
+ "TaskMoveTrickplayImages": "Premjesti mjesto slika brzog pregledavanja",
+ "TaskMoveTrickplayImagesDescription": "Premješta postojeće datoteke brzog pregledavanja prema postavkama biblioteke.",
"CleanupUserDataTask": "Zadatak čišćenja korisničkih podataka",
"CleanupUserDataTaskDescription": "Briše sve korisničke podatke (stanje gledanja, status favorita itd.) s medija koji više nisu prisutni najmanje 90 dana."
}
diff --git a/Emby.Server.Implementations/Localization/Core/ur.json b/Emby.Server.Implementations/Localization/Core/ur.json
index 376683041..94d9c8541 100644
--- a/Emby.Server.Implementations/Localization/Core/ur.json
+++ b/Emby.Server.Implementations/Localization/Core/ur.json
@@ -1,3 +1,16 @@
{
- "Books": "کتابیں"
+ "Books": "کتابیں",
+ "AppDeviceValues": "ایپ: {0}، ڈیوائس: {1}",
+ "Albums": "البمز",
+ "Application": "ایپلی کیشن",
+ "Artists": "فنکار",
+ "AuthenticationSucceededWithUserName": "{0} کی کامیابی سے تصدیق ہو چکی ہے",
+ "CameraImageUploadedFrom": "ایک نئی کیمرے کی تصویر {0} سے اپ لوڈ کی گئی ہے",
+ "Channels": "چینلز",
+ "ChapterNameValue": "باب {0}",
+ "Collections": "مجموعے",
+ "Default": "ڈیفالٹ",
+ "DeviceOfflineWithName": "{0} نے رابطہ منقطع کر دیا ہے",
+ "DeviceOnlineWithName": "{0} منسلک ہے",
+ "External": "بیرونی"
}
diff --git a/Emby.Server.Implementations/Localization/Core/ur_PK.json b/Emby.Server.Implementations/Localization/Core/ur_PK.json
index 5d3f19432..f6539adff 100644
--- a/Emby.Server.Implementations/Localization/Core/ur_PK.json
+++ b/Emby.Server.Implementations/Localization/Core/ur_PK.json
@@ -123,5 +123,9 @@
"TaskCleanActivityLogDescription": "تشکیل شدہ عمر سے زیادہ پرانی سرگرمی لاگ اندراجات کو حذف کرتا ہے۔",
"External": "بیرونی",
"HearingImpaired": "قوت سماعت سے محروم",
- "TaskCleanActivityLog": "سرگرمی لاگ کو صاف کریں"
+ "TaskCleanActivityLog": "سرگرمی لاگ کو صاف کریں",
+ "TaskDownloadMissingLyrics": "غائب بول ڈاؤن لوڈ کریں",
+ "TaskDownloadMissingLyricsDescription": "گانے کے غائب بول ڈاؤن لوڈ کریں",
+ "TaskAudioNormalization": "آڈیو نارملائزیشن",
+ "TaskAudioNormalizationDescription": "آڈیو نارملائزیشن ڈیٹا کے لیے فائلوں کو سکین کرتا ہے۔"
}
diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
index 0884efa43..f4396301c 100644
--- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
+++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
@@ -1232,8 +1232,20 @@ public sealed class BaseItemRepository
ExcludeItemIds = filter.ExcludeItemIds
};
- var query = TranslateQuery(innerQuery, context, outerQueryFilter)
- .GroupBy(e => e.PresentationUniqueKey);
+ var masterQuery = TranslateQuery(innerQuery, context, outerQueryFilter)
+ .GroupBy(e => e.PresentationUniqueKey)
+ .Select(e => e.FirstOrDefault())
+ .Select(e => e!.Id);
+
+ var query = context.BaseItems
+ .Include(e => e.TrailerTypes)
+ .Include(e => e.Provider)
+ .Include(e => e.LockedFields)
+ .Include(e => e.Images)
+ .AsSingleQuery()
+ .Where(e => masterQuery.Contains(e.Id));
+
+ query = ApplyOrder(query, filter);
var result = new QueryResult<(BaseItemDto, ItemCounts?)>();
if (filter.EnableTotalRecordCount)
@@ -1288,12 +1300,7 @@ public sealed class BaseItemRepository
var resultQuery = query.Select(e => new
{
- item = e.AsQueryable()
- .Include(e => e.TrailerTypes)
- .Include(e => e.Provider)
- .Include(e => e.LockedFields)
- .Include(e => e.Images)
- .AsSingleQuery().First(),
+ item = e,
// TODO: This is bad refactor!
itemCount = new ItemCounts()
{
@@ -1325,13 +1332,6 @@ public sealed class BaseItemRepository
result.Items =
[
.. query
- .Select(e => e.AsQueryable()
- .Include(e => e.TrailerTypes)
- .Include(e => e.Provider)
- .Include(e => e.LockedFields)
- .Include(e => e.Images)
- .AsSingleQuery()
- .First())
.AsEnumerable()
.Where(e => e is not null)
.Select<BaseItemEntity, (BaseItemDto, ItemCounts?)>(e =>
@@ -1875,10 +1875,17 @@ public sealed class BaseItemRepository
if (filter.PersonIds.Length > 0)
{
+ var peopleEntityIds = context.BaseItems
+ .WhereOneOrMany(filter.PersonIds, b => b.Id)
+ .Join(
+ context.Peoples,
+ b => b.Name,
+ p => p.Name,
+ (b, p) => p.Id);
+
baseQuery = baseQuery
- .Where(e =>
- context.PeopleBaseItemMap.Where(w => context.BaseItems.Where(r => filter.PersonIds.Contains(r.Id)).Any(f => f.Name == w.People.Name))
- .Any(f => f.ItemId == e.Id));
+ .Where(e => context.PeopleBaseItemMap
+ .Any(m => m.ItemId == e.Id && peopleEntityIds.Contains(m.PeopleId)));
}
if (!string.IsNullOrWhiteSpace(filter.Person))
diff --git a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs
index e03c13691..355ed6479 100644
--- a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs
+++ b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs
@@ -95,6 +95,7 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider, I
.ToArray();
var toAdd = people
+ .Where(e => e.Type is not PersonKind.Artist && e.Type is not PersonKind.AlbumArtist)
.Where(e => !existingPersons.Any(f => f.Name == e.Name && f.PersonType == e.Type.ToString()))
.Select(Map);
context.Peoples.AddRange(toAdd);
@@ -108,6 +109,11 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider, I
foreach (var person in people)
{
+ if (person.Type == PersonKind.Artist || person.Type == PersonKind.AlbumArtist)
+ {
+ continue;
+ }
+
var entityPerson = personsEntities.First(e => e.Name == person.Name && e.PersonType == person.Type.ToString());
var existingMap = existingMaps.FirstOrDefault(e => e.People.Name == person.Name && e.People.PersonType == person.Type.ToString() && e.Role == person.Role);
if (existingMap is null)
diff --git a/Jellyfin.Server/Migrations/Routines/CleanMusicArtist.cs b/Jellyfin.Server/Migrations/Routines/CleanMusicArtist.cs
new file mode 100644
index 000000000..d5c5f3d92
--- /dev/null
+++ b/Jellyfin.Server/Migrations/Routines/CleanMusicArtist.cs
@@ -0,0 +1,47 @@
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations;
+using Jellyfin.Server.ServerSetupApp;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Logging;
+
+namespace Jellyfin.Server.Migrations.Routines;
+
+/// <summary>
+/// Cleans up all Music artists that have been migrated in the 10.11 RC migrations.
+/// </summary>
+[JellyfinMigration("2025-10-09T20:00:00", nameof(CleanMusicArtist))]
+[JellyfinMigrationBackup(JellyfinDb = true)]
+public class CleanMusicArtist : IAsyncMigrationRoutine
+{
+ private readonly IStartupLogger<CleanMusicArtist> _startupLogger;
+ private readonly IDbContextFactory<JellyfinDbContext> _dbContextFactory;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CleanMusicArtist"/> class.
+ /// </summary>
+ /// <param name="startupLogger">The startup logger.</param>
+ /// <param name="dbContextFactory">The Db context factory.</param>
+ public CleanMusicArtist(IStartupLogger<CleanMusicArtist> startupLogger, IDbContextFactory<JellyfinDbContext> dbContextFactory)
+ {
+ _startupLogger = startupLogger;
+ _dbContextFactory = dbContextFactory;
+ }
+
+ /// <inheritdoc/>
+ public async Task PerformAsync(CancellationToken cancellationToken)
+ {
+ var context = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
+ await using (context.ConfigureAwait(false))
+ {
+ var peoples = context.Peoples.Where(e => e.PersonType == nameof(PersonKind.Artist) || e.PersonType == nameof(PersonKind.AlbumArtist));
+ _startupLogger.LogInformation("Delete {Number} Artist and Album Artist person types from db", await peoples.CountAsync(cancellationToken).ConfigureAwait(false));
+
+ await peoples
+ .ExecuteDeleteAsync(cancellationToken)
+ .ConfigureAwait(false);
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index e62004510..e9a383690 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -457,6 +457,12 @@ namespace MediaBrowser.Controller.Entities
{
foreach (var item in itemsRemoved)
{
+ if (!item.CanDelete())
+ {
+ Logger.LogDebug("Item marked as non-removable, skipping: {Path}", item.Path ?? item.Name);
+ continue;
+ }
+
if (item.IsFileProtocol)
{
Logger.LogDebug("Removed item: {Path}", item.Path);
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalUrlProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalUrlProvider.cs
index 56b0d9bcb..6c1fbbeb7 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalUrlProvider.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalUrlProvider.cs
@@ -22,7 +22,7 @@ public class AudioDbArtistExternalUrlProvider : IExternalUrlProvider
var baseUrl = "https://www.theaudiodb.com/";
switch (item)
{
- case MusicAlbum:
+ case MusicArtist:
case Person:
yield return baseUrl + $"artist/{externalId}";
break;
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalUrlProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalUrlProvider.cs
index ee5a597c6..398ec2d20 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalUrlProvider.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalUrlProvider.cs
@@ -21,7 +21,7 @@ public class MusicBrainzArtistExternalUrlProvider : IExternalUrlProvider
{
switch (item)
{
- case MusicAlbum:
+ case MusicArtist:
case Person:
yield return Plugin.Instance!.Configuration.Server + $"/artist/{externalId}";