Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"Bash(npx svelte-check *)",
"Bash(npm install *)",
"Bash(npx tsc *)",
"Bash(docker compose *)"
"Bash(docker compose *)",
"Bash(npx prisma *)",
"Bash(npm run *)"
]
}
}
3 changes: 2 additions & 1 deletion .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ env:

jobs:
build:
if: github.repository == 'willuhmjs/wytui'
runs-on: ${{ matrix.runner }}
strategy:
matrix:
Expand Down Expand Up @@ -77,7 +78,7 @@ jobs:

merge:
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
if: github.repository == 'willuhmjs/wytui' && github.event_name != 'pull_request'
needs: build
permissions:
contents: read
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/helm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ env:

jobs:
helm:
if: github.repository == 'willuhmjs/wytui'
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ concurrency:

jobs:
deploy:
if: github.repository == 'willuhmjs/wytui'
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,6 @@ extension-artifacts/
wytui-extension-*.zip

extension/.amo-upload-uuid

# Qwen tooling artifacts
.qwen/
15 changes: 12 additions & 3 deletions charts/wytui/templates/config/secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,23 @@ stringData:
{{- end }}
---
{{- if and .Values.oidc.enabled (not .Values.oidc.secret.existing) }}
{{- $oidcClientId := .Values.oidc.secret.clientId -}}
{{- $oidcClientSecret := .Values.oidc.secret.clientSecret -}}
{{- $oidcIssuer := .Values.oidc.secret.issuer -}}
{{- $existingOidc := (lookup "v1" "Secret" .Release.Namespace .Values.oidc.secret.name) -}}
{{- if $existingOidc -}}
{{- if not $oidcClientId -}}{{- $oidcClientId = index $existingOidc.data .Values.oidc.secret.clientIdKey | default "" | b64dec -}}{{- end -}}
{{- if not $oidcClientSecret -}}{{- $oidcClientSecret = index $existingOidc.data .Values.oidc.secret.clientSecretKey | default "" | b64dec -}}{{- end -}}
{{- if not $oidcIssuer -}}{{- $oidcIssuer = index $existingOidc.data .Values.oidc.secret.issuerKey | default "" | b64dec -}}{{- end -}}
{{- end -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.oidc.secret.name }}
namespace: {{ .Release.Namespace }}
type: Opaque
stringData:
{{ .Values.oidc.secret.clientIdKey }}: {{ .Values.oidc.secret.clientId | quote }}
{{ .Values.oidc.secret.clientSecretKey }}: {{ .Values.oidc.secret.clientSecret | quote }}
{{ .Values.oidc.secret.issuerKey }}: {{ .Values.oidc.secret.issuer | quote }}
{{ .Values.oidc.secret.clientIdKey }}: {{ $oidcClientId | quote }}
{{ .Values.oidc.secret.clientSecretKey }}: {{ $oidcClientSecret | quote }}
{{ .Values.oidc.secret.issuerKey }}: {{ $oidcIssuer | quote }}
{{- end }}
35 changes: 33 additions & 2 deletions docker-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,29 @@ set -e

ENV_FILE=".env"

# Ensure KEY exists with a non-empty value in $ENV_FILE.
# Appends the key if missing, fills it in if present but empty.
# $1 = key name, $2 = value to use when the key is missing/empty
ensure_var() {
local key="$1"
local value="$2"

# Already set with a non-empty value -> leave it alone
if grep -qE "^${key}=.+" "$ENV_FILE" 2>/dev/null; then
return
fi

if grep -qE "^${key}=" "$ENV_FILE" 2>/dev/null; then
# Present but empty -> fill in the value
sed -i.bak "s|^${key}=.*|${key}=${value}|" "$ENV_FILE" && rm -f "$ENV_FILE.bak"
echo " • Set empty ${key}"
else
# Missing entirely -> append it
printf '%s=%s\n' "$key" "$value" >> "$ENV_FILE"
echo " • Added missing ${key}"
fi
}

# Check if .env exists
if [ ! -f "$ENV_FILE" ]; then
echo "📝 No .env file found. Generating secure credentials..."
Expand Down Expand Up @@ -38,10 +61,18 @@ EOF
echo ""
else
echo "✅ Using existing $ENV_FILE"

# An existing .env may predate Docker support (e.g. a dev file with only
# DATABASE_URL). Ensure the variables docker-compose.yml requires are present.
echo "🔧 Ensuring Docker Compose credentials are set..."
ensure_var POSTGRES_USER postgres
ensure_var POSTGRES_PASSWORD "$(openssl rand -hex 32)"
ensure_var POSTGRES_DB wytui
ensure_var AUTH_SECRET "$(openssl rand -hex 32)"
fi

