Merge pull request #1828 from chme/feat/devcontainer

dev: Add template for VSCode settings and devcontainers
This commit is contained in:
Christian Meffert 2025-01-18 10:34:22 +01:00 committed by GitHub
commit 11fc7d3962
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 1195 additions and 9 deletions

245
.clang-format Normal file
View File

@ -0,0 +1,245 @@
---
Language: Cpp
AccessModifierOffset: -2
AlignAfterOpenBracket: DontAlign
AlignArrayOfStructures: Left
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseColons: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowBreakBeforeNoexceptSpecifier: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: All
AlwaysBreakAfterReturnType: All
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: Always
AfterEnum: false
AfterExternBlock: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: false
AfterUnion: true
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: true
IndentBraces: true
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakArrays: true
BreakBeforeBinaryOperators: All
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Custom
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
KeepEmptyLinesAtEOF: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
PPIndentWidth: -1
QualifierAlignment: Leave
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: false
AfterForeachMacros: false
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: false
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: c++03
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseTab: ForIndentation
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
...

7
.dev/Makefile Normal file
View File

@ -0,0 +1,7 @@
.PHONY: vscode
vscode:
mkdir -p ../.vscode
cp -rT ./vscode ../.vscode
mkdir -p ../.devcontainer
cp -rT ./devcontainer ../.devcontainer

View File

@ -0,0 +1,20 @@
#!/usr/bin/env sh
# cd aliases
alias ..='cd ..'
alias ...='cd ../..'
alias -- -='cd -'
# bat aliases
alias bat='batcat'
if [ "$ENABLE_ESA" = "1" ]; then
if [ "$(command -v eza)" ]; then
alias l='eza -la --icons=auto --group-directories-first'
alias la='eza -la --icons=auto --group-directories-first'
alias ll='eza -l --icons=auto --group-directories-first'
alias l.='eza -d .*'
alias ls='eza'
alias l1='eza -1'
fi
fi

View File

@ -0,0 +1,30 @@
#!/bin/sh
# Install mkdocs with mkdocs-material theme
pipx install --include-deps mkdocs-material
pipx inject mkdocs-material mkdocs-minify-plugin
# Starfish (https://starship.rs/) - shell prompt
if [ "$ENABLE_STARSHIP" = "1" ]
then
curl -sS https://starship.rs/install.sh | sh -s -- -y
echo 'eval "$(starship init bash)"' >> ~/.bashrc
fi
# Atuin (https://atuin.sh/) - shell history
if [ "$ENABLE_ATUIN" = "1" ]
then
curl --proto '=https' --tlsv1.2 -LsSf https://setup.atuin.sh | sh
curl https://raw.githubusercontent.com/rcaloras/bash-preexec/master/bash-preexec.sh -o ~/.bash-preexec.sh
fi
# zoxide (https://github.com/ajeetdsouza/zoxide) - replacement for cd
if [ "$ENABLE_ZOXIDE" = "1" ]
then
curl -sSfL https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh
echo 'eval "$(zoxide init bash)"' >> ~/.bashrc
fi
pipx install harlequin
pipx install toolong
pipx install posting

View File

