Skip to content

[Bug] [Regression]: Playback stops and video returns to beginning when going back to a playing browser tab #219

Description

@arcoast

What happened?

I've tested this with Chromium, Vivaldi and Firefox all on a Fedora 44 KDE install.

I'm seeing the same behaviour exhibited by my previous report of this here

Exhibited with a completely fresh install of v1.5.1

Steps to reproduce

  1. Open a browser
  2. Login to TypeType
  3. Play a video
  4. Open a new tab and browse Amazon, eBay, Reddit
  5. Video will continue to play as one would expect
  6. Return to TypeType tab
  7. Video stops playing and returns to the beginning.

Area

Frontend (web app)

Channel

main (stable)

Anything else?

My compose.yml

networks:
    typetype:
        external: false
        name: typetype

services:
    typetype:
        image: ghcr.io/typetype-video/typetype:latest
        container_name: typetype
        networks:
            traefik:
            typetype:
        # ports:
        #     - 8082:80
        depends_on:
            typetype-server:
                condition: service_healthy
        healthcheck:
            test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1/api/version/web"]
            interval: 5s
            timeout: 3s
            retries: 12
        restart: unless-stopped
        labels:
            traefik.enable: "true"
            traefik.docker.network: "traefik"
            traefik.http.services.typetype.loadbalancer.server.port: "80"
            traefik.http.routers.typetype.service: "typetype"
            traefik.http.routers.typetype.entrypoints: "websecure"
            traefik.http.routers.typetype.rule: "Host(`typetype.${DOMAIN}`)"
            traefik.http.routers.typetype.middlewares: ${MIDDLEWARE}

    typetype-server:
        image: ghcr.io/typetype-video/typetype-server:latest
        container_name: typetype-server
        networks:
            typetype:
        # ports:
        #     - 8080:8080
        environment:
            ALLOWED_ORIGINS: ${ALLOWED_ORIGINS}
            DATABASE_URL: ${DATABASE_URL}
            DATABASE_USER: ${DATABASE_USER}
            DATABASE_PASSWORD: ${DATABASE_PASSWORD}
            DRAGONFLY_URL: ${DRAGONFLY_URL}
            GITHUB_REPO: ${GITHUB_REPO}
            GITHUB_ISSUE_TEMPLATE: ${GITHUB_ISSUE_TEMPLATE}
            DOWNLOADER_SERVICE_URL: ${DOWNLOADER_SERVICE_URL}
            AUTH_SESSION_TTL_DAYS: ${AUTH_SESSION_TTL_DAYS}
            AUTH_ALLOW_INSECURE_COOKIES: ${AUTH_ALLOW_INSECURE_COOKIES}
            YOUTUBE_OUTBOUND_PROXY_URL: ${YOUTUBE_OUTBOUND_PROXY_URL}
            YOUTUBE_REMOTE_LOGIN_ENABLED: ${YOUTUBE_REMOTE_LOGIN_ENABLED}
            YOUTUBE_REMOTE_LOGIN_SERVICE_URL: ${YOUTUBE_REMOTE_LOGIN_SERVICE_URL}
            YOUTUBE_REMOTE_LOGIN_CALLBACK_BASE_URL: ${YOUTUBE_REMOTE_LOGIN_CALLBACK_BASE_URL}
            # YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN: ${YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN}
            YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN_FILE: ${YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN_FILE}
            # YOUTUBE_SESSION_ENCRYPTION_KEY: ${YOUTUBE_SESSION_ENCRYPTION_KEY}
            YOUTUBE_SESSION_ENCRYPTION_KEY_FILE: ${YOUTUBE_SESSION_ENCRYPTION_KEY_FILE}
            YOUTUBE_REMOTE_LOGIN_TTL_MS: ${YOUTUBE_REMOTE_LOGIN_TTL_MS}
            YOUTUBE_REMOTE_LOGIN_MAX_SESSIONS: ${YOUTUBE_REMOTE_LOGIN_MAX_SESSIONS}
            YOUTUBE_REMOTE_LOGIN_MAX_FRAME_BYTES: ${YOUTUBE_REMOTE_LOGIN_MAX_FRAME_BYTES}
            OIDC_PROVIDER_NAME: ${OIDC_PROVIDER_NAME}
            OIDC_ISSUER: ${OIDC_ISSUER}
            OIDC_CLIENT_ID: ${OIDC_CLIENT_ID}
            OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET}
            OIDC_SCOPES: ${OIDC_SCOPES}
            OIDC_DISCOVERY_URL: ${OIDC_DISCOVERY_URL}
        volumes:
            - ${CONFIG}/typetype/typetype-secrets:/run/typetype-secrets:ro
        depends_on:
            typetype-downloader:
                condition: service_started
            typetype-dragonfly:
                condition: service_started
            typetype-postgres-init:
                condition: service_completed_successfully
            typetype-secrets:
                condition: service_completed_successfully
            typetype-token:
                condition: service_started
        healthcheck:
            test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1:8080/health"]
        restart: unless-stopped

    typetype-secrets:
        image: busybox:1.38
        container_name: typetype-secrets
        networks:
            typetype:
        command:
            - /bin/sh
            - -ec
            - |
                generate_secret() {
                dd if=/dev/urandom bs=48 count=1 2>/dev/null | base64 | tr '+/' '-_' | tr -d '=\n'
                }
                ensure_secret() {
                file="$$1"
                value="$$2"
                placeholder="$$3"
                legacy_placeholder="$$4"
                if [ -n "$$value" ] && [ "$$value" != "$$placeholder" ] && [ "$$value" != "$$legacy_placeholder" ]; then
                    printf '%s' "$$value" > "$$file"
                elif [ ! -s "$$file" ]; then
                    generate_secret > "$$file"
                fi
                chmod 0444 "$$file"
                }
                mkdir -p /run/typetype-secrets
                ensure_secret /run/typetype-secrets/youtube_remote_login_internal_token "$$YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN" SET_ME_YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN SET_ME_SHARED_SECRET
                ensure_secret /run/typetype-secrets/youtube_session_encryption_key "$$YOUTUBE_SESSION_ENCRYPTION_KEY" SET_ME_YOUTUBE_SESSION_ENCRYPTION_KEY SET_ME_SHARED_SECRET
        # environment:
        #     YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN: ${YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN}
        #     YOUTUBE_SESSION_ENCRYPTION_KEY: ${YOUTUBE_SESSION_ENCRYPTION_KEY}
        volumes:
            - ${CONFIG}/typetype/typetype-secrets:/run/typetype-secrets
        restart: no

    typetype-downloader:
        image: ghcr.io/typetype-video/typetype-downloader:latest
        container_name: typetype-downloader
        networks:
            typetype:
        # ports:
        #     - 18093:18093
        environment:
            HTTP_PORT: ${HTTP_PORT}
            PUBLIC_BASE_URL: ${PUBLIC_BASE_URL}
            TYPETYPE_API_BASE: ${TYPETYPE_API_BASE}
            DB_URL: ${DB_URL}
            # DB_USER: ${POSTGRES_USER}
            # DB_PASSWORD: ${POSTGRES_PASSWORD}
            REDIS_HOST: ${REDIS_HOST}
            REDIS_PORT: ${REDIS_PORT}
            REDIS_QUEUE_KEY: ${REDIS_QUEUE_KEY}
            MAX_CONCURRENT_WORKERS: ${MAX_CONCURRENT_WORKERS}
            MAX_QUEUE_SIZE: ${MAX_QUEUE_SIZE}
            JOB_TTL_SECONDS: ${JOB_TTL_SECONDS}
            DOWNLOAD_WORKERS: ${DOWNLOAD_WORKERS}
            DOWNLOAD_CHUNK_SIZE: ${DOWNLOAD_CHUNK_SIZE}
            DOWNLOAD_RANGE_MODE: ${DOWNLOAD_RANGE_MODE}
            MUXER: ${MUXER}
            STORAGE_BACKEND: ${STORAGE_BACKEND}
            S3_ENDPOINT: ${S3_ENDPOINT}
            S3_PUBLIC_ENDPOINT: ${S3_PUBLIC_ENDPOINT}
            S3_REGION: ${S3_REGION}
            S3_BUCKET: ${S3_BUCKET}
            S3_ACCESS_KEY: ${S3_ACCESS_KEY}
            S3_SECRET_KEY: ${S3_SECRET_KEY}
            S3_ARTIFACT_TTL_SECONDS: ${S3_ARTIFACT_TTL_SECONDS}
        depends_on:
            typetype-postgres-init:
                condition: service_completed_successfully
            typetype-dragonfly:
                condition: service_started
            typetype-garage:
                condition: service_started
            typetype-token:
                condition: service_started
        restart: unless-stopped

    typetype-token:
        image: ghcr.io/typetype-video/typetype-token:latest
        container_name: typetype-token
        networks:
            typetype:
        # ports:
        #     - 8081:8081
        init: true
        ipc: host
        environment:
            NODE_ENV: production
            YOUTUBE_OUTBOUND_PROXY_URL: ${YOUTUBE_OUTBOUND_PROXY_URL}
            YOUTUBE_REMOTE_LOGIN_ENABLED: ${YOUTUBE_REMOTE_LOGIN_ENABLED}
            # YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN: ${YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN}
            YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN_FILE: ${YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN_FILE}
            YOUTUBE_REMOTE_LOGIN_CALLBACK_ORIGIN: ${YOUTUBE_REMOTE_LOGIN_CALLBACK_ORIGIN}
            YOUTUBE_REMOTE_LOGIN_MAX_SESSIONS: ${YOUTUBE_REMOTE_LOGIN_MAX_SESSIONS}
            YOUTUBE_REMOTE_LOGIN_FRAME_FPS: ${YOUTUBE_REMOTE_LOGIN_FRAME_FPS}
            YOUTUBE_REMOTE_LOGIN_MAX_FRAME_BYTES: ${YOUTUBE_REMOTE_LOGIN_MAX_FRAME_BYTES}
        volumes:
            - ${CONFIG}/typetype/typetype-secrets:/run/typetype-secrets:ro
        depends_on:
            typetype-secrets:
                condition: service_completed_successfully
        healthcheck:
            test: ["CMD-SHELL", "curl --fail --silent http://127.0.0.1:8081/health > /dev/null"]
        restart: unless-stopped

    typetype-postgres:
        image: postgres:17
        container_name: typetype-postgres
        networks:
            typetype:
        # ports:
        #     - 5432:5432
        environment:
            POSTGRES_DB: ${POSTGRES_DB}
            POSTGRES_USER: ${POSTGRES_USER}
            POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
        volumes:
            - ${CONFIG}/typetype/typetype-postgres:/var/lib/postgresql/data
        healthcheck:
            test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
            interval: 5s
            retries: 30
        restart: unless-stopped

    typetype-postgres-init:
        image: postgres:17
        container_name: typetype-postgres-init
        networks:
            typetype:
        # ports:
        #     - 5432:5432
        depends_on:
            typetype-postgres:
                condition: service_started
        environment:
            POSTGRES_CONTAINER: ${POSTGRES_CONTAINER}
            POSTGRES_DB: ${POSTGRES_DB}
            POSTGRES_USER: ${POSTGRES_USER}
            PGPASSWORD: ${POSTGRES_PASSWORD}
        command:
            - /bin/sh
            - -ec
            - |
                until pg_isready -h ${POSTGRES_CONTAINER} -U ${POSTGRES_USER} -d ${POSTGRES_DB}; do sleep 1; done
                EXISTS=$$(psql -h ${POSTGRES_CONTAINER} -U $${POSTGRES_USER} -d $${POSTGRES_DB} -tAc "SELECT 1 FROM pg_database WHERE datname='typetype_downloader'")
                if [ "$$EXISTS" != "1" ]; then
                    psql -h ${POSTGRES_CONTAINER} -U $${POSTGRES_USER} -d $${POSTGRES_DB} -c "CREATE DATABASE typetype_downloader"
                fi
        restart: no

    typetype-dragonfly:
        image: docker.dragonflydb.io/dragonflydb/dragonfly:v1.39.0
        container_name: typetype-dragonfly
        networks:
            typetype:
        # ports:
        #     - 6379:6379
        ulimits:
            memlock: -1
        healthcheck:
            test: ["CMD", "redis-cli", "ping"]
        restart: unless-stopped

    typetype-garage:
        image: dxflrs/garage:v2.2.0
        container_name: typetype-garage
        networks:
            traefik:
            typetype:
        # ports:
        #     - 3900:3900
        environment:
            GARAGE_CONFIG_FILE: ${GARAGE_CONFIG_FILE}
            GARAGE_RPC_SECRET: ${GARAGE_RPC_SECRET}
        volumes:
            - ${CONFIG}/typetype/typetype-garage/config:/etc/garage:ro
            - ${CONFIG}/typetype/typetype-garage/meta:/var/lib/garage/meta
            - ${CONFIG}/typetype/typetype-garage/data:/var/lib/garage/data
        depends_on:
            typetype-garage-config:
                condition: service_completed_successfully
        healthcheck:
            test: ["CMD", "/garage", "status"]
            interval: 5s
            timeout: 3s
            retries: 12
        restart: unless-stopped
        labels:
            traefik.enable: "true"
            traefik.docker.network: "traefik"
            traefik.http.services.typetype-garage.loadbalancer.server.port: "3900"
            traefik.http.routers.typetype-garage.service: "typetype-garage"
            traefik.http.routers.typetype-garage.entrypoints: "websecure"
            traefik.http.routers.typetype-garage.rule: "Host(`typetype-garage.${DOMAIN}`)"
            traefik.http.routers.typetype-garage.middlewares: ${MIDDLEWARE}

    typetype-garage-config:
        image: busybox:1.38
        container_name: typetype-garage-config
        networks:
            typetype:
        command:
            - /bin/sh
            - -ec
            - |
                config=/etc/garage/garage.toml
                if [ -s "$$config" ]; then
                    exit 0
                fi
                umask 077
                if [ -s /migration/garage.toml ]; then
                    cp /migration/garage.toml "$$config"
                    exit 0
                fi
                cat > "$$config" <<'EOF'
                metadata_dir = "/var/lib/garage/meta"
                data_dir = "/var/lib/garage/data"
                db_engine = "sqlite"

                replication_factor = 1

                rpc_bind_addr = "[::]:3901"
                rpc_public_addr = "127.0.0.1:3901"

                [s3_api]
                s3_region = "garage"
                api_bind_addr = "[::]:3900"
                EOF
        volumes:
            - ${CONFIG}/typetype/typetype-garage/config:/etc/garage
            # - ${CONFIG}/typetype/typetype-garage-migration:/migration:ro # Not needed as fresh install.
        restart: no