# Check if credentials are set
if grep -q "POSTGRES_PASSWORD=$" "$ENV_FILE" 2>/dev/null || grep -q "AUTH_SECRET=$" "$ENV_FILE" 2>/dev/null; then
# Final safety net: refuse to start with empty required credentials
if grep -qE "^POSTGRES_PASSWORD=$" "$ENV_FILE" 2>/dev/null || grep -qE "^AUTH_SECRET=$" "$ENV_FILE" 2>/dev/null; then
echo "⚠️ WARNING: Empty credentials detected in $ENV_FILE"
echo " Please set POSTGRES_PASSWORD and AUTH_SECRET"
exit 1
Expand Down
181 changes: 181 additions & 0 deletions src/lib/components/download/SubscriptionConfig.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
<script lang="ts">
import type { DownloadProfile } from "$lib/types";

let {
profiles = [],
selectedProfileId = "",
saveToLibrary = false,
options = { sponsorblock: false, subtitles: false, metadata: false },
libraryConfigured = false,
onChange,
}: {
profiles?: DownloadProfile[];
selectedProfileId?: string;
saveToLibrary?: boolean;
options?: {
sponsorblock: boolean;
subtitles: boolean;
metadata: boolean;
};
libraryConfigured?: boolean;
onChange?: (updates: {
profileId?: string;
saveToLibrary?: boolean;
options?: {
sponsorblock: boolean;
subtitles: boolean;
metadata: boolean;
};
}) => void;
} = $props();

function toggleOption(key: keyof typeof options) {
const newOptions = { ...options, [key]: !options[key] };
onChange?.({ options: newOptions });
}

function updateSaveToLibrary(value: boolean) {
onChange?.({ saveToLibrary: value });
if (value && libraryConfigured) {
onChange?.({
options: {
sponsorblock: true,
subtitles: true,
metadata: true,
},
});
}
}

function updateProfileId(value: string) {
onChange?.({ profileId: value });
}
</script>

<div class="subscription-config">
<div class="form-group">
<label for="sub-profile"
>Download Profile <span
class="required-asterisk"
aria-label="required">*</span
></label
>
<select
id="sub-profile"
value={selectedProfileId}
onchange={(e) =>
updateProfileId((e.target as HTMLSelectElement).value)}
required
>
{#each profiles as profile}
<option value={profile.id}>{profile.name}</option>
{/each}
</select>
</div>

{#if libraryConfigured}
<div class="form-group">
<label class="toggle-label">
<input
type="checkbox"
checked={saveToLibrary}
onchange={(e) =>
updateSaveToLibrary(
(e.target as HTMLInputElement).checked,
)}
/>
Save to Library
</label>
<p class="help-text">
Automatically save downloads to your library (requires library
path configured)
</p>
</div>
{/if}

<div class="form-group">
<span class="options-label">Options</span>
<div class="options-chips">
<button
type="button"
class="option-chip"
class:active={options.sponsorblock}
onclick={() => toggleOption("sponsorblock")}
>
SponsorBlock
</button>
<button
type="button"
class="option-chip"
class:active={options.subtitles}
onclick={() => toggleOption("subtitles")}
>
Subtitles
</button>
<button
type="button"
class="option-chip"
class:active={options.metadata}
onclick={() => toggleOption("metadata")}
>
Metadata
</button>
</div>
<p class="help-text">
Additional download options to apply to all videos from this
subscription
</p>
</div>
</div>

<style>
.subscription-config {
display: flex;
flex-direction: column;
gap: var(--spacing-md);
}

.subscription-config .form-group {
margin-bottom: 0;
}

.required-asterisk {
color: var(--color-status-error);
font-weight: var(--font-weight-bold);
margin-left: var(--spacing-xs);
}

.options-label {
display: block;
font-weight: var(--font-weight-semibold);
margin-bottom: var(--spacing-xs);
}

.options-chips {
display: flex;
gap: var(--spacing-sm);
flex-wrap: wrap;
}

.option-chip {
background: var(--color-bg-secondary);
border: 1px solid var(--color-border-default);
border-radius: var(--radius-sm);
padding: var(--spacing-xs) var(--spacing-sm);
font-size: var(--font-size-xs);
font-weight: var(--font-weight-medium);
color: var(--color-text-secondary);
cursor: pointer;
transition: all var(--transition-fast);
}

.option-chip:hover {
border-color: var(--color-border-translucent-hover);
}

.option-chip.active {
background: var(--color-accent-primary);
border-color: var(--color-accent-primary);
color: var(--color-text-on-accent);
}
</style>
7 changes: 3 additions & 4 deletions src/lib/components/ui/Sidebar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
<!-- Desktop sidebar -->
<aside class="sidebar" class:collapsed>
<div class="sidebar-header">
<a href="/" class="logo">
<a href="/" class="logo" title="wytui (W-Y-T-U-I)">
{#if !collapsed}
<div class="logo-row">
<h1>wytui</h1>
Expand All @@ -96,9 +96,8 @@
</a>
<button class="collapse-btn" onclick={() => collapsed = !collapsed} title={collapsed ? 'Expand sidebar' : 'Collapse sidebar'}>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M2 4h12" />
<path d="M2 8h12" />
<path d="M2 12h12" />
<rect x="2" y="3" width="12" height="10" rx="1.5" />
<path d="M6 3v10" />
</svg>
</button>
</div>
Expand Down
Loading
Loading