@ -0,0 +1,479 @@
# A quick guide to configuring OwnTone:
#
# For regular use, the most important setting to configure is "directories",
# which should be the location of your media. Whatever user you have set as
# "uid" must have read access to this location. If the location is a network
# mount, please see the README.
#
# In all likelihood, that's all you need to do!
general {
# Username
# Make sure the user has read access to the library directories you set
# below, and full access to the databases, log and local audio
uid = "vscode"
# Database location
db_path = "/data/cache/songs3.db"
# Database backup location
# Uncomment and specify a full path to enable abilty to use REST endpoint
# to initiate backup of songs3.db
# db_backup_path = "/usr/local/var/cache/owntone/songs3.bak"
# Log file and level
# Available levels: fatal, log, warning, info, debug, spam
logfile = "/data/logs/owntone.log"
loglevel = debug
# Admin password for the web interface
# Note that access to the web interface from computers in
# "trusted_network" (see below) does not require password
# admin_password = ""
# Websocket port for the web interface.
# websocket_port = 0
# Websocket interface to bind listener to (e.g. "eth0"). Default is
# disabled, which means listen on all interfaces.
# websocket_interface = ""
# Sets who is allowed to connect without authorisation. This applies to
# client types like Remotes, DAAP clients (iTunes) and to the web
# interface. Options are "any", "localhost" or the prefix to one or
# more ipv4/6 networks. The default is { "localhost", "192.168", "fd" }
# trusted_networks = { "localhost", "192.168", "fd" }
# Enable/disable IPv6
# ipv6 = no
# Set this if you want the server to bind to a specific IP address. Can
# be ipv6 or ipv4. Default (commented out or "::") is to listen on all
# IP addresses.
# bind_address = "::"
# Location of cache database
cache_path = "/data/cache/cache.db"
# DAAP requests that take longer than this threshold (in msec) get their
# replies cached for next time. Set to 0 to disable caching.
# cache_daap_threshold = 1000
# When starting playback, autoselect speaker (if none of the previously
# selected speakers/outputs are available)
# speaker_autoselect = no
# Most modern systems have a high-resolution clock, but if you are on an
# unusual platform and experience audio drop-outs, you can try changing
# this option
# high_resolution_clock = yes
}
# Library configuration
library {
# Name of the library as displayed by the clients (%h: hostname). If you
# change the name after pairing with Remote you may have to re-pair.
name = "My Music on %h"
# TCP port to listen on. Default port is 3689 (daap)
port = 3689
# Password for the library. Optional.
# password = ""
# Directories to index
directories = { "/data/music" }
# Follow symlinks. Default: true.
# follow_symlinks = true
# Directories containing podcasts
# For each directory that is indexed the path is matched against these
# names. If there is a match all items in the directory are marked as
# podcasts. Eg. if you index /srv/music, and your podcasts are in
# /srv/music/Podcasts, you can set this to "/Podcasts".
# (changing this setting only takes effect after rescan, see the README)
podcasts = { "/Podcasts" }
# Directories containing audiobooks
# For each directory that is indexed the path is matched against these
# names. If there is a match all items in the directory are marked as
# audiobooks.
# (changing this setting only takes effect after rescan, see the README)
audiobooks = { "/Audiobooks" }
# Directories containing compilations (eg soundtracks)
# For each directory that is indexed the path is matched against these
# names. If there is a match all items in the directory are marked as
# compilations.
# (changing this setting only takes effect after rescan, see the README)
compilations = { "/Compilations" }
# Compilations usually have many artists, and sometimes no album artist.
# If you don't want every artist to be listed in artist views, you can
# set a single name which will be used for all compilation tracks
# without an album artist, and for all tracks in the compilation
# directories.
# (changing this setting only takes effect after rescan, see the README)
compilation_artist = "Various Artists"
# If your album and artist lists are cluttered, you can choose to hide
# albums and artists with only one track. The tracks will still be
# visible in other lists, e.g. songs and playlists. This setting
# currently only works in some remotes.
# hide_singles = false
# Internet streams in your playlists will by default be shown in the
# "Radio" library, like iTunes does. However, some clients (like
# TunesRemote+) won't show the "Radio" library. If you would also like
# to have them shown like normal playlists, you can enable this option.
# radio_playlists = false
# These are the default playlists. If you want them to have other names,
# you can set it here.
# name_library = "Library"
# name_music = "Music"
# name_movies = "Movies"
# name_tvshows = "TV Shows"
# name_podcasts = "Podcasts"
# name_audiobooks = "Audiobooks"
# name_radio = "Radio"
# Artwork file names (without file type extension)
# OwnTone will look for jpg and png files with these base names
# artwork_basenames = { "artwork", "cover", "Folder" }
# Enable searching for artwork corresponding to each individual media
# file instead of only looking for album artwork. This is disabled by
# default to reduce cache size.
# artwork_individual = false
# File types the scanner should ignore
# Non-audio files will never be added to the database, but here you
# can prevent the scanner from even probing them. This might improve
# scan time. By default .db, .ini, .db-journal, .pdf and .metadata are
# ignored.
# filetypes_ignore = { ".db", ".ini", ".db-journal", ".pdf", ".metadata" }
# File paths the scanner should ignore
# If you want to exclude files on a more advanced basis you can enter
# one or more POSIX regular expressions, and any file with a matching
# path will be ignored.
# filepath_ignore = { "myregex" }
# Disable startup file scanning
# When OwnTone starts it will do an initial file scan of your
# library (and then watch it for changes). If you are sure your library
# never changes while OwnTone is not running, you can disable the
# initial file scan and save some system ressources. Disabling this scan
# may lead to OwnTone's database coming out of sync with the
# library. If that happens read the instructions in the README on how
# to trigger a rescan.
# filescan_disable = false
# Only use the first genre found in metadata
# Some tracks have multiple genres semicolon-separated in the same tag,
# e.g. 'Pop;Rock'. If you don't want them listed like this, you can
# enable this option and only the first genre will be used (i.e. 'Pop').
# only_first_genre = false
# Should metadata from m3u playlists, e.g. artist and title in EXTINF,
# override the metadata we get from radio streams?
# m3u_overrides = false
# Should iTunes metadata override ours?
# itunes_overrides = false
# Should we import the content of iTunes smart playlists?
# itunes_smartpl = false
# Decoding options for DAAP and RSP clients
# Since iTunes has native support for mpeg, mp4a, mp4v, alac and wav,
# such files will be sent as they are. Any other formats will be decoded
# to raw wav. If OwnTone detects a non-iTunes DAAP client, it is
# assumed to only support mpeg and wav, other formats will be decoded.
# Here you can change when to decode. Note that these settings only
# affect serving media to DAAP and RSP clients, they have no effect on
# direct AirPlay, Chromecast and local audio playback.
# Formats: mp4a, mp4v, mpeg, alac, flac, mpc, ogg, wma, wmal, wmav, aif, wav
# Formats that should never be decoded
# no_decode = { "format", "format" }
# Formats that should always be decoded
# force_decode = { "format", "format" }
# Set ffmpeg filters (similar to 'ffmpeg -af xxx') that you want the
# server to use when decoding files from your library. Examples:
# { 'volume=replaygain=track' } -> use REPLAYGAIN_TRACK_GAIN metadata
# { 'loudnorm=I=-16:LRA=11:TP=-1.5' } -> normalize volume
# decode_audio_filters = { }
# Watch named pipes in the library for data and autostart playback when
# there is data to be read. To exclude specific pipes from watching,
# consider using the above _ignore options.
# pipe_autostart = true
# Enable automatic rating updates
# If enabled, rating is automatically updated after a song has either been
# played or skipped (only skipping to the next song is taken into account).
# The calculation is taken from the beets plugin "mpdstats" (see
# https://beets.readthedocs.io/en/latest/plugins/mpdstats.html).
# It consist of calculating a stable rating based only on the play- and
# skipcount and a rolling rating based on the current rating and the action
# (played or skipped). Both results are combined with a mix-factor of 0.75:
# new rating = 0.75 * stable rating + 0.25 * rolling rating)
# rating_updates = false
# By default, ratings are only saved in the server's database. Enable
# the below to make the server also read ratings from file metadata and
# write on update (requires write access). To avoid excessive writing to
# the library, automatic rating updates are not written, even with the
# write_rating option enabled.
# read_rating = false
# write_rating = false
# The scale used when reading/writing ratings to files
# max_rating = 100
# Allows creating, deleting and modifying m3u playlists in the library directories.
# Only supported by the player web interface and some mpd clients
# Defaults to being disabled.
# allow_modifying_stored_playlists = false
# A directory in one of the library directories that will be used as the default
# playlist directory. OwnTone creates new playlists in this directory if only
# a playlist name is provided (requires "allow_modify_stored_playlists" set to true).
# default_playlist_directory = ""
# By default OwnTone will - like iTunes - clear the playqueue if
# playback stops. Setting clear_queue_on_stop_disable to true will keep
# the playlist like MPD does. Note that some dacp clients do not show
# the playqueue if playback is stopped.
# clear_queue_on_stop_disable = false
}
# Local audio output
audio {
# Name - used in the speaker list in Remote
nickname = "Computer"
# Type of the output (alsa, pulseaudio, dummy or disabled)
# type = "alsa"
# For pulseaudio output, an optional server hostname or IP can be
# specified (e.g. "localhost"). If not set, connection is made via local
# socket.
# server = ""
# Audio PCM device name for local audio output - ALSA only
# card = "default"
# Mixer channel to use for volume control - ALSA only
# If not set, PCM will be used if available, otherwise Master.
# mixer = ""
# Mixer device to use for volume control - ALSA only
# If not set, the value for "card" will be used.
# mixer_device = ""
# Enable or disable audio resampling to keep local audio in sync with
# e.g. Airplay. This feature relies on accurate ALSA measurements of
# delay, and some devices don't provide that. If that is the case you
# are better off disabling the feature.
# sync_disable = false
# Here you can adjust when local audio is started relative to other
# speakers, e.g. Airplay. Negative values correspond to moving local
# audio ahead, positive correspond to delaying it. The unit is
# milliseconds. The offset must be between -1000 and 1000 (+/- 1 sec).
# offset_ms = 0
# To calculate what and if resampling is required, local audio delay is
# measured each second. After a period the collected measurements are
# used to estimate drift and latency, which determines if corrections
# are required. This setting sets the length of that period in seconds.
# adjust_period_seconds = 100
}
# ALSA device settings
# If you have multiple ALSA devices you can configure them individually via
# sections like the below. Make sure to set the "card name" correctly. See the
# README about ALSA for details. Note that these settings will override the ALSA
# settings in the "audio" section above.
#alsa "card name" {
# Name used in the speaker list. If not set, the card name will be used.
# nickname = "Computer"
# Mixer channel to use for volume control
# If not set, PCM will be used if available, otherwise Master
# mixer = ""
# Mixer device to use for volume control
# If not set, the card name will be used
# mixer_device = ""
#}
# Pipe output
# Allows OwnTone to output audio data to a named pipe
#fifo {
# nickname = "fifo"
# path = "/path/to/fifo"
#}
# AirPlay settings common to all devices
#airplay_shared {
# UDP ports used when airplay devices make connections back to
# OwnTone (choosing specific ports may be helpful when running
# OwnTone behind a firewall)
# control_port = 0
# timing_port = 0
# Switch Airplay 1 streams to uncompressed ALAC (as opposed to regular,
# compressed ALAC). Reduces CPU use at the cost of network bandwidth.
# uncompressed_alac = false
#}
# AirPlay per device settings
# (make sure you get the capitalization of the device name right)
#airplay "My AirPlay device" {
# OwnTone's volume goes to 11! If that's more than you can handle
# you can set a lower value here
# max_volume = 11
# Enable this option to exclude a particular AirPlay device from the
# speaker list
# exclude = false
# Enable this option to keep a particular AirPlay device in the speaker
# list and thus ignore mdns notifications about it no longer being
# present. The speaker will remain until restart of OwnTone.
# permanent = false
# Some devices spuriously disconnect during playback, and based on the
# device type OwnTone may attempt to reconnect. Setting this option
# overrides this so reconnecting is either always enabled or disabled.
# reconnect = false
# AirPlay password
# password = "s1kr3t"
# Disable AirPlay 1 (RAOP)
# raop_disable = false
# Name used in the speaker list, overrides name from the device
# nickname = "My speaker name"
#}
# Chromecast settings
# (make sure you get the capitalization of the device name right)
#chromecast "My Chromecast device" {
# OwnTone's volume goes to 11! If that's more than you can handle
# you can set a lower value here
# max_volume = 11
# Enable this option to exclude a particular device from the speaker
# list
# exclude = false
# Name used in the speaker list, overrides name from the device
# nickname = "My speaker name"
#}
# Spotify settings (only have effect if Spotify enabled - see README/INSTALL)
spotify {
# Set preferred bitrate for music streaming
# 0: No preference (default), 1: 96kbps, 2: 160kbps, 3: 320kbps
# bitrate = 0
# Your Spotify playlists will by default be put in a "Spotify" playlist
# folder. If you would rather have them together with your other
# playlists you can set this option to true.
# base_playlist_disable = false
# Spotify playlists usually have many artist, and if you don't want
# every artist to be listed when artist browsing in Remote, you can set
# the artist_override flag to true. This will use the compilation_artist
# as album artist for Spotify items.
# artist_override = false
# Similar to the different artists in Spotify playlists, the playlist
# items belong to different albums, and if you do not want every album
# to be listed when browsing in Remote, you can set the album_override
# flag to true. This will use the playlist name as album name for
# Spotify items. Notice that if an item is in more than one playlist,
# it will only appear in one album when browsing (in which album is
# random).
# album_override = false
}
# RCP/Roku Soundbridge output settings
# (make sure you get the capitalization of the device name right)
#rcp "My SoundBridge device" {
# Enable this option to exclude a particular device from the speaker
# list
# exclude = false
# A Roku/SoundBridge can power up in 2 modes: (default) reconnect to the
# previously used library (ie OwnTone) or in a 'cleared library' mode.
# The Roku power up behaviour is affected by how OwnTone disconnects
# from the Roku device.
#
# Set to false to maintain default Roku power on behaviour
# clear_on_close = false
#}
# MPD configuration (only have effect if MPD enabled - see README/INSTALL)
mpd {
# TCP port to listen on for MPD client requests.
# Default port is 6600, set to 0 to disable MPD support.
# port = 6600
# HTTP port to listen for artwork requests (only supported by some MPD
# clients and will need additional configuration in the MPD client to
# work). Set to 0 to disable serving artwork over http.
# http_port = 0
}
# SQLite configuration (allows to modify the operation of the SQLite databases)
# Make sure to read the SQLite documentation for the corresponding PRAGMA
# statements as changing them from the defaults may increase the possibility of
# database corruptions! By default the SQLite default values are used.
sqlite {
# Cache size in number of db pages for the library database
# (SQLite default page size is 1024 bytes and cache size is 2000 pages)
# pragma_cache_size_library = 2000
# Cache size in number of db pages for the daap cache database
# (SQLite default page size is 1024 bytes and cache size is 2000 pages)
# pragma_cache_size_cache = 2000
# Sets the journal mode for the database
# DELETE (default), TRUNCATE, PERSIST, MEMORY, WAL, OFF
# pragma_journal_mode = DELETE
# Change the setting of the "synchronous" flag
# 0: OFF, 1: NORMAL, 2: FULL (default)
# pragma_synchronous = 2
# Number of bytes set aside for memory-mapped I/O for the library database
# (requires sqlite 3.7.17 or later)
# 0: disables mmap (default), any other value > 0: number of bytes for mmap
# pragma_mmap_size_library = 0
# Number of bytes set aside for memory-mapped I/O for the cache database
# (requires sqlite 3.7.17 or later)
# 0: disables mmap (default), any other value > 0: number of bytes for mmap
# pragma_mmap_size_cache = 0
# Should the database be vacuumed on startup? (increases startup time,
# but may reduce database size). Default is yes.
# vacuum = yes
}
# Streaming audio settings for remote connections (ie stream.mp3)
streaming {
# Sample rate, typically 44100 or 48000
# sample_rate = 44100
# Set the MP3 streaming bit rate (in kbps), valid options: 64 / 96 / 128 / 192 / 320
# bit_rate = 192
}