My .env

All secrets/passwords I've regenerated, so no worries about credential exposure.

# typetype-postgres
POSTGRES_CONTAINER=typetype-postgres
POSTGRES_DB=typetype
POSTGRES_USER=typetype
POSTGRES_PASSWORD=Sanctity-Lego-Preshow5

# typetype-server
ALLOWED_ORIGINS=https://typetype.${DOMAIN} #,http://localhost:8082,http://127.0.0.1:8082,http://localhost:5173,http://127.0.0.1:5173,
DATABASE_URL=jdbc:postgresql://${POSTGRES_CONTAINER}:5432/${POSTGRES_DB}
DATABASE_USER=${POSTGRES_USER}
DATABASE_PASSWORD=${POSTGRES_PASSWORD}
DRAGONFLY_URL=redis://typetype-dragonfly:6379
GITHUB_REPO=Priveetee/TypeType-Server
GITHUB_ISSUE_TEMPLATE=bug_report_backend.md
DOWNLOADER_SERVICE_URL=http://typetype-downloader:18093
AUTH_SESSION_TTL_DAYS=30
AUTH_ALLOW_INSECURE_COOKIES=false
YOUTUBE_REMOTE_LOGIN_SERVICE_URL=http://typetype-token:8081
YOUTUBE_REMOTE_LOGIN_CALLBACK_BASE_URL=http://typetype-server:8080
# YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN=
YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN_FILE=/run/typetype-secrets/youtube_remote_login_internal_token
# YOUTUBE_SESSION_ENCRYPTION_KEY=
YOUTUBE_SESSION_ENCRYPTION_KEY_FILE=/run/typetype-secrets/youtube_session_encryption_key
YOUTUBE_REMOTE_LOGIN_TTL_MS=480000
YOUTUBE_REMOTE_LOGIN_MAX_SESSIONS=2
YOUTUBE_REMOTE_LOGIN_MAX_FRAME_BYTES=524288

