--- # Source: tautulli/charts/tautulli/templates/common.yaml apiVersion: v1 kind: ConfigMap metadata: name: tautulli labels: app.kubernetes.io/instance: tautulli app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: tautulli helm.sh/chart: tautulli-4.4.0 namespace: tautulli data: select_tmdb_poster.py: | #!/usr/bin/env python # -*- coding: utf-8 -*- ''' Description: Selects the default TMDB poster if no poster is selected or the current poster is from Gracenote. Author: /u/SwiftPanda16 Requires: plexapi Usage: * Change the posters for an entire library: python select_tmdb_poster.py --library "Movies" * Change the poster for a specific item: python select_tmdb_poster.py --rating_key 1234 * By default locked posters are skipped. To update locked posters: python select_tmdb_poster.py --library "Movies" --include_locked Tautulli script trigger: * Notify on recently added Tautulli script conditions: * Filter which media to select the poster. Examples: [ Media Type | is | movie ] Tautulli script arguments: * Recently Added: --rating_key {rating_key} ''' import argparse import os import plexapi.base from plexapi.server import PlexServer plexapi.base.USER_DONT_RELOAD_FOR_KEYS.add('fields') # Environmental Variables PLEX_URL = os.getenv('PLEX_URL') PLEX_TOKEN = os.getenv('PLEX_TOKEN') def select_tmdb_poster_library(library, include_locked=False): for item in library.all(includeGuids=False): # Only reload for fields item.reload(**{k: 0 for k, v in item._INCLUDES.items()}) select_tmdb_poster_item(item, include_locked=include_locked) def select_tmdb_poster_item(item, include_locked=False): if item.isLocked('thumb') and not include_locked: # PlexAPI 4.5.10 print(f"Locked poster for {item.title}. Skipping.") return posters = item.posters() selected_poster = next((p for p in posters if p.selected), None) if selected_poster is None: print(f"WARNING: No poster selected for {item.title}.") else: skipping = ' Skipping.' if selected_poster.provider != 'gracenote' else '' print(f"Poster provider is '{selected_poster.provider}' for {item.title}.{skipping}") if posters and (selected_poster is None or selected_poster.provider == 'gracenote'): # Fallback to first poster if no TMDB posters are available tmdb_poster = next((p for p in posters if p.provider == 'tmdb'), posters[0]) # Selecting the poster automatically locks it tmdb_poster.select() print(f"Selected {tmdb_poster.provider} poster for {item.title}.") if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--rating_key', type=int) parser.add_argument('--library') parser.add_argument('--include_locked', action='store_true') opts = parser.parse_args() plex = PlexServer(PLEX_URL, PLEX_TOKEN) if opts.rating_key: item = plex.fetchItem(opts.rating_key) select_tmdb_poster_item(item, opts.include_locked) elif opts.library: library = plex.library.section(opts.library) select_tmdb_poster_library(library, opts.include_locked) else: print("No --rating_key or --library specified. Exiting.") --- # Source: tautulli/charts/tautulli/templates/common.yaml --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: tautulli-config labels: app.kubernetes.io/instance: tautulli app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: tautulli helm.sh/chart: tautulli-4.4.0 annotations: helm.sh/resource-policy: keep namespace: tautulli spec: accessModes: - "ReadWriteOnce" resources: requests: storage: "5Gi" storageClassName: "ceph-block" --- # Source: tautulli/charts/tautulli/templates/common.yaml apiVersion: v1 kind: Service metadata: name: tautulli labels: app.kubernetes.io/instance: tautulli app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: tautulli app.kubernetes.io/service: tautulli helm.sh/chart: tautulli-4.4.0 namespace: tautulli spec: type: ClusterIP ports: - port: 80 targetPort: 8181 protocol: TCP name: http selector: app.kubernetes.io/controller: main app.kubernetes.io/instance: tautulli app.kubernetes.io/name: tautulli --- # Source: tautulli/charts/tautulli/templates/common.yaml apiVersion: apps/v1 kind: Deployment metadata: name: tautulli labels: app.kubernetes.io/controller: main app.kubernetes.io/instance: tautulli app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: tautulli helm.sh/chart: tautulli-4.4.0 annotations: reloader.stakater.com/auto: "true" namespace: tautulli spec: revisionHistoryLimit: 3 replicas: 1 strategy: type: Recreate selector: matchLabels: app.kubernetes.io/controller: main app.kubernetes.io/name: tautulli app.kubernetes.io/instance: tautulli template: metadata: annotations: checksum/configMaps: 8f779aaa6f9bccc9e07f526b05d4f9d81e7e55a443819d526312ff297ac88ba5 labels: app.kubernetes.io/controller: main app.kubernetes.io/instance: tautulli app.kubernetes.io/name: tautulli spec: enableServiceLinks: false serviceAccountName: default automountServiceAccountToken: true hostIPC: false hostNetwork: false hostPID: false dnsPolicy: ClusterFirst containers: - env: - name: PUID value: "1001" - name: GUID value: "1001" - name: TZ value: US/Central image: ghcr.io/tautulli/tautulli:v2.16.0 imagePullPolicy: IfNotPresent name: main resources: requests: cpu: 10m memory: 128Mi volumeMounts: - mountPath: /config name: config - mountPath: /config/scripts/select_tmdb_poster.py mountPropagation: None name: scripts readOnly: true subPath: select_tmdb_poster.py volumes: - name: config persistentVolumeClaim: claimName: tautulli-config - configMap: name: tautulli-scripts name: scripts --- # Source: tautulli/templates/external-secret.yaml apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: tautulli-config-backup-secret namespace: tautulli labels: app.kubernetes.io/name: tautulli-config-backup-secret app.kubernetes.io/instance: tautulli app.kubernetes.io/part-of: tautulli spec: secretStoreRef: kind: ClusterSecretStore name: vault target: template: mergePolicy: Merge engineVersion: v2 data: RESTIC_REPOSITORY: "{{ .BUCKET_ENDPOINT }}/tautulli/tautulli-config" data: - secretKey: BUCKET_ENDPOINT remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/volsync/restic/config metadataPolicy: None property: S3_BUCKET_ENDPOINT - secretKey: RESTIC_PASSWORD remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/volsync/restic/config metadataPolicy: None property: RESTIC_PASSWORD - secretKey: AWS_DEFAULT_REGION remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/volsync/restic/config metadataPolicy: None property: AWS_DEFAULT_REGION - secretKey: AWS_ACCESS_KEY_ID remoteRef: conversionStrategy: Default decodingStrategy: None key: /digital-ocean/home-infra/volsync-backups metadataPolicy: None property: access_key - secretKey: AWS_SECRET_ACCESS_KEY remoteRef: conversionStrategy: Default decodingStrategy: None key: /digital-ocean/home-infra/volsync-backups metadataPolicy: None property: secret_key --- # Source: tautulli/templates/http-route.yaml apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: http-route-tautulli namespace: tautulli labels: app.kubernetes.io/name: http-route-tautulli app.kubernetes.io/instance: tautulli app.kubernetes.io/part-of: tautulli spec: parentRefs: - group: gateway.networking.k8s.io kind: Gateway name: traefik-gateway namespace: traefik hostnames: - tautulli.alexlebens.net rules: - matches: - path: type: PathPrefix value: / backendRefs: - group: '' kind: Service name: tautulli port: 80 weight: 100 --- # Source: tautulli/templates/replication-source.yaml apiVersion: volsync.backube/v1alpha1 kind: ReplicationSource metadata: name: tautulli-config-backup-source namespace: tautulli labels: app.kubernetes.io/name: tautulli-config-backup-source app.kubernetes.io/instance: tautulli app.kubernetes.io/part-of: tautulli spec: sourcePVC: tautulli-config trigger: schedule: 0 4 * * * restic: pruneIntervalDays: 7 repository: tautulli-config-backup-secret retain: hourly: 1 daily: 3 weekly: 2 monthly: 2 yearly: 4 copyMethod: Snapshot storageClassName: ceph-block volumeSnapshotClassName: ceph-blockpool-snapshot