View File

@ -0,0 +1,11 @@
# Starfish (https://starship.rs/) - shell prompt
ENABLE_STARSHIP=1
# Atuin (https://atuin.sh/) - shell history
ENABLE_ATUIN=1
# zoxide (https://github.com/ajeetdsouza/zoxide) - replacement for cd
ENABLE_ZOXIDE=1
# eza (https://eza.rocks/) - replacement for ls
ENABLE_ESA=1

View File

@ -0,0 +1,73 @@
FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04
ARG USERNAME=vscode
# Workaround for bug: https://github.com/devcontainers/images/issues/1056
RUN userdel -r ubuntu; usermod -u 1000 $USERNAME; groupmod -g 1000 $USERNAME
RUN apt-get -y update \
&& apt-get install -y \
# Build tools and dependencies for OwnTone
autoconf \
automake \
autotools-dev \
bison \
build-essential \
flex \
gawk \
gettext \
git \
gperf \
libasound2-dev \
libavahi-client-dev \
libavcodec-dev \
libavfilter-dev \
libavformat-dev \
libavutil-dev \
libconfuse-dev \
libcurl4-openssl-dev \
libevent-dev \
libgcrypt20-dev \
libjson-c-dev \
libmxml-dev \
libplist-dev \
libprotobuf-c-dev \
libsodium-dev \
libsqlite3-dev \
libswscale-dev \
libtool \
libunistring-dev \
libwebsockets-dev \
libxml2-dev \
zlib1g-dev \
# Build tools for mmkdocs (OwnTone documentation)
python3-pip \
# Additional runtime dependencies for dev container
avahi-daemon \
# Additional debug and devtools for dev container
clang \
clang-format \
clang-tools \
gdb \
valgrind \
# Additional terminal utility applications
pipx \
# bat - replacement for cat
bat \
# eza (https://eza.rocks/) - replacement for ls
eza \
# fuzzy search
fzf \
# Create folders and set ownership for folders that might be mounted as volumes
&& mkdir -p /home/$USERNAME/.local/share \
&& chown -R $USERNAME /home/$USERNAME/.local \
&& mkdir /commandhistory \
&& touch /commandhistory/.bash_history \
&& chown -R $USERNAME /commandhistory \
&& echo "export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" >> "/home/$USERNAME/.bashrc" \
&& echo '[[ -f /scripts/init-devcontainer-cli.sh ]] && source /scripts/init-devcontainer-cli.sh' >> "/home/$USERNAME/.bashrc" \
# Create folders for owntone-server data
&& mkdir -p /data/logs /data/music /data/cache /data/conf \
&& chown -R $USERNAME /data \
# Clean up
&& apt-get clean -y && rm -rf /var/lib/apt/lists/*

View File

@ -0,0 +1,55 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu
{
"name": "Ubuntu",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
// "image": "mcr.microsoft.com/devcontainers/base:jammy"
"build": {
"dockerfile": "Dockerfile"
},
"runArgs": [
// Use host network to be able to connect to remote speakers
"--network=host",
"--env-file", ".devcontainer/devcontainer.env"
],
// Configure tool-specific properties.
"customizations": {
"vscode": {
"extensions": [
"Vue.volar",
"ms-vscode.cpptools-extension-pack",
"ms-azuretools.vscode-docker",
"lokalise.i18n-ally",
"esbenp.prettier-vscode"
]
}
},
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers/features/node:1": {}
},
// Mounts volumes to keep files / state between container rebuilds
"mounts": [
// Map script folder to install and init additional tools (see "postCreateCommand" and Dockerfile / .bashrc)
"source=${localWorkspaceFolder}/.devcontainer/.scripts,target=/scripts,type=bind,consistency=cached",
// Persist ~/.bash_history
"source=owntone-bashhistory,target=/commandhistory,type=volume",
// Persist ~/.local/share to persist state of additionally installed tools (e. g. atuin, zoxide)
"source=owntone-localshare,target=/home/vscode/.local/share,type=volume",
// Bind mounts for owntone config file and logs, cache, music directories
//"source=<path-to-local-logs-dir>,target=/data/logs,type=bind,consistency=cached",
//"source=<path-to-local-cache-dir>,target=/data/cache,type=bind,consistency=cached",
//"source=<path-to-local-music-dir>,target=/data/music,type=bind,consistency=cached",
"source=${localWorkspaceFolder}/.devcontainer/data/devcontainer-owntone.conf,target=/data/conf/owntone.conf,type=bind,consistency=cached"
],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "bash /scripts/install-devcontainer-tools.sh",
// Start dbus and avahi, required when running owntone-server
"postStartCommand": "sudo service dbus start ; sudo avahi-daemon -D"
}

View File

@ -0,0 +1,17 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"/usr/include/json-c"
],
"defines": [],
"compilerPath": "/usr/bin/clang",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "linux-clang-x64"
}
],
"version": 4
}

28
.dev/vscode/launch.json Normal file
View File

@ -0,0 +1,28 @@
{
"configurations": [
{
"name": "OwnTone",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/src/owntone",
"args": ["-f", "-c", "/data/conf/owntone.conf", "-w", "${workspaceFolder}/htdocs", "-s", "${workspaceFolder}/sqlext/.libs/owntone-sqlext.so"],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
],
"version": "2.0.0"
}

12
.dev/vscode/settings.json Normal file
View File

@ -0,0 +1,12 @@
{
"C_Cpp.default.forcedInclude": [
"${workspaceFolder}/config.h"
],
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[c]": {
"editor.detectIndentation": false,
"editor.tabSize": 8
}
}

106
.dev/vscode/tasks.json Normal file
View File

@ -0,0 +1,106 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "[server] autoreconf",
"type": "shell",
"command": "autoreconf -i",
"group": {
"kind": "build",
"isDefault": false
}
},
{
"label": "[server] configure",
"type": "shell",
"command": "./configure",
"group": {
"kind": "build",
"isDefault": false
}
},
{
"label": "[server] make",
"type": "shell",
"command": "make",
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "[server] scan-build",
"type": "shell",
"command": "make clean && scan-build --status-bugs -disable-checker deadcode.DeadStores --exclude src/parsers make",
"group": {
"kind": "build",
"isDefault": false
}
},
{
"label": "[server] clean",
"type": "shell",
"command": "make clean",
"group": {
"kind": "build",
"isDefault": false
}
},
{
"label": "[web] install",
"type": "npm",
"script": "install",
"options": {
"cwd": "${workspaceFolder}/web-src"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "[web] build",
"type": "npm",
"script": "build",
"options": {
"cwd": "${workspaceFolder}/web-src"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "[web] serve",
"type": "npm",
"script": "serve",
"options": {
"cwd": "${workspaceFolder}/web-src"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "[docs] serve",
"type": "shell",
"command": "mkdocs serve",
"group": {
"kind": "build",
"isDefault": false
}
},
{
"label": "[docs] build",
"type": "shell",
"command": "mkdocs build",
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

6
.gitignore vendored
View File

@ -39,7 +39,11 @@ owntone@.service
/.cproject
/.project
/.autotools
/.vscode
# ignore MkDocs generated documentation
/site/
/test/
/.vscode/
/.devcontainer/
!/.dev/Makefile

88
docs/development.md Normal file
View File

@ -0,0 +1,88 @@
# Development
## Dev Containers and VSCode
To set up a development environment for OwnTone, the project includes an example Dev Containers configuration.
!!! tip "Dev Containers"
To learn more about Dev Containers and how to use them check out the documentation at:
- <https://code.visualstudio.com/docs/devcontainers/containers>
- <https://containers.dev/>
Dev Containers config for OwnTone includes all the necessary and some nice to have tooling:
- C-tools to build and develop for owntone-server, including autotools, dependencies, etc.
- Javascript-tools to build and develop the OwnTone web interface.
- Python-tools to build and run the OwnTone documentation with mkdocs.
### Prerquisites
1. Install [Docker](https://www.docker.com/get-started).
2. Install [Visual Studio Code](https://code.visualstudio.com/).
3. Install the [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension for Visual Studio Code.
### Initial setup
The Dev Container and VSCode example configuration files are located in the project folder `.dev/devcontainer` and `.dev/vscode`.
To make use of them follow these steps:
1. Copy the directories or run `make vscode` from inside the `.dev` folder.
2. Open your project in Visual Studio Code.
3. Open the Command Palette (`Ctrl+Shift+P`) and select `Dev Containers: Reopen in Container`.
4. VSCode will build the container and reopen the project inside the container.
Be patient, the first run will take several minutes to complete.
### Usage
Inside the container you can follow the build instructions (see [Building](building.md)):
- Build owntone-server
```bash
autoreconf -i
./configure
make
```
- Build web interface
```bash
cd web-src
npm run build
```
Running `owntone-server` from inside the container with the predefined run/debug configuration will
use the conf file `.devcontainer/data/devcontainer-owntone.conf` as `owntone.conf`.
Configure the mount configuration in `.devcontainer/devcontainer.json` to use a different music folder
or mount the log folder to a local directory.
```json
// Mounts volumes to keep files / state between container rebuilds
"mounts": [
//...
// Bind mounts for owntone config file and logs, cache, music directories
//"source=<path-to-local-logs-dir>,target=/data/logs,type=bind,consistency=cached",
//"source=<path-to-local-cache-dir>,target=/data/cache,type=bind,consistency=cached",
//"source=<path-to-local-music-dir>,target=/data/music,type=bind,consistency=cached",
"source=${localWorkspaceFolder}/.devcontainer/data/devcontainer-owntone.conf,target=/data/conf/owntone.conf,type=bind,consistency=cached"
],
```
### Dev Container configuration
The Dev Container example uses an Ubuntu image as base. It contains some additional (opinionated) tools to customize the shell prompt and some terminal niceties:
- [Starship](https://starship.rs/) to customize the shell prompt.
- [eza](https://eza.rocks/) as `ls` replacement.
- [Atuin](https://atuin.sh/) for the shell history.
Take a look at `.devcontainer/devcontainer.env` if you want to disable any of those.
Additional terminal tools installed are:
- [zoxide](https://github.com/ajeetdsouza/zoxide) - a smarter `cd`
- [bat](https://github.com/sharkdp/bat) - a `cat` clone with syntax highlighting

View File

@ -158,4 +158,5 @@ nav:
- Radio Streams: advanced/radio-streams.md
- Remote Access: advanced/remote-access.md
- Multiple Instances: advanced/multiple-instances.md
- Development: development.md
- JSON API: json-api.md

View File

@ -652,6 +652,7 @@ db_pl_type_label(enum pl_type pl_type)
struct rng_ctx shuffle_rng;
static char *db_path;
static char *db_sqlite_ext_path;
static bool db_rating_updates;
static __thread sqlite3 *hdl;
@ -6957,7 +6958,7 @@ db_open(void)
return -1;
}
ret = sqlite3_load_extension(hdl, PKGLIBDIR "/" PACKAGE_NAME "-sqlext.so", NULL, &errmsg);
ret = sqlite3_load_extension(hdl, db_sqlite_ext_path, NULL, &errmsg);
if (ret != SQLITE_OK)
{
DPRINTF(E_LOG, L_DB, "Could not load SQLite extension: %s\n", errmsg);
@ -7371,7 +7372,7 @@ db_check_version(void)
}
int
db_init(void)
db_init(char *sqlite_ext_path)
{
uint32_t files;
uint32_t pls;
@ -7388,6 +7389,7 @@ db_init(void)
}
db_path = cfg_getstr(cfg_getsec(cfg, "general"), "db_path");
db_sqlite_ext_path = sqlite_ext_path;
db_rating_updates = cfg_getbool(cfg_getsec(cfg, "library"), "rating_updates");
DPRINTF(E_INFO, L_DB, "Configured to use database file '%s'\n", db_path);

View File

@ -1029,7 +1029,7 @@ void
db_perthread_deinit(void);
int
db_init(void);
db_init(char *sqlite_ext_path);
void
db_deinit(void);

View File

@ -75,6 +75,7 @@
#define PIDFILE STATEDIR "/run/" PACKAGE ".pid"
#define WEB_ROOT DATADIR "/htdocs"
#define SQLITE_EXT_PATH PKGLIBDIR "/" PACKAGE_NAME "-sqlext.so"
struct event_base *evbase_main;
@ -106,6 +107,7 @@ usage(char *program)
printf(" --mdns-no-daap Don't announce DAAP service via mDNS\n");
printf(" --mdns-no-cname Don't register owntone.local as CNAME via mDNS\n");
printf(" --mdns-no-web Don't announce web interface via mDNS\n");
printf(" -s <path> Use <path> as the path for the OwnTone sqlite extension (owntone-sqlext.so)\n");
printf("\n\n");
printf("Available log domains:\n");
logger_domains();
@ -495,6 +497,7 @@ main(int argc, char **argv)
char *ffid = NULL;
char *pidfile = PIDFILE;
char *webroot = WEB_ROOT;
char *sqlite_extension_path = SQLITE_EXT_PATH;
char **buildopts;
const char *av_version;
const char *gcry_version;
@ -516,6 +519,7 @@ main(int argc, char **argv)
{ "pidfile", 1, NULL, 'P' },
{ "version", 0, NULL, 'v' },
{ "webroot", 1, NULL, 'w' },
{ "sqliteext", 1, NULL, 's' },
{ "testrun", 0, NULL, 't' }, // Used for CI, not documented to user
{ "mdns-no-rsp", 0, NULL, 512 },
@ -526,7 +530,7 @@ main(int argc, char **argv)
{ NULL, 0, NULL, 0 }
};
while ((option = getopt_long(argc, argv, "D:d:c:P:ftb:vw:", option_map, NULL)) != -1)
while ((option = getopt_long(argc, argv, "D:d:c:P:ftb:vw:s:", option_map, NULL)) != -1)
{
switch (option)
{
@ -587,6 +591,10 @@ main(int argc, char **argv)
webroot = optarg;
break;
case 's':
sqlite_extension_path = optarg;
break;
default:
usage(argv[0]);
return EXIT_FAILURE;
@ -739,7 +747,7 @@ main(int argc, char **argv)
/* Initialize the database before starting */
DPRINTF(E_INFO, L_MAIN, "Initializing database\n");
ret = db_init();
ret = db_init(sqlite_extension_path);
if (ret < 0)
{
DPRINTF(E_FATAL, L_MAIN, "Database init failed\n");

View File

@ -3,7 +3,7 @@
"version": "2.0.1",
"type": "module",
"scripts": {
"serve": "vite --port 3000",
"serve": "vite --port 3000 --host",
"build": "vite build --base='./'",
"lint": "eslint",
"dev": "vite",