# OIDC - Pocket ID
OIDC_ISSUER=https://pocket-id.${DOMAIN}
OIDC_CLIENT_ID=d2f653e1-65a3-412c-a5a3-253390ebf49d
OIDC_CLIENT_SECRET=gtlIocwYkXNmKhV2yTONLAFXeO6c7p3g
OIDC_SCOPES="openid email profile"
OIDC_PROVIDER_NAME="Pocket ID"
OIDC_DISCOVERY_URL=https://pocket-id.${DOMAIN}/.well-known/openid-configuration 

# # OIDC - Authelia
# OIDC_ISSUER=https://authelia.${DOMAIN}
# OIDC_CLIENT_ID=9ef93e4d37300cc2ba82a4121e4641513b8468065a4dd13aa05af821c420356860513558
# OIDC_CLIENT_SECRET=jpwFR5GXX2uy_Exsud1~ZZWnYct2WCNOGSAKwZagyehMvbf3m5m.gWU.EGp1wBcGTChctbGG
# OIDC_SCOPES="openid email profile"
# OIDC_PROVIDER_NAME="Authelia"
# OIDC_DISCOVERY_URL=https://authelia.${DOMAIN}/.well-known/openid-configuration


# typetype-downloader
HTTP_PORT="18093"
PUBLIC_BASE_URL=/api/downloader
TYPETYPE_API_BASE=http://typetype-server:8080
DB_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_CONTAINER}:5432/typetype_downloader?sslmode=disable
REDIS_HOST=typetype-dragonfly
REDIS_PORT="6379"
REDIS_QUEUE_KEY=downloader:queue
MAX_CONCURRENT_WORKERS="2"
MAX_QUEUE_SIZE="100"
JOB_TTL_SECONDS="600"
DOWNLOAD_WORKERS="8"
DOWNLOAD_CHUNK_SIZE="10485760"
DOWNLOAD_RANGE_MODE=query
MUXER=avformat
STORAGE_BACKEND=s3
S3_ENDPOINT=http://typetype-garage:3900
# S3_PUBLIC_ENDPOINT=http://typetype-garage:3900
S3_PUBLIC_ENDPOINT=https://typetype-garage.${DOMAIN}
S3_REGION=garage
S3_BUCKET=typetype-downloads
# Generate with S3_ACCESS_KEY=GK$(openssl rand -hex 12) && echo $S3_ACCESS_KEY
S3_ACCESS_KEY=GK82b350b995e678cae0733612
# Generate with S3_SECRET_KEY=$(openssl rand -hex 32) && echo $S3_SECRET_KEY
S3_SECRET_KEY=dff4999861527b504110116b6b48e8465b0a34ea5f9c43d86ba563d2062841f4
S3_ARTIFACT_TTL_SECONDS="7200"

# typetype-token
NODE_ENV=production
YOUTUBE_OUTBOUND_PROXY_URL=
YOUTUBE_REMOTE_LOGIN_ENABLED=true
# YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN=
YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN_FILE=/run/typetype-secrets/youtube_remote_login_internal_token
YOUTUBE_REMOTE_LOGIN_CALLBACK_ORIGIN=http://typetype-server:8080
YOUTUBE_REMOTE_LOGIN_MAX_SESSIONS=2
YOUTUBE_REMOTE_LOGIN_FRAME_FPS=10
YOUTUBE_REMOTE_LOGIN_MAX_FRAME_BYTES=524288

# typetype-garage
GARAGE_CONFIG_FILE=/etc/garage/garage.toml
# Generate with openssl rand -hex 32
GARAGE_RPC_SECRET=f5d35e2f3a7c904612eb35a4777a185352c8786c6b788b449f2e0b06a43f774a

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions