From d96d65b8af7fbb3bb0f016962340919a0358ebd4 Mon Sep 17 00:00:00 2001 From: sct Date: Tue, 15 Dec 2020 09:16:35 +0000 Subject: [PATCH 01/22] refactor(api): increased plex sync speed and changed full sync to run every 24 hours With this change, plex sync will now process 20 items at a time every 4 seconds. (About double its previous speed). We will see how much faster we can push this in the future. --- server/job/plexsync/index.ts | 5 +++-- server/job/schedule.ts | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/server/job/plexsync/index.ts b/server/job/plexsync/index.ts index cf1b3823b..cefce9fd1 100644 --- a/server/job/plexsync/index.ts +++ b/server/job/plexsync/index.ts @@ -8,7 +8,8 @@ import logger from '../../logger'; import { getSettings, Library } from '../../lib/settings'; import Season from '../../entity/Season'; -const BUNDLE_SIZE = 10; +const BUNDLE_SIZE = 20; +const UPDATE_RATE = 4 * 1000; const imdbRegex = new RegExp(/imdb:\/\/(tt[0-9]+)/); const tmdbRegex = new RegExp(/tmdb:\/\/([0-9]+)/); @@ -277,7 +278,7 @@ class JobPlexSync { end: end + BUNDLE_SIZE, }); resolve(); - }, 5000) + }, UPDATE_RATE) ); } } diff --git a/server/job/schedule.ts b/server/job/schedule.ts index 43ef1113e..4ce2f8f87 100644 --- a/server/job/schedule.ts +++ b/server/job/schedule.ts @@ -13,7 +13,7 @@ export const startJobs = (): void => { // Run recently added plex sync every 5 minutes scheduledJobs.push({ name: 'Plex Recently Added Sync', - job: schedule.scheduleJob('0 */10 * * * *', () => { + job: schedule.scheduleJob('0 */5 * * * *', () => { logger.info('Starting scheduled job: Plex Recently Added Sync', { label: 'Jobs', }); @@ -23,7 +23,7 @@ export const startJobs = (): void => { // Run full plex sync every 6 hours scheduledJobs.push({ name: 'Plex Full Library Sync', - job: schedule.scheduleJob('0 0 */6 * * *', () => { + job: schedule.scheduleJob('0 0 3 * * *', () => { logger.info('Starting scheduled job: Plex Full Sync', { label: 'Jobs' }); jobPlexFullSync.run(); }), From e08fa35548bb8644afa8df3124e6f9cc3a2c8f4a Mon Sep 17 00:00:00 2001 From: sct Date: Tue, 15 Dec 2020 10:23:19 +0000 Subject: [PATCH 02/22] fix(api): only run recently added sync on enabled libraries fixes #259 --- overseerr-api.yml | 1 - server/api/plexapi.ts | 9 +++++--- server/job/plexsync/index.ts | 40 ++++++++++++++++++++++-------------- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/overseerr-api.yml b/overseerr-api.yml index 07da768af..28bdcadb2 100644 --- a/overseerr-api.yml +++ b/overseerr-api.yml @@ -643,7 +643,6 @@ components: readOnly: true requestedBy: $ref: '#/components/schemas/User' - readOnly: true modifiedBy: anyOf: - $ref: '#/components/schemas/User' diff --git a/server/api/plexapi.ts b/server/api/plexapi.ts index c8e123710..cc71b07e7 100644 --- a/server/api/plexapi.ts +++ b/server/api/plexapi.ts @@ -4,10 +4,12 @@ import { getSettings } from '../lib/settings'; export interface PlexLibraryItem { ratingKey: string; parentRatingKey?: string; + grandparentRatingKey?: string; title: string; guid: string; parentGuid?: string; - type: 'movie' | 'show' | 'season'; + grandparentGuid?: string; + type: 'movie' | 'show' | 'season' | 'episode'; } interface PlexLibraryResponse { @@ -20,6 +22,7 @@ export interface PlexLibrary { type: 'show' | 'movie'; key: string; title: string; + agent: string; } interface PlexLibrariesResponse { @@ -120,9 +123,9 @@ class PlexAPI { return response.MediaContainer.Metadata[0]; } - public async getRecentlyAdded(): Promise { + public async getRecentlyAdded(id: string): Promise { const response = await this.plexClient.query( - '/library/recentlyAdded' + `/library/sections/${id}/recentlyAdded` ); return response.MediaContainer.Metadata; diff --git a/server/job/plexsync/index.ts b/server/job/plexsync/index.ts index cefce9fd1..d64e5898d 100644 --- a/server/job/plexsync/index.ts +++ b/server/job/plexsync/index.ts @@ -137,7 +137,9 @@ class JobPlexSync { try { const metadata = await this.plexClient.getMetadata( - plexitem.parentRatingKey ?? plexitem.ratingKey, + plexitem.grandparentRatingKey ?? + plexitem.parentRatingKey ?? + plexitem.ratingKey, { includeChildren: true } ); if (metadata.guid.match(tvdbRegex)) { @@ -240,7 +242,9 @@ class JobPlexSync { } catch (e) { this.log( `Failed to process plex item. ratingKey: ${ - plexitem.parentRatingKey ?? plexitem.ratingKey + plexitem.grandparentRatingKey ?? + plexitem.parentRatingKey ?? + plexitem.ratingKey }`, 'error' ); @@ -252,7 +256,11 @@ class JobPlexSync { slicedItems.map(async (plexitem) => { if (plexitem.type === 'movie') { await this.processMovie(plexitem); - } else if (plexitem.type === 'show') { + } else if ( + plexitem.type === 'show' || + plexitem.type === 'episode' || + plexitem.type === 'season' + ) { await this.processShow(plexitem); } }) @@ -301,20 +309,22 @@ class JobPlexSync { }); this.plexClient = new PlexAPI({ plexToken: admin.plexToken }); + + this.libraries = settings.plex.libraries.filter( + (library) => library.enabled + ); + if (this.isRecentOnly) { - this.currentLibrary = { - id: '0', - name: 'Recently Added', - enabled: true, - }; - this.log(`Beginning to process recently added`, 'info'); - this.items = await this.plexClient.getRecentlyAdded(); - await this.loop(); + for (const library of this.libraries) { + this.currentLibrary = library; + this.log( + `Beginning to process recently added for library: ${library.name}`, + 'info' + ); + this.items = await this.plexClient.getRecentlyAdded(library.id); + await this.loop(); + } } else { - this.libraries = settings.plex.libraries.filter( - (library) => library.enabled - ); - for (const library of this.libraries) { this.currentLibrary = library; this.log(`Beginning to process library: ${library.name}`, 'info'); From 01c179f762e686a1e5a3d4dab3a5bea53425b575 Mon Sep 17 00:00:00 2001 From: sct Date: Tue, 15 Dec 2020 10:24:39 +0000 Subject: [PATCH 03/22] fix(api): filter out libraries that do not have any metadata agent or are not movie/show --- server/routes/settings.ts | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/server/routes/settings.ts b/server/routes/settings.ts index fee4e5c78..b278652c4 100644 --- a/server/routes/settings.ts +++ b/server/routes/settings.ts @@ -93,17 +93,22 @@ settingsRoutes.get('/plex/library', async (req, res) => { const libraries = await plexapi.getLibraries(); - const newLibraries: Library[] = libraries.map((library) => { - const existing = settings.plex.libraries.find( - (l) => l.id === library.key - ); - - return { - id: library.key, - name: library.title, - enabled: existing?.enabled ?? false, - }; - }); + const newLibraries: Library[] = libraries + // Remove libraries that are not movie or show + .filter((library) => library.type === 'movie' || library.type === 'show') + // Remove libraries that do not have a metadata agent set (usually personal video libraries) + .filter((library) => library.agent !== 'com.plexapp.agents.none') + .map((library) => { + const existing = settings.plex.libraries.find( + (l) => l.id === library.key + ); + + return { + id: library.key, + name: library.title, + enabled: existing?.enabled ?? false, + }; + }); settings.plex.libraries = newLibraries; } From fddbb3cdfe3d50b2835c248556139c769dc2b805 Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Tue, 15 Dec 2020 12:39:14 +0100 Subject: [PATCH 04/22] feat(lang): Translations update from Weblate (#291) * feat(lang): translated using Weblate (Spanish) Currently translated at 100.0% (321 of 321 strings) feat(lang): translated using Weblate (Spanish) Currently translated at 56.0% (180 of 321 strings) feat(lang): translated using Weblate (Spanish) Currently translated at 52.6% (169 of 321 strings) feat(lang): added translation using Weblate (Spanish) Co-authored-by: Hosted Weblate Co-authored-by: TheRaZex Co-authored-by: sct Translate-URL: https://hosted.weblate.org/projects/overseerr/overseerr-frontend/es/ Translation: Overseerr/Overseerr Frontend * feat(lang): translated using Weblate (German) Currently translated at 100.0% (310 of 310 strings) Co-authored-by: Hosted Weblate Co-authored-by: K. Herbert Translate-URL: https://hosted.weblate.org/projects/overseerr/overseerr-frontend/de/ Translation: Overseerr/Overseerr Frontend * feat(lang): translated using Weblate (Dutch) Currently translated at 100.0% (314 of 314 strings) feat(lang): translated using Weblate (Dutch) Currently translated at 100.0% (310 of 310 strings) Co-authored-by: Hosted Weblate Co-authored-by: Jos Vennik Co-authored-by: K. Herbert Translate-URL: https://hosted.weblate.org/projects/overseerr/overseerr-frontend/nl/ Translation: Overseerr/Overseerr Frontend * feat(lang): translated using Weblate (Japanese) Currently translated at 100.0% (321 of 321 strings) Co-authored-by: Hosted Weblate Co-authored-by: T'ai Translate-URL: https://hosted.weblate.org/projects/overseerr/overseerr-frontend/ja/ Translation: Overseerr/Overseerr Frontend * feat(lang): translated using Weblate (French) Currently translated at 100.0% (310 of 310 strings) Co-authored-by: Hosted Weblate Co-authored-by: J. Lavoie Translate-URL: https://hosted.weblate.org/projects/overseerr/overseerr-frontend/fr/ Translation: Overseerr/Overseerr Frontend Co-authored-by: TheRaZex Co-authored-by: sct Co-authored-by: K. Herbert Co-authored-by: Jos Vennik Co-authored-by: T'ai Co-authored-by: J. Lavoie --- src/i18n/locale/de.json | 10 +- src/i18n/locale/es.json | 323 ++++++++++++++++++++++++++++++++++++++++ src/i18n/locale/fr.json | 6 +- src/i18n/locale/ja.json | 21 ++- src/i18n/locale/nl.json | 16 +- 5 files changed, 364 insertions(+), 12 deletions(-) create mode 100644 src/i18n/locale/es.json diff --git a/src/i18n/locale/de.json b/src/i18n/locale/de.json index 75eb151d7..a37b6b1c9 100644 --- a/src/i18n/locale/de.json +++ b/src/i18n/locale/de.json @@ -1,9 +1,9 @@ { "components.Discover.discovermovies": "Beliebte Filme", - "components.Discover.discovertv": "Beliebte Serie", + "components.Discover.discovertv": "Beliebte Serien", "components.Discover.nopending": "Keine ausstehenden Anträge", "components.Discover.popularmovies": "Beliebte Filme", - "components.Discover.populartv": "Beliebte Serie", + "components.Discover.populartv": "Beliebte Serien", "components.Discover.recentlyAdded": "Kürzlich hinzugefügt", "components.Discover.recentrequests": "Letzte Anträge", "components.Discover.trending": "Trends", @@ -304,5 +304,9 @@ "pages.serviceUnavailable": "{statusCode} – Dienst nicht verfügbar", "pages.somethingWentWrong": "{statusCode} – Es ist ein Fehler aufgetreten", "components.TvDetails.TvCast.fullseriescast": "Vollserienbesetzung", - "components.MovieDetails.MovieCast.fullcast": "Vollständige Besetzung" + "components.MovieDetails.MovieCast.fullcast": "Vollständige Besetzung", + "components.Settings.Notifications.emailsettingssaved": "E-Mail-Benachrichtigungseinstellungen gespeichert!", + "components.Settings.Notifications.emailsettingsfailed": "Die Einstellungen für die E-Mail-Benachrichtigungen konnten nicht gespeichert werden.", + "components.Settings.Notifications.discordsettingssaved": "Discord-Benachrichtigungseinstellungen gespeichert!", + "components.Settings.Notifications.discordsettingsfailed": "Die Einstellungen für die Discord-Benachrichtigungen konnten nicht gespeichert werden." } diff --git a/src/i18n/locale/es.json b/src/i18n/locale/es.json new file mode 100644 index 000000000..2e7905caf --- /dev/null +++ b/src/i18n/locale/es.json @@ -0,0 +1,323 @@ +{ + "components.Settings.SonarrModal.toastRadarrTestFailure": "Error al connectar al Servidor Sonarr", + "components.Settings.SonarrModal.testing": "Comprobando...", + "components.Settings.SonarrModal.test": "Comprobar", + "components.Settings.SonarrModal.ssl": "SSL", + "components.Settings.SonarrModal.servernamePlaceholder": "Un servidor Sonarr", + "components.Settings.SonarrModal.servername": "Nombre del Servidor", + "components.Settings.SonarrModal.server4k": "Servidor 4K", + "components.Settings.SonarrModal.selectRootFolder": "Selecciona la Carpeta Raíz", + "components.Settings.SonarrModal.selectQualityProfile": "Selecciona un Perfil de Calidad", + "components.Settings.SonarrModal.seasonfolders": "Carpetas por Temporada", + "components.Settings.SonarrModal.saving": "Guardando...", + "components.Settings.SonarrModal.save": "Guardar Cambios", + "components.Settings.SonarrModal.rootfolder": "Carpeta Raíz", + "components.Settings.SonarrModal.qualityprofile": "Perfil de Calidad", + "components.Settings.SonarrModal.port": "Puerto", + "components.Settings.SonarrModal.hostname": "Nombre de Host", + "components.Settings.SonarrModal.editsonarr": "Editar Servidor Sonarr", + "components.Settings.SonarrModal.defaultserver": "Servidor por Defecto", + "components.Settings.SonarrModal.createsonarr": "Crear Nuevo Servidor Sonarr", + "components.Settings.SonarrModal.baseUrlPlaceholder": "Ejemplo: /sonarr", + "components.Settings.SonarrModal.baseUrl": "URL Base", + "components.Settings.SonarrModal.apiKeyPlaceholder": "Tu Clave API de Sonarr", + "components.Settings.SonarrModal.apiKey": "Clave API", + "components.Settings.SonarrModal.add": "Agregar Servidor", + "components.Settings.SettingsAbout.version": "Versión", + "components.Settings.SettingsAbout.totalrequests": "Peticiones Totales", + "components.Settings.SettingsAbout.totalmedia": "Contenido Total", + "components.Settings.SettingsAbout.overseerrinformation": "Información de Overseerr", + "components.Settings.SettingsAbout.githubdiscussions": "Discursiones en GitHub", + "components.Settings.SettingsAbout.gettingsupport": "Soporte", + "components.Settings.SettingsAbout.clickheretojoindiscord": "Click aquín para unirte a nuestro servidor de Discord.", + "components.Settings.RadarrModal.validationRootFolderRequired": "Debes seleccionar una carpeta raíz", + "components.Settings.RadarrModal.validationProfileRequired": "Debes seleccionar un perfil", + "components.Settings.RadarrModal.validationPortRequired": "Debes proporcionar un puerto", + "components.Settings.RadarrModal.validationNameRequired": "Debes proporcionar un nombre de servidor", + "components.Settings.RadarrModal.validationHostnameRequired": "Debes proporcionar un hostname/IP", + "components.Settings.RadarrModal.validationApiKeyRequired": "Debes proporcionar la clave API", + "components.Settings.RadarrModal.toastRadarrTestSuccess": "¡Conexión con Radarr establecida!", + "components.Settings.RadarrModal.toastRadarrTestFailure": "Error al connectar al Servidor Radarr", + "components.Settings.RadarrModal.testing": "Comprobando...", + "components.Settings.RadarrModal.test": "Comprobar", + "components.Settings.RadarrModal.ssl": "SSL", + "components.Settings.RadarrModal.servernamePlaceholder": "Un Servidor Radarr", + "components.Settings.RadarrModal.servername": "Nombre del Servidor", + "components.Settings.RadarrModal.server4k": "Servidor 4K", + "components.Settings.RadarrModal.selectRootFolder": "Selecciona la Carpeta Raíz", + "components.Settings.RadarrModal.selectQualityProfile": "Selecciona un Perfil de Calidad", + "components.Settings.RadarrModal.selectMinimumAvailability": "Selecciona Disponibilidad Mínima", + "components.Settings.RadarrModal.saving": "Guardando...", + "components.Settings.RadarrModal.save": "Guardar Cambios", + "components.Settings.RadarrModal.rootfolder": "Carpeta Raíz", + "components.Settings.RadarrModal.qualityprofile": "Perfil de Calidad", + "components.Settings.RadarrModal.port": "Puerto", + "components.Settings.RadarrModal.minimumAvailability": "Disponibilidad Mínima", + "components.Settings.RadarrModal.hostname": "Nombre de Host", + "components.Settings.RadarrModal.editradarr": "Editar Servidor Radarr", + "components.Settings.RadarrModal.defaultserver": "Servidor por Defecto", + "components.Settings.RadarrModal.createradarr": "Crear Nuevo Servidor Radarr", + "components.Settings.RadarrModal.baseUrlPlaceholder": "Ejemplo: /radarr", + "components.Settings.RadarrModal.baseUrl": "URL Base", + "components.Settings.RadarrModal.apiKeyPlaceholder": "Tu clave API de Radarr", + "components.Settings.RadarrModal.apiKey": "Clave API", + "components.Settings.RadarrModal.add": "Agregar Servidor", + "components.Settings.Notifications.webhookUrlPlaceholder": "Ajustes del servidor -> Integraciones -> Webhooks", + "components.Settings.Notifications.webhookUrl": "URL de Webhook", + "components.Settings.Notifications.validationWebhookUrlRequired": "Debes proporcionar una URL del webhook", + "components.Settings.Notifications.validationSmtpPortRequired": "Debes proporcionar un puerto SMTP", + "components.Settings.Notifications.validationSmtpHostRequired": "Debes proporcionar un host SMTP", + "components.Settings.Notifications.validationFromRequired": "Debes proporcionar una dirección de envío de email", + "components.Settings.Notifications.smtpPort": "Puerto SMTP", + "components.Settings.Notifications.smtpHost": "Host SMTP", + "components.Settings.Notifications.saving": "Guardando...", + "components.Settings.Notifications.save": "Guardar Cambios", + "components.Settings.Notifications.enableSsl": "Activar SSL", + "components.Settings.Notifications.emailsettingssaved": "¡Ajustes de notificación de Email guardados!", + "components.Settings.Notifications.emailsettingsfailed": "Fallo al guardar ajustes de notificación de Email.", + "components.Settings.Notifications.emailsender": "Dirección del Remitente de Email", + "components.Settings.Notifications.discordsettingssaved": "¡Ajustes de notificación de Discord guardados!", + "components.Settings.Notifications.discordsettingsfailed": "Fallo al guardar ajustes de notificación de Discord.", + "components.Settings.Notifications.authUser": "Usuario", + "components.Settings.Notifications.authPass": "Contraseña", + "components.Settings.Notifications.agentenabled": "Agente Activado", + "components.Search.searchresults": "Resultado de la búsqueda", + "components.RequestModal.status": "Estado", + "components.RequestModal.selectseason": "Seleccionar temporada(s)", + "components.RequestModal.seasonnumber": "Temporada {number}", + "components.RequestModal.season": "Temporada", + "components.RequestModal.requesttitle": "Solicitar {title}", + "components.RequestModal.requestseasons": "Solicitar {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}", + "components.RequestModal.requesting": "Solicitando…", + "components.RequestModal.requestfrom": "Hay una petición pendiente de {username}", + "components.RequestModal.requestadmin": "Tu petición será aprovada inmediatamente.", + "components.RequestModal.requestSuccess": "{title} solicitado.", + "components.RequestList.showingresults": "Mostrando {from} a {to} de {total} resultados", + "components.RequestModal.requestCancel": "Solicitud para {title} cancelada", + "components.RequestModal.request": "Solicitar", + "components.RequestModal.pendingrequest": "Solicitud pendiente para {title}", + "components.RequestModal.numberofepisodes": "# de Episodios", + "components.RequestModal.notrequested": "No Solicitado", + "components.RequestModal.extras": "Extras", + "components.RequestModal.close": "Cerrar", + "components.RequestModal.cancelrequest": "Esto borrará tu petición. ¿Quieres continuar?", + "components.RequestModal.cancelling": "Cancelando...", + "components.RequestModal.cancel": "Cancelar Petición", + "components.RequestList.status": "Estado", + "components.RequestList.requests": "Peticiones", + "components.RequestList.requestedAt": "Solicitado", + "components.RequestList.previous": "Anterior", + "components.RequestList.next": "Siguiente", + "components.RequestList.modifiedBy": "Última Edición Por", + "components.RequestList.mediaInfo": "Información", + "components.RequestList.RequestItem.seasons": "Temporadas", + "components.RequestList.RequestItem.requestedby": "Solicitado por {username}", + "components.RequestList.RequestItem.notavailable": "N/D", + "components.RequestCard.seasons": "Temporadas", + "components.RequestCard.requestedby": "Solicitado por {username}", + "components.RequestCard.all": "Todas", + "components.RequestBlock.seasons": "Temporadas", + "components.PlexLoginButton.loginwithplex": "Iniciar Sesión con Plex", + "components.PlexLoginButton.loggingin": "Iniciando Sesión...", + "components.PlexLoginButton.loading": "Cargando...", + "components.PersonDetails.nobiography": "No hay biografía disponible.", + "components.PersonDetails.ascharacter": "como {character}", + "components.PersonDetails.appearsin": "Aparece en", + "components.MovieDetails.viewrequest": "Ver Petición", + "components.MovieDetails.userrating": "Puntuación de los Usuarios", + "components.MovieDetails.unavailable": "No Disponible", + "components.MovieDetails.status": "Estado", + "components.MovieDetails.similarsubtext": "Otras películas parecidas a {title}", + "components.MovieDetails.similar": "Títulos Similares", + "components.MovieDetails.runtime": "{minutes} minutos", + "components.MovieDetails.revenue": "Recaudado", + "components.MovieDetails.request": "Solicitar", + "components.MovieDetails.releasedate": "Fecha de Lanzamiento", + "components.MovieDetails.recommendationssubtext": "Si te gustó {title}, también te puede gustar...", + "components.MovieDetails.cast": "Reparto", + "components.MovieDetails.MovieCast.fullcast": "Reparto Completo", + "components.MovieDetails.recommendations": "Recomendaciones", + "components.MovieDetails.pending": "Pendiente", + "components.MovieDetails.overviewunavailable": "Resumen no disponible", + "components.MovieDetails.overview": "Resumen", + "components.MovieDetails.originallanguage": "Idioma Original", + "components.MovieDetails.manageModalTitle": "Gestionar Película", + "components.MovieDetails.manageModalRequests": "Peticiones", + "components.MovieDetails.manageModalNoRequests": "Sin Peticiones", + "components.MovieDetails.manageModalClearMediaWarning": "Esto borrará todos los datos de los medios, incluyendo las peticiones. Si el elemento existe en tu librería de Plex, la información del elemento se recreará en la siguiente sincronización.", + "components.MovieDetails.manageModalClearMedia": "Borrar todos los datos de medios", + "components.MovieDetails.decline": "Rechazar", + "components.MovieDetails.cancelrequest": "Cancelar Petición", + "components.MovieDetails.budget": "Presupuesto", + "components.MovieDetails.available": "Disponible", + "components.MovieDetails.approve": "Aprobar", + "components.Login.signinplex": "Inicia Sesión para continuar", + "components.Layout.UserDropdown.signout": "Cerrar Sesión", + "components.Layout.Sidebar.users": "Usuarios", + "components.Layout.Sidebar.settings": "Ajustes", + "components.Layout.Sidebar.requests": "Peticiones", + "components.Layout.Sidebar.dashboard": "Descubrir", + "components.Layout.SearchInput.searchPlaceholder": "Buscar Películas y Series", + "components.Layout.LanguagePicker.changelanguage": "Cambiar Idioma", + "components.Discover.upcomingmovies": "Próximas Películas", + "components.Discover.upcoming": "Próximas Películas", + "components.Discover.trending": "Tendencias", + "components.Discover.recentrequests": "Peticiones Recientes", + "components.Discover.recentlyAdded": "Agregado Recientemente", + "components.Discover.populartv": "Series Populares", + "components.Discover.popularmovies": "Películas Populares", + "components.Discover.nopending": "Sin Peticiones Pendientes", + "components.Discover.discovertv": "Series Populares", + "components.Discover.discovermovies": "Películas Populares", + "components.Layout.alphawarning": "Este software está en fase ALFA. Muchas cosas pueden ser inestables o fallar. ¡Por favor reporta estos problemas en el GitHub de Overseerr!", + "components.Settings.addsonarr": "Agregar servidor Sonarr", + "components.Settings.address": "Dirección", + "components.Settings.addradarr": "Agregar servidor Radarr", + "components.Settings.activeProfile": "Perfil activo", + "components.Settings.SonarrModal.validationRootFolderRequired": "Debes seleccionar una carpeta raíz", + "components.Settings.SonarrModal.validationProfileRequired": "Debes seleccionar un perfil", + "components.Settings.SonarrModal.validationPortRequired": "Debes proporcionar un puerto", + "components.Settings.SonarrModal.validationNameRequired": "Debes proporcionar un nombre de servidor", + "components.Settings.SonarrModal.validationHostnameRequired": "Debes proporcionar un hostname/IP", + "components.Settings.SonarrModal.validationApiKeyRequired": "Debes proporcionar la clave API", + "components.Settings.SonarrModal.toastRadarrTestSuccess": "¡Conexión con Sonarr establecida!", + "components.Settings.menuLogs": "Registro", + "pages.somethingWentWrong": "{statusCode} - Algo salió mal", + "pages.serviceUnavailable": "{statusCode}: Servicio no Disponible", + "pages.returnHome": "Volver al Inicio", + "pages.pageNotFound": "404 - Página no encontrada", + "pages.oops": "Ups", + "pages.internalServerError": "{statusCode}: Error interno del servidor", + "i18n.unavailable": "No Disponible", + "i18n.tvshows": "Series", + "i18n.processing": "Procesando…", + "i18n.pending": "Pendiente", + "i18n.partiallyavailable": "Parcialmente Disponible", + "i18n.movies": "Películas", + "i18n.delete": "Eliminar", + "i18n.declined": "Rechazado", + "i18n.decline": "Rechazar", + "i18n.cancel": "Cancelar", + "i18n.available": "Disponible", + "i18n.approved": "Aprobado", + "i18n.approve": "Aprobar", + "components.UserList.usertype": "Tipo de usuario", + "components.UserList.username": "Nombre de usuario", + "components.UserList.userlist": "Lista de usuarios", + "components.UserList.user": "Usuario", + "components.UserList.totalrequests": "Solicitudes totales", + "components.UserList.role": "Rol", + "components.UserList.plexuser": "Usuario de Plex", + "components.UserList.lastupdated": "Última actualización", + "components.UserList.edit": "Editar", + "components.UserList.delete": "Eliminar", + "components.UserList.created": "Creado", + "components.UserList.admin": "Administrador", + "components.UserEdit.voteDescription": "Otorga permiso para votar en las solicitudes (votación aún no implementada)", + "components.UserEdit.vote": "Votar", + "components.UserEdit.usersaved": "Usuario guardado", + "components.UserEdit.usersDescription": "Otorga permiso para administrar usuarios de Overseerr. Los usuarios con este permiso no pueden modificar a los usuarios con privilegios de administrador, o concederlos.", + "components.UserEdit.users": "Administrar usuarios", + "components.UserEdit.username": "Nombre de usuario", + "components.UserEdit.userfail": "Algo salió mal al guardar al usuario.", + "components.UserEdit.settingsDescription": "Otorga permiso para modificar todas las configuraciones de Overseerr. El usuario debe tener este permiso para otorgarlo a otros.", + "components.UserEdit.settings": "Administrar configuración", + "components.UserEdit.saving": "Guardando...", + "components.UserEdit.save": "Guardar", + "components.UserEdit.requestDescription": "Otorga permiso para solicitar películas y series.", + "components.UserEdit.request": "Solicitar", + "components.UserEdit.permissions": "Permisos", + "components.UserEdit.managerequestsDescription": "Otorga permiso para administrar las solicitudes de Overseerr. Esto incluye aprobar y rechazar solicitudes.", + "components.UserEdit.managerequests": "Gestionar solicitudes", + "components.UserEdit.email": "Correo electrónico", + "components.UserEdit.edituser": "Editar Usuario", + "components.UserEdit.avatar": "Avatar", + "components.UserEdit.autoapproveDescription": "Otorga aprobación automática para cualquier solicitud de este usuario.", + "components.UserEdit.autoapprove": "Aprobación automática", + "components.UserEdit.adminDescription": "Acceso total de administrador . Ignoran todas las comprobaciones de permisos.", + "components.UserEdit.admin": "Administrador", + "components.TvDetails.userrating": "Puntuación de los Usuarios", + "components.TvDetails.unavailable": "No Disponible", + "components.TvDetails.status": "Estado", + "components.TvDetails.similarsubtext": "Otras series similares a {title}", + "components.TvDetails.similar": "Series similares", + "components.TvDetails.requestmore": "Solicitar más", + "components.TvDetails.request": "Solicitar", + "components.TvDetails.recommendationssubtext": "Si te gustó {title}, también te puede gustar...", + "components.TvDetails.recommendations": "Recomendaciones", + "components.TvDetails.pending": "Pendiente", + "components.TvDetails.overviewunavailable": "Resumen no disponible", + "components.TvDetails.overview": "Resumen", + "components.TvDetails.originallanguage": "Idioma original", + "components.TvDetails.manageModalTitle": "Gestionar Series", + "components.TvDetails.manageModalRequests": "Peticiones", + "components.TvDetails.manageModalNoRequests": "Sin Peticiones", + "components.TvDetails.manageModalClearMediaWarning": "Esto borrará todos los datos de los medios, incluyendo las peticiones. Si el elemento existe en tu librería de Plex, la información del elemento se recreará en la siguiente sincronización.", + "components.TvDetails.manageModalClearMedia": "Borrar todos los datos de medios", + "components.TvDetails.declinerequests": "Rechazar {requestCount} {requestCount, plural, one {Request} other {Requests}}", + "components.TvDetails.decline": "Rechazar", + "components.TvDetails.cast": "Reparto", + "components.TvDetails.cancelrequest": "Cancelar Petición", + "components.TvDetails.available": "Disponible", + "components.TvDetails.approverequests": "Aprobar {requestCount} {requestCount, plural, one {Request} other {Requests}}", + "components.TvDetails.approve": "Aprobar", + "components.TvDetails.TvCast.fullseriescast": "Reparto completo de la serie", + "components.TitleCard.tvshow": "Series", + "components.Settings.jobname": "Nombre de Tarea", + "components.TitleCard.movie": "Película", + "components.Slider.noresults": "Sin resultados", + "components.Setup.welcome": "Bienvenido a Overseerr", + "components.Setup.signinMessage": "Comience iniciando sesión con su cuenta de Plex", + "components.Setup.loginwithplex": "Iniciar sesión con Plex", + "components.Setup.finishing": "Finalizando...", + "components.Setup.finish": "Finalizar configuración", + "components.Setup.continue": "Continuar", + "components.Setup.configureplex": "Configurar Plex", + "components.Setup.configureservices": "Configurar servicios", + "components.Settings.validationPortRequired": "Debes proporcionar un puerto", + "components.Settings.validationHostnameRequired": "Debe proporcionar un nombre de host / IP", + "components.Settings.syncing": "Sincronizando…", + "components.Settings.sync": "Sincronizar bibliotecas de Plex", + "components.Settings.startscan": "Iniciar escaneo", + "components.Settings.ssl": "SSL", + "components.Settings.sonarrsettings": "Ajustes de Sonarr", + "components.Settings.sonarrSettingsDescription": "Configure su conexión Sonarr a continuación. Puede tener varias instancias, pero sólo dos activas como predeterminadas en cualquier momento (una para HD estándar y otro para 4K). Los administradores pueden elegir qué servidor se utiliza para nuevas solicitudes.", + "components.Settings.servernamePlaceholder": "Nombre del servidor Plex", + "components.Settings.servername": "Nombre del servidor (Establecido automáticamente después de guardar)", + "components.Settings.saving": "Guardando...", + "components.Settings.save": "Guardar cambios", + "components.Settings.runnow": "Ejecutar ahora", + "components.Settings.radarrsettings": "Ajustes de Radarr", + "components.Settings.radarrSettingsDescription": "Configure su conexión a Radarr a continuación. Puede tener varias instancias, pero sólo dos activas como predeterminadas en cualquier momento (una para HD estándar y otro para 4K). Los administradores pueden elegir qué servidor se utiliza para nuevas solicitudes.", + "components.Settings.port": "Puerto", + "components.Settings.plexsettingsDescription": "Configure los ajustes de su servidor Plex. Overseerr usa su servidor Plex para escanear su biblioteca en un intervalo y ver qué contenido está disponible.", + "components.Settings.plexsettings": "Ajustes de Plex", + "components.Settings.plexlibrariesDescription": "Las bibliotecas en las que Overseerr busca títulos. Configure y guarde la configuración de conexión Plex y haga clic en el botón de abajo si no aparece ninguna.", + "components.Settings.plexlibraries": "Bibliotecas Plex", + "components.Settings.notrunning": "Sin ejecutarse", + "components.Settings.notificationsettingsDescription": "Aquí puedes elegir qué tipos de notificaciones enviar y a través de qué tipos de servicios.", + "components.Settings.notificationsettings": "Configuración de notificaciones", + "components.Settings.nextexecution": "Siguiente ejecución", + "components.Settings.menuServices": "Servicios", + "components.Settings.menuPlexSettings": "Plex", + "components.Settings.menuNotifications": "Notificaciones", + "components.Settings.menuJobs": "Tareas", + "components.Settings.menuGeneralSettings": "Ajustes Generales", + "components.Settings.menuAbout": "Acerca de", + "components.Settings.manualscanDescription": "Normalmente, esto sólo se ejecutará una vez cada 6 horas. Overseerr comprobará de forma más agresiva los añadidos recientemente de su servidor Plex. ¡Si es la primera vez que configura Plex se recomienda un escaneo manual completo de la biblioteca!", + "components.Settings.manualscan": "Escaneo manual de biblioteca", + "components.Settings.librariesRemaining": "Bibliotecas restantes: {count}", + "components.Settings.hostname": "Nombre de host / IP", + "components.Settings.generalsettingsDescription": "Estos son ajustes relacionados con la configuración general de Overseerr.", + "components.Settings.generalsettings": "Configuración general", + "components.Settings.edit": "Editar", + "components.Settings.deleteserverconfirm": "¿Está seguro de que desea eliminar este servidor?", + "components.Settings.delete": "Eliminar", + "components.Settings.default4k": "4K predeterminado", + "components.Settings.default": "Predeterminado", + "components.Settings.currentlibrary": "Biblioteca actual: {name}", + "components.Settings.copied": "Clave API copiada en el portapapeles", + "components.Settings.cancelscan": "Cancelar escaneo", + "components.Settings.applicationurl": "URL de la aplicación", + "components.Settings.apikey": "Clave API" +} diff --git a/src/i18n/locale/fr.json b/src/i18n/locale/fr.json index dd9cd2732..9efd51d9e 100644 --- a/src/i18n/locale/fr.json +++ b/src/i18n/locale/fr.json @@ -304,5 +304,9 @@ "pages.serviceUnavailable": "{statusCode} – Service indisponible", "pages.somethingWentWrong": "{statusCode} – Une erreur est survenue", "components.TvDetails.TvCast.fullseriescast": "Casting complet de la série", - "components.MovieDetails.MovieCast.fullcast": "Casting complet" + "components.MovieDetails.MovieCast.fullcast": "Casting complet", + "components.Settings.Notifications.emailsettingssaved": "Paramètres de notification par courriel enregistrés !", + "components.Settings.Notifications.emailsettingsfailed": "Les paramètres de notification par courriel n'ont pas pu être enregistrés.", + "components.Settings.Notifications.discordsettingssaved": "Paramètres de notification Discord enregistrés !", + "components.Settings.Notifications.discordsettingsfailed": "Les paramètres de notification Discord n'ont pas pu être enregistrés." } diff --git a/src/i18n/locale/ja.json b/src/i18n/locale/ja.json index 010b0a991..9bb9937be 100644 --- a/src/i18n/locale/ja.json +++ b/src/i18n/locale/ja.json @@ -205,7 +205,7 @@ "components.Settings.runnow": "今すぐ実行", "components.Settings.save": "変更を保存", "components.Settings.saving": "保存中...", - "components.Settings.servername": "サーバー名 (自動設定)", + "components.Settings.servername": "サーバー名 (保存時に自動で設定されます)", "components.Settings.servernamePlaceholder": "Plexサーバー名", "components.Settings.sonarrSettingsDescription": "Sonarr接続設定。複数のサーバーを繋ぐことができますが、デフォルトで常にアクティブなのは2つのみ(1つは標準HD用、もう1つは4K用)。管理者は、新しいリクエストに使用するサーバーを選択することができます。", "components.Settings.sonarrsettings": "Sonarr設定", @@ -302,5 +302,22 @@ "pages.pageNotFound": "404 - ページが見つかりません", "pages.returnHome": "ホームへ戻る", "pages.serviceUnavailable": "{statusCode} - サービスが利用できません", - "pages.somethingWentWrong": "{statusCode} - 問題が発生しました" + "pages.somethingWentWrong": "{statusCode} - 問題が発生しました", + "components.TvDetails.TvCast.fullseriescast": "フルシリーズキャスト", + "components.Settings.validationPortRequired": "ポートの入力が必要です", + "components.Settings.validationHostnameRequired": "ホスト名/IPの入力が必要です", + "components.Settings.SonarrModal.validationNameRequired": "サーバー名を指定してください", + "components.Settings.SettingsAbout.version": "バージョン", + "components.Settings.SettingsAbout.totalrequests": "総リクエスト数", + "components.Settings.SettingsAbout.totalmedia": "総メディア数", + "components.Settings.SettingsAbout.overseerrinformation": "Overseerr情報", + "components.Settings.SettingsAbout.githubdiscussions": "GitHubディスカッション", + "components.Settings.SettingsAbout.gettingsupport": "サポート", + "components.Settings.SettingsAbout.clickheretojoindiscord": "Discordサーバーの参加はこちら。", + "components.Settings.RadarrModal.validationNameRequired": "サーバー名を指定してください", + "components.Settings.Notifications.emailsettingssaved": "メール通知設定が保存されました!", + "components.Settings.Notifications.emailsettingsfailed": "メール通知設定の保存に失敗しました。", + "components.Settings.Notifications.discordsettingsfailed": "ディスコード通知設定の保存に失敗しました。", + "components.Settings.Notifications.discordsettingssaved": "ディスコードの通知設定が保存されました!", + "components.MovieDetails.MovieCast.fullcast": "フルキャスト" } diff --git a/src/i18n/locale/nl.json b/src/i18n/locale/nl.json index 6b3f36386..1a1eea45c 100644 --- a/src/i18n/locale/nl.json +++ b/src/i18n/locale/nl.json @@ -90,13 +90,13 @@ "components.Settings.Notifications.agentenabled": "Agent Ingeschakeld", "components.Settings.Notifications.authPass": "Wachtwoord", "components.Settings.Notifications.authUser": "Gebruikersnaam", - "components.Settings.Notifications.emailsender": "E-mail Adres Van Afzender", + "components.Settings.Notifications.emailsender": "E-mailadres van afzender", "components.Settings.Notifications.enableSsl": "Schakel SSL in", "components.Settings.Notifications.save": "Wijzigingen Opslaan", "components.Settings.Notifications.saving": "Bezig met opslaan...", "components.Settings.Notifications.smtpHost": "SMTP Host", "components.Settings.Notifications.smtpPort": "SMTP Poort", - "components.Settings.Notifications.validationFromRequired": "Je moet een afzender adres opgeven", + "components.Settings.Notifications.validationFromRequired": "Je moet een afzenderadres opgeven", "components.Settings.Notifications.validationSmtpHostRequired": "Je moet een SMTP host opgeven", "components.Settings.Notifications.validationSmtpPortRequired": "Je moet een SMTP poort opgeven", "components.Settings.Notifications.validationWebhookUrlRequired": "Je moet een webhook URL opgeven", @@ -205,7 +205,7 @@ "components.Settings.runnow": "Nu Starten", "components.Settings.save": "Wijzigingen Opslaan", "components.Settings.saving": "Bezig met opslaan...", - "components.Settings.servername": "Server Naam (Automatisch Ingesteld)", + "components.Settings.servername": "Server Naam (Automatisch Ingesteld na opslaan)", "components.Settings.servernamePlaceholder": "Plex Server Naam", "components.Settings.sonarrSettingsDescription": "Stel hier onder je Sonarr connectie in. Je kan er meerdere hebben, maar slechts twee actief hebben als standaard (één voor standaard HD, en één voor 4K). Beheerders kunnen bepalen welke server gebruikt wordt voor nieuwe verzoeken.", "components.Settings.sonarrsettings": "Sonarr Instellingen", @@ -305,8 +305,12 @@ "pages.somethingWentWrong": "{statusCode} - Er is iets verkeerd gegaan", "components.MovieDetails.MovieCast.fullcast": "Volledige Cast", "components.TvDetails.TvCast.fullseriescast": "Volledige Cast van de Series", - "components.Settings.Notifications.emailsettingssaved": "E-mail notificatie instellingen zijn opgeslagen!", - "components.Settings.Notifications.emailsettingsfailed": "E-mail notificatie instellingen konden niet opgeslagen worden.", + "components.Settings.Notifications.emailsettingssaved": "Instellingen voor e-mailmeldingen opgeslagen!", + "components.Settings.Notifications.emailsettingsfailed": "Instellingen voor e-mailmeldingen zijn niet opgeslagen.", "components.Settings.Notifications.discordsettingssaved": "Discord notificatie instellingen zijn opgeslagen!", - "components.Settings.Notifications.discordsettingsfailed": "Discord notificatie instellingen konden niet opgeslagen worden." + "components.Settings.Notifications.discordsettingsfailed": "Discord notificatie instellingen konden niet opgeslagen worden.", + "components.Settings.validationPortRequired": "Je moet een poort opgeven", + "components.Settings.validationHostnameRequired": "Je moet een hostnaam/IP opgeven", + "components.Settings.SonarrModal.validationNameRequired": "Je moet een servernaam opgeven", + "components.Settings.RadarrModal.validationNameRequired": "Je moet een servernaam opgeven" } From cb8a50bd663ebf7c49768fb5f7d05759d1dfff76 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 15 Dec 2020 20:40:15 +0900 Subject: [PATCH 05/22] docs: add Shutruk as a contributor (#304) [skip ci] * docs: update README.md [skip ci] * docs: update .all-contributorsrc [skip ci] Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index fac1d1f01..a853a5d19 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -97,6 +97,15 @@ "contributions": [ "infra" ] + }, + { + "login": "Shutruk", + "name": "Shutruk", + "avatar_url": "https://avatars2.githubusercontent.com/u/9198633?v=4", + "profile": "https://github.com/Shutruk", + "contributions": [ + "translation" + ] } ], "badgeTemplate": "\"All-orange.svg\"/>", diff --git a/README.md b/README.md index 544b2cd68..2a9909576 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Language grade: JavaScript GitHub -All Contributors +All Contributors

@@ -105,6 +105,7 @@ Our [Code of Conduct](https://github.com/sct/overseerr/blob/develop/CODE_OF_COND
jvennik

🌍
darknessgp

💻
salty

🚇 +
Shutruk

🌍 From 6cd20491d2a0ceb995c4744eeb92a6e2f57a4893 Mon Sep 17 00:00:00 2001 From: sct Date: Tue, 15 Dec 2020 11:46:43 +0000 Subject: [PATCH 06/22] feat(lang): add support for Spanish language --- src/components/Layout/LanguagePicker/index.tsx | 4 ++++ src/context/LanguageContext.tsx | 3 ++- src/pages/_app.tsx | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/Layout/LanguagePicker/index.tsx b/src/components/Layout/LanguagePicker/index.tsx index a3c065449..13f66de8e 100644 --- a/src/components/Layout/LanguagePicker/index.tsx +++ b/src/components/Layout/LanguagePicker/index.tsx @@ -45,6 +45,10 @@ const availableLanguages: AvailableLanguageObject = { code: 'nl', display: 'Nederlands', }, + es: { + code: 'es', + display: 'Spanish', + }, }; const LanguagePicker: React.FC = () => { diff --git a/src/context/LanguageContext.tsx b/src/context/LanguageContext.tsx index f4f61cc4e..c493b18c1 100644 --- a/src/context/LanguageContext.tsx +++ b/src/context/LanguageContext.tsx @@ -7,7 +7,8 @@ export type AvailableLocales = | 'nb-NO' | 'de' | 'ru' - | 'nl'; + | 'nl' + | 'es'; interface LanguageContextProps { locale: AvailableLocales; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index d59d26fe0..139813c21 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -28,6 +28,8 @@ const loadLocaleData = (locale: string): Promise => { return import('../i18n/locale/ru.json'); case 'nl': return import('../i18n/locale/nl.json'); + case 'es': + return import('../i18n/locale/es.json'); default: return import('../i18n/locale/en.json'); } From 20b119c1ac4de34b911101cafa85fd41fe9073da Mon Sep 17 00:00:00 2001 From: sct Date: Tue, 15 Dec 2020 11:54:15 +0000 Subject: [PATCH 07/22] docs: update bug report issue template to include app version [skip ci] --- .github/ISSUE_TEMPLATE/bug_report.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 40ae9700e..6d369e18a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -9,8 +9,10 @@ assignees: '' **Describe the bug** A clear and concise description of what the bug is. -**Are you on latest or develop branch?** -Please fill in which docker image you are currently using. +**What version of Overseerr are you running?** +Please fill in the version you are currently running. + +You can find it under: Settings -> About -> Version **To Reproduce** Steps to reproduce the behavior: From 33f8831e880dc7fd3f69d951246cada5c6c0ffe7 Mon Sep 17 00:00:00 2001 From: sct Date: Tue, 15 Dec 2020 14:13:41 +0000 Subject: [PATCH 08/22] fix(api): accept the api key to perform actions on the api with X-API-Key header --- overseerr-api.yml | 5 +++++ server/middleware/auth.ts | 18 +++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/overseerr-api.yml b/overseerr-api.yml index 28bdcadb2..90c2bcb77 100644 --- a/overseerr-api.yml +++ b/overseerr-api.yml @@ -966,6 +966,10 @@ components: type: apiKey name: connect.sid in: cookie + apiKey: + type: apiKey + in: header + name: X-Api-Key paths: /settings/main: @@ -2485,3 +2489,4 @@ paths: security: - cookieAuth: [] + - apiKey: [] diff --git a/server/middleware/auth.ts b/server/middleware/auth.ts index 97814772b..f541c3d60 100644 --- a/server/middleware/auth.ts +++ b/server/middleware/auth.ts @@ -1,9 +1,25 @@ import { getRepository } from 'typeorm'; import { User } from '../entity/User'; import { Permission } from '../lib/permissions'; +import { getSettings } from '../lib/settings'; export const checkUser: Middleware = async (req, _res, next) => { - if (req.session?.userId) { + const settings = getSettings(); + if (req.header('X-API-Key') === settings.main.apiKey) { + const userRepository = getRepository(User); + + let userId = 1; // Work on original administrator account + + // If a User ID is provided, we will act on that users behalf + if (req.header('X-API-User')) { + userId = Number(req.header('X-API-User')); + } + const user = await userRepository.findOne({ where: { id: userId } }); + + if (user) { + req.user = user; + } + } else if (req.session?.userId) { const userRepository = getRepository(User); const user = await userRepository.findOne({ From 7fd43c95290ff7f2acdfdff237396907a1b74cce Mon Sep 17 00:00:00 2001 From: Krystian Charubin Date: Tue, 15 Dec 2020 10:42:27 -0500 Subject: [PATCH 09/22] style: dark splash screen (#310) --- public/site.webmanifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/site.webmanifest b/public/site.webmanifest index 45dc8a206..3f47bc7cb 100644 --- a/public/site.webmanifest +++ b/public/site.webmanifest @@ -1 +1 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file +{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#1e2937","display":"standalone"} From 7c08809501876a055db7a98415d912b2a26a2fcd Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 16 Dec 2020 00:43:31 +0900 Subject: [PATCH 10/22] docs: add krystiancharubin as a contributor (#311) [skip ci] * docs: update README.md [skip ci] * docs: update .all-contributorsrc [skip ci] Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index a853a5d19..a471c2f84 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -106,6 +106,15 @@ "contributions": [ "translation" ] + }, + { + "login": "krystiancharubin", + "name": "Krystian Charubin", + "avatar_url": "https://avatars2.githubusercontent.com/u/17775600?v=4", + "profile": "https://github.com/krystiancharubin", + "contributions": [ + "design" + ] } ], "badgeTemplate": "\"All-orange.svg\"/>", diff --git a/README.md b/README.md index 2a9909576..217bb9ae4 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Language grade: JavaScript GitHub -All Contributors +All Contributors

@@ -106,6 +106,7 @@ Our [Code of Conduct](https://github.com/sct/overseerr/blob/develop/CODE_OF_COND
darknessgp

💻
salty

🚇
Shutruk

🌍 +
Krystian Charubin

🎨 From e8776fd3361c6a579fba554b3b9ae8015f726f26 Mon Sep 17 00:00:00 2001 From: sct Date: Tue, 15 Dec 2020 15:49:59 +0000 Subject: [PATCH 11/22] refactor(frontend): titlecard behavior changed to allow clicking anywhere to go through to title mobile behavior remains mostly the same, except after the first click, a second click anywhere else will go through to the title. --- src/components/TitleCard/index.tsx | 296 +++++++++++++++-------------- src/context/InteractionContext.tsx | 20 ++ src/hooks/useInteraction.ts | 78 ++++++++ src/hooks/useIsTouch.ts | 7 + src/pages/_app.tsx | 15 +- 5 files changed, 267 insertions(+), 149 deletions(-) create mode 100644 src/context/InteractionContext.tsx create mode 100644 src/hooks/useInteraction.ts create mode 100644 src/hooks/useIsTouch.ts diff --git a/src/components/TitleCard/index.tsx b/src/components/TitleCard/index.tsx index 5202c1928..443f06a1b 100644 --- a/src/components/TitleCard/index.tsx +++ b/src/components/TitleCard/index.tsx @@ -10,10 +10,11 @@ import Link from 'next/link'; import { MediaStatus } from '../../../server/constants/media'; import RequestModal from '../RequestModal'; import { defineMessages, useIntl } from 'react-intl'; +import { useIsTouch } from '../../hooks/useIsTouch'; const messages = defineMessages({ - movie: 'MOVIE', - tvshow: 'SERIES', + movie: 'Movie', + tvshow: 'Series', }); interface TitleCardProps { @@ -38,6 +39,7 @@ const TitleCard: React.FC = ({ mediaType, canExpand = false, }) => { + const isTouch = useIsTouch(); const intl = useIntl(); const [isUpdating, setIsUpdating] = useState(false); const [currentStatus, setCurrentStatus] = useState(status); @@ -74,9 +76,13 @@ const TitleCard: React.FC = ({
{ + if (!isTouch) { + setShowDetail(true); + } }} - onMouseEnter={() => setShowDetail(true)} onMouseLeave={() => setShowDetail(false)} onClick={() => setShowDetail(true)} onKeyDown={(e) => { @@ -146,158 +152,162 @@ const TitleCard: React.FC = ({ -
-
-
-
{year}
+ + +
+
+
{year}
-

- {title} -

-
- {summary} +

+ {title} +

+
+ {summary} +
-
-
- - - - - - - - - {(!currentStatus || - currentStatus === MediaStatus.UNKNOWN) && ( - - )} - {currentStatus === MediaStatus.PENDING && ( - + )} + {currentStatus === MediaStatus.PENDING && ( + - )} - {currentStatus === MediaStatus.PROCESSING && ( - + )} + {currentStatus === MediaStatus.PROCESSING && ( + - )} - {(currentStatus === MediaStatus.AVAILABLE || - currentStatus === MediaStatus.PARTIALLY_AVAILABLE) && ( - + )} + {(currentStatus === MediaStatus.AVAILABLE || + currentStatus === MediaStatus.PARTIALLY_AVAILABLE) && ( + - )} + + + + + )} +
-
-
+ +
diff --git a/src/context/InteractionContext.tsx b/src/context/InteractionContext.tsx new file mode 100644 index 000000000..0a78cdac1 --- /dev/null +++ b/src/context/InteractionContext.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import useInteraction from '../hooks/useInteraction'; + +interface InteractionContextProps { + isTouch: boolean; +} + +export const InteractionContext = React.createContext({ + isTouch: false, +}); + +export const InteractionProvider: React.FC = ({ children }) => { + const isTouch = useInteraction(); + + return ( + + {children} + + ); +}; diff --git a/src/hooks/useInteraction.ts b/src/hooks/useInteraction.ts new file mode 100644 index 000000000..61d4f99fc --- /dev/null +++ b/src/hooks/useInteraction.ts @@ -0,0 +1,78 @@ +import { useState, useEffect } from 'react'; + +export const INTERACTION_TYPE = { + MOUSE: 'mouse', + PEN: 'pen', + TOUCH: 'touch', +}; + +const UPDATE_INTERVAL = 1000; // Throttle updates to the type to prevent flip flopping + +const useInteraction = (): boolean => { + const [isTouch, setIsTouch] = useState(false); + + useEffect(() => { + const hasTapEvent = 'ontouchstart' in window; + setIsTouch(hasTapEvent); + + let localTouch = hasTapEvent; + let lastTouchUpdate = Date.now(); + + const shouldUpdate = (): boolean => + lastTouchUpdate + UPDATE_INTERVAL < Date.now(); + + const onMouseMove = (): void => { + if (localTouch && shouldUpdate()) { + setTimeout(() => { + if (shouldUpdate()) { + setIsTouch(false); + localTouch = false; + } + }, UPDATE_INTERVAL); + } + }; + + const onTouchStart = (): void => { + lastTouchUpdate = Date.now(); + + if (!localTouch) { + setIsTouch(true); + localTouch = true; + } + }; + + const onPointerMove = (e: PointerEvent): void => { + const { pointerType } = e; + + switch (pointerType) { + case INTERACTION_TYPE.TOUCH: + case INTERACTION_TYPE.PEN: + return onTouchStart(); + default: + return onMouseMove(); + } + }; + + if (hasTapEvent) { + window.addEventListener('mousemove', onMouseMove); + window.addEventListener('touchstart', onTouchStart); + } else { + window.addEventListener('pointerdown', onPointerMove); + window.addEventListener('pointermove', onPointerMove); + } + + return () => { + if (hasTapEvent) { + window.removeEventListener('mousemove', onMouseMove); + window.removeEventListener('touchstart', onTouchStart); + } else { + window.removeEventListener('pointerdown', onPointerMove); + window.removeEventListener('pointermove', onPointerMove); + } + }; + }, []); + + return isTouch; +}; + +export default useInteraction; diff --git a/src/hooks/useIsTouch.ts b/src/hooks/useIsTouch.ts new file mode 100644 index 000000000..2f5ac9831 --- /dev/null +++ b/src/hooks/useIsTouch.ts @@ -0,0 +1,7 @@ +import { useContext } from 'react'; +import { InteractionContext } from '../context/InteractionContext'; + +export const useIsTouch = (): boolean => { + const { isTouch } = useContext(InteractionContext); + return isTouch; +}; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 139813c21..53d15d7c4 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -12,6 +12,7 @@ import { IntlProvider } from 'react-intl'; import { LanguageContext, AvailableLocales } from '../context/LanguageContext'; import Head from 'next/head'; import Toast from '../components/Toast'; +import { InteractionProvider } from '../context/InteractionContext'; // eslint-disable-next-line @typescript-eslint/no-explicit-any const loadLocaleData = (locale: string): Promise => { @@ -90,12 +91,14 @@ const CoreApp: Omit = ({ defaultLocale="en" messages={loadedMessages} > - - - Overseerr - - {component} - + + + + Overseerr + + {component} + + From 961d1107208069a6fc820a1ba97ffda7336677cb Mon Sep 17 00:00:00 2001 From: Kieron Boswell Date: Wed, 16 Dec 2020 00:28:09 +0000 Subject: [PATCH 12/22] fix: spelling mistake on the word 'requested' fixed (#319) --- server/lib/notifications/agents/email.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/lib/notifications/agents/email.ts b/server/lib/notifications/agents/email.ts index 050c98e70..6ba96f608 100644 --- a/server/lib/notifications/agents/email.ts +++ b/server/lib/notifications/agents/email.ts @@ -135,7 +135,7 @@ class EmailAgent implements NotificationAgent { to: payload.notifyUser.email, }, locals: { - body: 'Your requsested media is now available!', + body: 'Your requested media is now available!', mediaName: payload.subject, imageUrl: payload.image, timestamp: new Date().toTimeString(), From c545ec16e711c181cf8461e047128620ba3b4ebd Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 16 Dec 2020 09:29:17 +0900 Subject: [PATCH 13/22] docs: add kieron as a contributor (#329) [skip ci] * docs: update README.md [skip ci] * docs: update .all-contributorsrc [skip ci] Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index a471c2f84..31a4cc63b 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -115,6 +115,15 @@ "contributions": [ "design" ] + }, + { + "login": "kieron", + "name": "Kieron Boswell", + "avatar_url": "https://avatars2.githubusercontent.com/u/8655212?v=4", + "profile": "https://github.com/kieron", + "contributions": [ + "code" + ] } ], "badgeTemplate": "\"All-orange.svg\"/>", diff --git a/README.md b/README.md index 217bb9ae4..fbc1c971b 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Language grade: JavaScript GitHub -All Contributors +All Contributors

@@ -107,6 +107,7 @@ Our [Code of Conduct](https://github.com/sct/overseerr/blob/develop/CODE_OF_COND
salty

🚇
Shutruk

🌍
Krystian Charubin

🎨 +
Kieron Boswell

💻 From db0a5c44f678e76eee7f5582381016306d1f46a2 Mon Sep 17 00:00:00 2001 From: Brandon Cohen Date: Tue, 15 Dec 2020 19:44:58 -0500 Subject: [PATCH 14/22] fix(frontend): aligned movie and tv details (#331) --- src/components/MovieDetails/index.tsx | 6 +++--- src/components/TvDetails/index.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/MovieDetails/index.tsx b/src/components/MovieDetails/index.tsx index 57e4779db..df99de949 100644 --- a/src/components/MovieDetails/index.tsx +++ b/src/components/MovieDetails/index.tsx @@ -193,14 +193,14 @@ const MovieDetails: React.FC = ({ movie }) => { )}
-
+
-
+
{data.mediaInfo?.status === MediaStatus.AVAILABLE && ( @@ -352,7 +352,7 @@ const MovieDetails: React.FC = ({ movie }) => { {hasPermission(Permission.MANAGE_REQUESTS) && (
- diff --git a/src/components/Settings/SettingsLogs/index.tsx b/src/components/Settings/SettingsLogs/index.tsx new file mode 100644 index 000000000..9c6d9cf79 --- /dev/null +++ b/src/components/Settings/SettingsLogs/index.tsx @@ -0,0 +1,17 @@ +import React from 'react'; + +// We will localize this file when the complete version is released. + +const SettingsLogs: React.FC = () => { + return ( + <> +
+ Logs page is still being built. For now, you can access your logs + directly in stdout (container logs) or looking in{' '} + /app/config/logs/overseerr.logs +
+ + ); +}; + +export default SettingsLogs; diff --git a/src/pages/settings/logs.tsx b/src/pages/settings/logs.tsx new file mode 100644 index 000000000..2b50be3ac --- /dev/null +++ b/src/pages/settings/logs.tsx @@ -0,0 +1,14 @@ +import { NextPage } from 'next'; +import React from 'react'; +import SettingsLayout from '../../components/Settings/SettingsLayout'; +import SettingsLogs from '../../components/Settings/SettingsLogs'; + +const SettingsLogsPage: NextPage = () => { + return ( + + + + ); +}; + +export default SettingsLogsPage; diff --git a/src/styles/globals.css b/src/styles/globals.css index 0bbdb4881..18c2b0ff0 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -47,3 +47,7 @@ body { -ms-overflow-style: none; /* IE and Edge */ scrollbar-width: none; /* Firefox */ } + +code { + @apply bg-gray-800 py-1 px-2 rounded-md; +} From 6d7907e844a909993d185759d660632f55aeaa35 Mon Sep 17 00:00:00 2001 From: Brandon Cohen Date: Tue, 15 Dec 2020 20:58:41 -0500 Subject: [PATCH 16/22] fix(frontend): close sidebar when clicking outside (#333) --- src/components/Layout/Sidebar/index.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/Layout/Sidebar/index.tsx b/src/components/Layout/Sidebar/index.tsx index b5de5f2e8..b6e44f37d 100644 --- a/src/components/Layout/Sidebar/index.tsx +++ b/src/components/Layout/Sidebar/index.tsx @@ -1,9 +1,10 @@ -import React, { ReactNode } from 'react'; +import React, { ReactNode, useRef } from 'react'; import Transition from '../../Transition'; import Link from 'next/link'; import { useRouter } from 'next/router'; import { defineMessages, FormattedMessage } from 'react-intl'; import { useUser, Permission } from '../../../hooks/useUser'; +import useClickOutside from '../../../hooks/useClickOutside'; const messages = defineMessages({ dashboard: 'Discover', @@ -116,8 +117,10 @@ const SidebarLinks: SidebarLinkProps[] = [ ]; const Sidebar: React.FC = ({ open, setClosed }) => { + const navRef = useRef(null); const router = useRouter(); const { hasPermission } = useUser(); + useClickOutside(navRef, () => setClosed()); return ( <>
@@ -166,7 +169,10 @@ const Sidebar: React.FC = ({ open, setClosed }) => {
-
+
From 92a874e36d326949d17a01d101394030a8f52251 Mon Sep 17 00:00:00 2001 From: sct Date: Wed, 16 Dec 2020 02:07:49 +0000 Subject: [PATCH 17/22] docs: update readme.md with emoji key for contributors --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fbc1c971b..6c52d0153 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,13 @@ If you would like to chat with community members you can join the [Overseerr Dis Our [Code of Conduct](https://github.com/sct/overseerr/blob/develop/CODE_OF_CONDUCT.md) applies to all Overseerr community channels. -## Contributors +## Contributing + +You can help build Overseerr too! Check out our [Contribution Guide](https://github.com/sct/overseerr/blob/develop/CONTRIBUTING.md) to get started. + +## Contributors ✨ + +Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): @@ -113,8 +119,5 @@ Our [Code of Conduct](https://github.com/sct/overseerr/blob/develop/CODE_OF_COND - - -## Contributing -You can help build Overseerr too! Check out our [Contribution Guide](https://github.com/sct/overseerr/blob/develop/CONTRIBUTING.md) to get started. + From df4ac8361f82971ee845f3be217408a9123a0bf3 Mon Sep 17 00:00:00 2001 From: sct Date: Wed, 16 Dec 2020 02:35:15 +0000 Subject: [PATCH 18/22] fix(frontend): adds a tip to plex setup to clarify that syncing runs in the background fixes #325 --- src/components/Setup/index.tsx | 10 ++++++++++ src/i18n/locale/en.json | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/components/Setup/index.tsx b/src/components/Setup/index.tsx index d4cacd43f..7fc0b2d6a 100644 --- a/src/components/Setup/index.tsx +++ b/src/components/Setup/index.tsx @@ -8,6 +8,7 @@ import LoginWithPlex from './LoginWithPlex'; import SetupSteps from './SetupSteps'; import axios from 'axios'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; +import Badge from '../Common/Badge'; const messages = defineMessages({ finish: 'Finish Setup', @@ -16,6 +17,9 @@ const messages = defineMessages({ loginwithplex: 'Login with Plex', configureplex: 'Configure Plex', configureservices: 'Configure Services', + tip: 'Tip', + syncingbackground: + 'Syncing will run in the background. You can continue the setup process in the meantime.', }); const Setup: React.FC = () => { @@ -85,6 +89,12 @@ const Setup: React.FC = () => { {currentStep === 2 && (
setPlexSettingsComplete(true)} /> +
+ + {intl.formatMessage(messages.tip)} + + {intl.formatMessage(messages.syncingbackground)} +
diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json index f598cae48..8b1b27e39 100644 --- a/src/i18n/locale/en.json +++ b/src/i18n/locale/en.json @@ -236,6 +236,8 @@ "components.Setup.finishing": "Finishing...", "components.Setup.loginwithplex": "Login with Plex", "components.Setup.signinMessage": "Get started by logging in with your Plex account", + "components.Setup.syncingbackground": "Syncing will run in the background. You can continue the setup process in the meantime.", + "components.Setup.tip": "Tip", "components.Setup.welcome": "Welcome to Overseerr", "components.Slider.noresults": "No Results", "components.TitleCard.movie": "Movie", From 2948f9360eb484d1d6c0740a840135ca97e7240a Mon Sep 17 00:00:00 2001 From: sct Date: Wed, 16 Dec 2020 03:54:32 +0000 Subject: [PATCH 19/22] feat: add version to startup logs --- server/index.ts | 4 +++- server/routes/settings.ts | 11 ++--------- server/utils/appVersion.ts | 12 ++++++++++++ 3 files changed, 17 insertions(+), 10 deletions(-) create mode 100644 server/utils/appVersion.ts diff --git a/server/index.ts b/server/index.ts index 6c469371e..657c2bfeb 100644 --- a/server/index.ts +++ b/server/index.ts @@ -17,9 +17,11 @@ import { startJobs } from './job/schedule'; import notificationManager from './lib/notifications'; import DiscordAgent from './lib/notifications/agents/discord'; import EmailAgent from './lib/notifications/agents/email'; +import { getAppVersion } from './utils/appVersion'; const API_SPEC_PATH = path.join(__dirname, '../overseerr-api.yml'); +logger.info(`Starting Overseerr version ${getAppVersion()}`); const dev = process.env.NODE_ENV !== 'production'; const app = next({ dev }); const handle = app.getRequestHandler(); @@ -101,7 +103,7 @@ app const port = Number(process.env.PORT) || 3000; server.listen(port, () => { logger.info(`Server ready on port ${port}`, { - label: 'SERVER', + label: 'Server', }); }); }) diff --git a/server/routes/settings.ts b/server/routes/settings.ts index b278652c4..8feeefd4d 100644 --- a/server/routes/settings.ts +++ b/server/routes/settings.ts @@ -19,6 +19,7 @@ import { isAuthenticated } from '../middleware/auth'; import { merge } from 'lodash'; import Media from '../entity/Media'; import { MediaRequest } from '../entity/MediaRequest'; +import { getAppVersion } from '../utils/appVersion'; const settingsRoutes = Router(); @@ -445,16 +446,8 @@ settingsRoutes.get('/about', async (req, res) => { const totalMediaItems = await mediaRepository.count(); const totalRequests = await mediaRequestRepository.count(); - // eslint-disable-next-line @typescript-eslint/no-var-requires - const { version } = require('../../package.json'); - - let finalVersion = version; - - if (version === '0.1.0') { - finalVersion = `develop-${process.env.COMMIT_TAG ?? 'local'}`; - } return res.status(200).json({ - version: finalVersion, + version: getAppVersion(), totalMediaItems, totalRequests, }); diff --git a/server/utils/appVersion.ts b/server/utils/appVersion.ts new file mode 100644 index 000000000..ef9f35c3b --- /dev/null +++ b/server/utils/appVersion.ts @@ -0,0 +1,12 @@ +export const getAppVersion = (): string => { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const { version } = require('../../package.json'); + + let finalVersion = version; + + if (version === '0.1.0') { + finalVersion = `develop-${process.env.COMMIT_TAG ?? 'local'}`; + } + + return finalVersion; +}; From f8f388db6de69eb6ffece21fc8fc63f75af0bb37 Mon Sep 17 00:00:00 2001 From: sct Date: Wed, 16 Dec 2020 03:57:03 +0000 Subject: [PATCH 20/22] refactor(api): add better error context when plex items fail to sync --- server/job/plexsync/index.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/server/job/plexsync/index.ts b/server/job/plexsync/index.ts index d64e5898d..87e078d40 100644 --- a/server/job/plexsync/index.ts +++ b/server/job/plexsync/index.ts @@ -246,7 +246,11 @@ class JobPlexSync { plexitem.parentRatingKey ?? plexitem.ratingKey }`, - 'error' + 'error', + { + errorMessage: e.message, + plexitem, + } ); } } @@ -293,9 +297,10 @@ class JobPlexSync { private log( message: string, - level: 'info' | 'error' | 'debug' = 'debug' + level: 'info' | 'error' | 'debug' = 'debug', + optional?: Record ): void { - logger[level](message, { label: 'Plex Sync' }); + logger[level](message, { label: 'Plex Sync', ...optional }); } public async run(): Promise { From 675060bcdf23acbfd4de2900a65f95e74f4966a5 Mon Sep 17 00:00:00 2001 From: sct Date: Wed, 16 Dec 2020 04:07:59 +0000 Subject: [PATCH 21/22] fix(api): set plex libraries to disabled if the name changes re #324 --- server/routes/settings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/routes/settings.ts b/server/routes/settings.ts index 8feeefd4d..25a702b07 100644 --- a/server/routes/settings.ts +++ b/server/routes/settings.ts @@ -101,7 +101,7 @@ settingsRoutes.get('/plex/library', async (req, res) => { .filter((library) => library.agent !== 'com.plexapp.agents.none') .map((library) => { const existing = settings.plex.libraries.find( - (l) => l.id === library.key + (l) => l.id === library.key && l.name === library.title ); return { From ae2ede89529342048c47310a72d7b1653504693e Mon Sep 17 00:00:00 2001 From: samwiseg0 <2241731+samwiseg0@users.noreply.github.com> Date: Tue, 15 Dec 2020 23:56:52 -0500 Subject: [PATCH 22/22] docs: add invalid template workflow (#340) --- .github/workflows/invalid_template.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/invalid_template.yml diff --git a/.github/workflows/invalid_template.yml b/.github/workflows/invalid_template.yml new file mode 100644 index 000000000..c98d3174b --- /dev/null +++ b/.github/workflows/invalid_template.yml @@ -0,0 +1,19 @@ +name: 'Invalid Template' + +on: + issues: + types: [labeled, unlabeled, reopened] + +jobs: + support: + runs-on: ubuntu-latest + steps: + - uses: dessant/support-requests@v2 + with: + github-token: ${{ github.token }} + support-label: 'invalid:template-incomplete' + issue-comment: > + :wave: @{issue-author}, please edit your issue and follow the template provided. + close-issue: false + lock-issue: true + issue-lock-reason: 'resolved'