Add StartOS 0.4.0 packaging

This commit is contained in:
MacPro
2026-04-09 15:03:31 -05:00
commit 68ec875ee7
2057 changed files with 490924 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
import { sdk } from '../sdk'
import { updateYtdlp } from './updateYtdlp'
export const actions = sdk.Actions.of().addAction(updateYtdlp)
+50
View File
@@ -0,0 +1,50 @@
import { i18n } from '../i18n'
import { sdk } from '../sdk'
export const updateYtdlp = sdk.Action.withoutInput(
'update-ytdlp',
async ({ effects }) => ({
name: i18n('Update yt-dlp'),
description: i18n(
'Downloads the latest version of yt-dlp. Run this if YouTube downloads are failing — YouTube frequently changes its systems, requiring yt-dlp updates.',
),
warning: i18n('This may take a minute. The service will continue running.'),
allowedStatuses: 'any',
group: null,
visibility: 'enabled' as const,
}),
async ({ effects }) => {
// Run pip upgrade inside the running subcontainer
const sub = await sdk.SubContainer.of(
effects,
{ imageId: 'main' },
sdk.Mounts.of().mountVolume({
volumeId: 'main',
subpath: null,
mountpoint: '/data',
readonly: false,
}),
'ytdlp-update-sub',
)
const result = await sub.exec(['sh', '-c',
'pip3 install --break-system-packages -U yt-dlp curl_cffi 2>&1; echo "---"; echo "yt-dlp version: $(yt-dlp --version)"',
])
const output = result.stdout || 'Update completed'
return {
version: '1' as const,
title: 'yt-dlp Update',
message: output,
result: {
type: 'single' as const,
name: 'Output',
value: output,
masked: false,
copyable: true,
qr: false,
},
}
},
)
+5
View File
@@ -0,0 +1,5 @@
import { sdk } from './sdk'
export const { createBackup, restoreInit } = sdk.setupBackups(
async ({ effects }) => sdk.Backups.ofVolumes('main'),
)
+6
View File
@@ -0,0 +1,6 @@
import { sdk } from './sdk'
// YouTube Summarizer has no dependencies on other StartOS services.
export const dependencies = sdk.setupDependencies(async ({ effects }) => {
return {}
})
+25
View File
@@ -0,0 +1,25 @@
export const DEFAULT_LANG = 'en_US'
const dict = {
// main.ts
'Starting YouTube Summarizer...': 0,
'Web Interface': 1,
'YouTube Summarizer is ready': 2,
'YouTube Summarizer is not responding': 3,
// interfaces.ts
'Web UI': 4,
'The web interface for YouTube Summarizer — browse, search, and manage your transcript library': 5,
// actions/updateYtdlp.ts
'Update yt-dlp': 6,
'Downloads the latest version of yt-dlp. Run this if YouTube downloads are failing — YouTube frequently changes its systems, requiring yt-dlp updates.': 7,
'This may take a minute. The service will continue running.': 8,
} as const
/**
* Plumbing. DO NOT EDIT.
*/
export type I18nKey = keyof typeof dict
export type LangDict = Record<(typeof dict)[I18nKey], string>
export default dict
@@ -0,0 +1,4 @@
import { LangDict } from './default'
// English-only for now. Add translations here as needed.
export default {} satisfies Record<string, LangDict>
+8
View File
@@ -0,0 +1,8 @@
/**
* Plumbing. DO NOT EDIT this file.
*/
import { setupI18n } from '@start9labs/start-sdk'
import defaultDict, { DEFAULT_LANG } from './dictionaries/default'
import translations from './dictionaries/translations'
export const i18n = setupI18n(defaultDict, translations, DEFAULT_LANG)
+11
View File
@@ -0,0 +1,11 @@
/**
* Plumbing. DO NOT EDIT.
*/
export { createBackup } from './backups'
export { main } from './main'
export { init, uninit } from './init'
export { actions } from './actions'
import { buildManifest } from '@start9labs/start-sdk'
import { manifest as sdkManifest } from './manifest'
import { versionGraph } from './versions'
export const manifest = buildManifest(versionGraph, sdkManifest)
+11
View File
@@ -0,0 +1,11 @@
import { sdk } from './sdk'
// init runs on install, update, restore, and container rebuild.
// For YouTube Summarizer, no special initialization is needed —
// the entrypoint script handles directory creation and config loading.
export const { init, uninit } = sdk.setupInit(
async ({ effects, kind }) => {
// Nothing to do — directories are created by docker_entrypoint.sh
// and config is loaded from the persistent volume.
},
)
+27
View File
@@ -0,0 +1,27 @@
import { i18n } from './i18n'
import { sdk } from './sdk'
import { uiPort } from './utils'
export const setInterfaces = sdk.setupInterfaces(async ({ effects }) => {
const uiMulti = sdk.MultiHost.of(effects, 'ui-multi')
const uiMultiOrigin = await uiMulti.bindPort(uiPort, {
protocol: 'http',
})
const ui = sdk.createInterface(effects, {
name: i18n('Web UI'),
id: 'ui',
description: i18n(
'The web interface for YouTube Summarizer — browse, search, and manage your transcript library',
),
type: 'ui',
masked: false,
schemeOverride: null,
username: null,
path: '',
query: {},
})
const uiReceipt = await uiMultiOrigin.export([ui])
return [uiReceipt]
})
+37
View File
@@ -0,0 +1,37 @@
import { i18n } from './i18n'
import { sdk } from './sdk'
import { uiPort } from './utils'
export const main = sdk.setupMain(async ({ effects }) => {
console.info(i18n('Starting YouTube Summarizer...'))
return sdk.Daemons.of(effects).addDaemon('primary', {
subcontainer: await sdk.SubContainer.of(
effects,
{ imageId: 'main' },
sdk.Mounts.of().mountVolume({
volumeId: 'main',
subpath: null,
mountpoint: '/data',
readonly: false,
}),
'youtube-summarizer-sub',
),
exec: {
command: [
'dumb-init',
'--',
'/usr/local/bin/docker_entrypoint.sh',
],
},
ready: {
display: i18n('Web Interface'),
fn: () =>
sdk.healthCheck.checkPortListening(effects, uiPort, {
successMessage: i18n('YouTube Summarizer is ready'),
errorMessage: i18n('YouTube Summarizer is not responding'),
}),
},
requires: [],
})
})
+21
View File
@@ -0,0 +1,21 @@
export const short = {
en_US:
'Download, transcribe, and summarize YouTube videos and podcasts with AI.',
}
export const long = {
en_US:
'YouTube Summarizer downloads audio from YouTube videos and podcast RSS feeds, ' +
'transcribes them using Google Gemini, and produces structured topic-by-topic ' +
'summaries with timestamps. Features include channel and podcast subscriptions ' +
'with automatic new episode detection, a background processing queue with ' +
'configurable delays, auto-download per subscription, organized history with ' +
'folders, multiple AI model support, and a responsive web interface. ' +
'Requires a Google Gemini API key (free tier available at aistudio.google.com/apikey).',
}
export const alertInstall = {
en_US:
'After installing, open the web UI and enter your Google Gemini API key in Settings. ' +
'For reliable YouTube downloads, set up OAuth2 authentication in Settings > YouTube Authentication.',
}
+37
View File
@@ -0,0 +1,37 @@
import { setupManifest } from '@start9labs/start-sdk'
import { alertInstall, long, short } from './i18n'
export const manifest = setupManifest({
id: 'youtube-summarizer',
title: 'YouTube Summarizer',
license: 'Proprietary',
packageRepo: 'https://github.com/user/youtube-summarizer-startos',
upstreamRepo: 'https://github.com/user/youtube-summarizer',
marketingUrl: 'https://github.com/user/youtube-summarizer',
donationUrl: null,
docsUrls: [
'https://github.com/user/youtube-summarizer/blob/main/README.md',
],
description: { short, long },
volumes: ['main'],
images: {
main: {
source: {
dockerBuild: {
workdir: '.',
dockerfile: './Dockerfile',
},
},
arch: ['x86_64', 'aarch64'],
},
},
alerts: {
install: alertInstall,
update: null,
uninstall: null,
restore: null,
start: null,
stop: null,
},
dependencies: {},
})
+9
View File
@@ -0,0 +1,9 @@
import { StartSdk } from '@start9labs/start-sdk'
import { manifest } from './manifest'
/**
* Plumbing. DO NOT EDIT.
*
* The exported "sdk" const is used throughout this package codebase.
*/
export const sdk = StartSdk.of().withManifest(manifest).build(true)
+2
View File
@@ -0,0 +1,2 @@
// Shared constants used across the package codebase
export const uiPort = 3001
+7
View File
@@ -0,0 +1,7 @@
import { VersionGraph } from '@start9labs/start-sdk'
import { v_0_1_0 } from './v0.1.0'
export const versionGraph = VersionGraph.of({
current: v_0_1_0,
other: [],
})
+16
View File
@@ -0,0 +1,16 @@
import { VersionInfo } from '@start9labs/start-sdk'
export const v_0_1_0 = VersionInfo.of({
version: '0.1.0:0',
releaseNotes: {
en_US:
'Initial StartOS package. Download, transcribe, and summarize YouTube videos ' +
'and podcast episodes using Google Gemini AI. Features include channel and ' +
'podcast subscriptions, background processing queue, auto-download per ' +
'subscription, and organized history with folders.',
},
migrations: {
up: async ({ effects }) => {},
down: 'IMPOSSIBLE',
},
})