diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0213d5178..53c0864a9 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,40 +1,47 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node { - "name": "Audiobookshelf", - "build": { - "dockerfile": "Dockerfile", - // Update 'VARIANT' to pick a Node version: 18, 16, 14. - // Append -bullseye or -buster to pin to an OS version. - // Use -bullseye variants on local arm64/Apple Silicon. - "args": { - "VARIANT": "20" - } - }, - "mounts": [ - "source=abs-server-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume", - "source=abs-client-node_modules,target=${containerWorkspaceFolder}/client/node_modules,type=volume" - ], - // Features to add to the dev container. More info: https://containers.dev/features. - // "features": {}, - // Use 'forwardPorts' to make a list of ports inside the container available locally. - "forwardPorts": [ - 3000, - 3333 - ], - // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": "sh .devcontainer/post-create.sh", - // Configure tool-specific properties. - "customizations": { - // Configure properties specific to VS Code. - "vscode": { - // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "dbaeumer.vscode-eslint", - "octref.vetur" - ] - } - } - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" -} \ No newline at end of file + "name": "Audiobookshelf", + "build": { + "dockerfile": "Dockerfile", + // Update 'VARIANT' to pick a Node version: 18, 16, 14. + // Append -bullseye or -buster to pin to an OS version. + // Use -bullseye variants on local arm64/Apple Silicon. + "args": { + "VARIANT": "20" + } + }, + "mounts": ["source=abs-server-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume", "source=abs-client-node_modules,target=${containerWorkspaceFolder}/client/node_modules,type=volume", "type=bind,source=/Users/benjamindonaldson/Downloads,target=${containerWorkspaceFolder}/downloads"], + // Features to add to the dev container. More info: https://containers.dev/features. + "features": { + "ghcr.io/devcontainers/features/common-utils:2": { + "installZsh": true, + "username": "vscode", + "upgradePackages": true + } + }, + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000, 3333], + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "sh .devcontainer/post-create.sh", + // Configure tool-specific properties. + "customizations": { + // Configure properties specific to VS Code. + "vscode": { + // Add the IDs of extensions you want installed when the container is created. + "extensions": ["dbaeumer.vscode-eslint", "octref.vetur"] + } + }, + // Add settings for Cursor + "settings": { + "terminal.integrated.defaultProfile.linux": "zsh", + "terminal.integrated.profiles.linux": { + "zsh": { + "path": "/bin/zsh" + } + } + }, + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + "remoteUser": "vscode", + "updateRemoteUserUID": true +} diff --git a/.gitignore b/.gitignore index 12ebec1c2..b6d6f25dd 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ /media/ /metadata/ /plugins/ +*.epub /client/.nuxt/ /client/dist/ /dist/ diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 000000000..30568a12f --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,114 @@ +# Audiobookshelf Deployment Guide + +## Prerequisites + +- Docker Desktop (for local deployment) +- Portainer (optional, for container management) +- At least 1GB of free RAM +- Sufficient disk space for your audiobooks and metadata + +## Directory Structure + +``` +audiobookshelf/ +├── audiobooks/ # Your audiobooks directory +├── podcasts/ # Your podcasts directory +├── metadata/ # Application metadata +├── config/ # Configuration files +├── client/ # Frontend source code +├── server/ # Backend source code +├── Dockerfile # Docker build instructions +└── docker-compose.prod.yml + +External Directories: +/libraries/ # Additional media libraries directory (customizable path) +``` + +## Deployment Steps + +### Using Docker Desktop + +1. Create the required directories: + + ```bash + mkdir -p audiobooks podcasts metadata config + ``` + +2. Configure your libraries path: Edit `docker-compose.prod.yml` and modify the libraries volume mount to point to your desired path: + + ```yaml + volumes: + - /path/to/your/libraries:/libraries + ``` + +3. Build and start the application: + + ```bash + # Build the image + docker compose -f docker-compose.prod.yml build + + # Start the containers + docker compose -f docker-compose.prod.yml up -d + ``` + +4. Access the application at `http://localhost:13378` + +### Using Portainer + +1. In Portainer, go to "Stacks" and click "Add Stack" +2. Give your stack a name (e.g., "audiobookshelf") +3. Copy the contents of `docker-compose.prod.yml` into the web editor +4. Modify the libraries volume mount path to match your system +5. Enable "Build Image" option in Portainer +6. Click "Deploy the stack" + +## Configuration + +- The application runs on port 13378 by default +- Data is persisted in the mounted volumes: + - `./audiobooks`: Default audiobooks directory + - `./podcasts`: Default podcasts directory + - `./metadata`: Application metadata + - `./config`: Configuration files + - `/libraries`: Additional media libraries (customize path in docker-compose.prod.yml) +- Timezone can be configured in the docker-compose file +- User/Group IDs can be set via PUID/PGID environment variables + +## Post-Installation + +1. On first run, create an admin account +2. Configure your libraries in the web interface: + - Set up the default audiobooks and podcasts directories + - Add additional libraries from the `/libraries` mount point +3. Add your media files to the appropriate directories + +## Updating + +When you make changes to your code: + +```bash +# Rebuild the image with your changes +docker compose -f docker-compose.prod.yml build + +# Restart the containers with the new image +docker compose -f docker-compose.prod.yml up -d +``` + +## Backup + +Important directories to backup: + +- `config/` - Contains application settings and database +- `metadata/` - Contains metadata for your media +- `audiobooks/` and `podcasts/` - Your media files +- Any additional libraries you've configured + +## Troubleshooting + +- Check container logs: `docker logs audiobookshelf` +- Ensure proper file permissions on mounted volumes +- Verify port 13378 is not in use by another application +- Check resource usage in Docker Desktop dashboard +- Build logs: `docker compose -f docker-compose.prod.yml build --progress=plain` +- Check that all volume mount paths exist and are accessible +- Verify file permissions on the libraries directory diff --git a/client/assets/app.css b/client/assets/app.css index 36b3b4bad..7ad730842 100644 --- a/client/assets/app.css +++ b/client/assets/app.css @@ -7,6 +7,92 @@ :root { --bookshelf-texture-img: url(~static/textures/wood_default.jpg); --bookshelf-divider-bg: linear-gradient(180deg, rgba(149, 119, 90, 1) 0%, rgba(103, 70, 37, 1) 17%, rgba(103, 70, 37, 1) 88%, rgba(71, 48, 25, 1) 100%); + + /* Theme Colors */ + --color-primary: #1e293b; + --color-primary-dark: #0f172a; + --color-success: #22c55e; + --color-warning: #f59e0b; + --color-error: #ef4444; + --color-info: #3b82f6; + --color-bg: #111827; +} + +/* Color Classes */ +.bg-primary { + background-color: var(--color-primary) !important; +} + +.bg-primary-dark { + background-color: var(--color-primary-dark) !important; +} + +.bg-success { + background-color: var(--color-success) !important; +} + +.bg-warning { + background-color: var(--color-warning) !important; +} + +.bg-error { + background-color: var(--color-error) !important; +} + +.bg-info { + background-color: var(--color-info) !important; +} + +.bg-bg { + background-color: var(--color-bg) !important; +} + +.text-primary { + color: var(--color-primary) !important; +} + +.text-primary-dark { + color: var(--color-primary-dark) !important; +} + +.text-success { + color: var(--color-success) !important; +} + +.text-warning { + color: var(--color-warning) !important; +} + +.text-error { + color: var(--color-error) !important; +} + +.text-info { + color: var(--color-info) !important; +} + +.border-primary { + border-color: var(--color-primary) !important; +} + +.border-primary-dark { + border-color: var(--color-primary-dark) !important; +} + +.border-success { + border-color: var(--color-success) !important; +} + +.border-warning { + border-color: var(--color-warning) !important; +} + +.border-error { + border-color: var(--color-error) !important; +} + +.border-info { + border-color: var(--color-info) !important; } .page { @@ -249,4 +335,4 @@ Bookshelf Label .abs-btn:disabled::before { background-color: rgba(0, 0, 0, 0.2); -} +} \ No newline at end of file diff --git a/client/assets/tailwind.css b/client/assets/tailwind.css index 7883f32ff..5608bf7f4 100644 --- a/client/assets/tailwind.css +++ b/client/assets/tailwind.css @@ -9,6 +9,7 @@ color utility to any element that depends on these defaults. */ @layer base { + *, ::after, ::before, @@ -58,22 +59,23 @@ --spacing-80e: 20em; --spacing-96e: 24em; - --color-bg: #373838; - --color-primary: #232323; + --color-bg: #2F4F4F; + --color-primary: #2E8B57; + --color-mid-purple: #3CB371; --color-accent: #1ad691; --color-error: #ff5252; --color-info: #2196f3; --color-success: #4caf50; --color-warning: #fb8c00; --color-darkgreen: rgb(34, 127, 35); - --color-black-50: #bbbbbb; - --color-black-100: #666666; - --color-black-200: #555555; - --color-black-300: #444444; - --color-black-400: #333333; - --color-black-500: #222222; - --color-black-600: #111111; - --color-black-700: #101010; + --color-black-50: #F0FFF0; + --color-black-100: #98FB98; + --color-black-200: #90EE90; + --color-black-300: #3CB371; + --color-black-400: #2E8B57; + --color-black-500: #228B22; + --color-black-600: #006400; + --color-black-700: #004225; --font-sans: 'Source Sans Pro'; --font-mono: 'Ubuntu Mono'; @@ -82,4 +84,4 @@ --text-1\.5xl: 1.375rem; --text-2\.5xl: 1.6875rem; --text-4\.5xl: 2.625rem; -} +} \ No newline at end of file diff --git a/client/components/app/Appbar.vue b/client/components/app/Appbar.vue index f74134041..6d022fd75 100644 --- a/client/components/app/Appbar.vue +++ b/client/components/app/Appbar.vue @@ -3,11 +3,11 @@
{{ route.title }}
- +{{ setting.description }}
+Apply Tags
+Add or remove tags from {{ selectedItemsCount }} selected items
+{{ addMode ? 'Add tags to items' : 'Remove tags from items' }}
++ {{ addMode ? 'Selected tags will be added to all selected items' : 'Selected tags will be removed from all selected items' }} +
+| {{ $strings.LabelUsername }} | +{{ $strings.LabelDisplayName }} | {{ $strings.LabelAccountType }} | {{ $strings.LabelActivity }} | @@ -17,6 +18,9 @@
+ {{ user.displayName || '-' }} + |
{{ user.type }} |
diff --git a/client/components/ui/MultiSelect.vue b/client/components/ui/MultiSelect.vue
index bf0d1ec99..67e126d5a 100644
--- a/client/components/ui/MultiSelect.vue
+++ b/client/components/ui/MultiSelect.vue
@@ -138,7 +138,8 @@ export default {
},
setInputWidth() {
setTimeout(() => {
- var value = this.$refs.input.value
+ if (!this.$refs.input) return
+ var value = this.$refs.input.value || ''
var len = value.length * 7 + 24
this.$refs.input.style.width = len + 'px'
this.recalcMenuPos()
diff --git a/client/layouts/default.vue b/client/layouts/default.vue
index 33e7aa15b..db858ceaa 100644
--- a/client/layouts/default.vue
+++ b/client/layouts/default.vue
@@ -1,5 +1,6 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/client/pages/config/users/_id/index.vue b/client/pages/config/users/_id/index.vue
index e2f8e2086..ff3aabe3f 100644
--- a/client/pages/config/users/_id/index.vue
+++ b/client/pages/config/users/_id/index.vue
@@ -107,7 +107,7 @@ export default {
return this.$store.getters['libraries/getBookCoverAspectRatio']
},
username() {
- return this.user.username
+ return this.user.displayName || this.user.username
},
userOnline() {
return this.$store.getters['users/getIsUserOnline'](this.user.id)
diff --git a/client/pages/config/users/_id/sessions.vue b/client/pages/config/users/_id/sessions.vue
index ab33b4b1c..7f7cab227 100644
--- a/client/pages/config/users/_id/sessions.vue
+++ b/client/pages/config/users/_id/sessions.vue
@@ -92,7 +92,7 @@ export default {
},
computed: {
username() {
- return this.user.username
+ return this.user.displayName || this.user.username
},
userOnline() {
return this.$store.getters['users/getIsUserOnline'](this.user.id)
diff --git a/client/pages/item/_id/index.vue b/client/pages/item/_id/index.vue
index 6042f92a2..0b2232862 100644
--- a/client/pages/item/_id/index.vue
+++ b/client/pages/item/_id/index.vue
@@ -139,6 +139,116 @@
+
+
+
+
+ Server Title+Customize the name of your server. +
+
+
+
+
+
+ Theme Colors+Customize the appearance of your server by adjusting these colors. +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Preview+
+
+
+
+
+
+
+ Buttons +
+
+ Alerts +
+
+
+
+
+
+
+
+
+
+
-
@@ -44,6 +44,13 @@ export default {
return this.$store.state.streamLibraryItem
}
},
- methods: {}
+ methods: {
+ selectAllItems() {
+ if (this.$refs.lazyBookshelf) {
+ this.$refs.lazyBookshelf.selectAllItems()
+ } else {
+ }
+ }
+ }
}
diff --git a/client/pages/library/_library/index.vue b/client/pages/library/_library/index.vue
index f235028c7..f3c32a4a2 100644
--- a/client/pages/library/_library/index.vue
+++ b/client/pages/library/_library/index.vue
@@ -1,7 +1,7 @@
-
@@ -25,7 +25,14 @@ export default {
return this.$store.state.streamLibraryItem
}
},
- methods: {},
+ methods: {
+ selectAllItems() {
+ if (this.$refs.bookShelfCategorized) {
+ this.$refs.bookShelfCategorized.selectAllItems()
+ } else {
+ }
+ }
+ },
mounted() {},
beforeDestroy() {}
}
diff --git a/client/pages/library/_library/search.vue b/client/pages/library/_library/search.vue
index 429603bff..cd6e1275a 100644
--- a/client/pages/library/_library/search.vue
+++ b/client/pages/library/_library/search.vue
@@ -1,6 +1,6 @@
- {{ $getString('MessageNoSearchResultsFor', [query]) }} @@ -11,10 +11,13 @@ + + diff --git a/client/static/Logo.png b/client/static/Logo.png index 24e03a64a..87fb48ff9 100644 Binary files a/client/static/Logo.png and b/client/static/Logo.png differ diff --git a/client/static/bookfire-logo-white.svg b/client/static/bookfire-logo-white.svg new file mode 100644 index 000000000..87fb48ff9 --- /dev/null +++ b/client/static/bookfire-logo-white.svg @@ -0,0 +1,12 @@ + + + diff --git a/client/static/dumpsterFireLogo.png b/client/static/dumpsterFireLogo.png new file mode 100644 index 000000000..08c313a71 Binary files /dev/null and b/client/static/dumpsterFireLogo.png differ diff --git a/client/static/dumpsterFireLogo.svg b/client/static/dumpsterFireLogo.svg new file mode 100644 index 000000000..1f919ac3e --- /dev/null +++ b/client/static/dumpsterFireLogo.svg @@ -0,0 +1,15 @@ + + + diff --git a/client/static/dumpsterFireLogoWhite.png b/client/static/dumpsterFireLogoWhite.png new file mode 100644 index 000000000..42e3ba130 Binary files /dev/null and b/client/static/dumpsterFireLogoWhite.png differ diff --git a/client/static/favicon.ico b/client/static/favicon.ico index 6561a0844..87fb48ff9 100644 Binary files a/client/static/favicon.ico and b/client/static/favicon.ico differ diff --git a/client/static/icon.svg b/client/static/icon.svg index 91b25705a..87fb48ff9 100644 --- a/client/static/icon.svg +++ b/client/static/icon.svg @@ -1,41 +1,12 @@ - \ No newline at end of file + + + diff --git a/client/static/icon192.png b/client/static/icon192.png index 5cbf1d4db..87fb48ff9 100644 Binary files a/client/static/icon192.png and b/client/static/icon192.png differ diff --git a/client/static/icon48.png b/client/static/icon48.png index 8f94f77c1..87fb48ff9 100644 Binary files a/client/static/icon48.png and b/client/static/icon48.png differ diff --git a/client/static/icon64.png b/client/static/icon64.png index e420b7ca9..87fb48ff9 100644 Binary files a/client/static/icon64.png and b/client/static/icon64.png differ diff --git a/client/static/ios_icon.png b/client/static/ios_icon.png index 4deb595b7..87fb48ff9 100644 Binary files a/client/static/ios_icon.png and b/client/static/ios_icon.png differ diff --git a/client/store/index.js b/client/store/index.js index b9feec8db..f7c78d5a8 100644 --- a/client/store/index.js +++ b/client/store/index.js @@ -36,6 +36,10 @@ export const getters = { if (!state.serverSettings) return null return state.serverSettings[key] }, + getServerStyling: (state) => { + if (!state.serverSettings?.styling) return null + return state.serverSettings.styling + }, getLibraryItemIdStreaming: (state) => { return state.streamLibraryItem?.id || null }, diff --git a/client/strings/en-us.json b/client/strings/en-us.json index 939eb9f4b..6574aeac6 100644 --- a/client/strings/en-us.json +++ b/client/strings/en-us.json @@ -1103,5 +1103,31 @@ "ToastUserPasswordChangeSuccess": "Password changed successfully", "ToastUserPasswordMismatch": "Passwords do not match", "ToastUserPasswordMustChange": "New password cannot match old password", - "ToastUserRootRequireName": "Must enter a root username" + "ToastUserRootRequireName": "Must enter a root username", + "LabelComments": "Comments", + "PlaceholderAddComment": "Add a rating... (Ctrl+Enter to post)", + "ButtonPost": "Post", + "MessageNoComments": "No rating yet. Be the first to rate!", + "MessageCommentAdded": "Rating added successfully", + "MessageCommentUpdated": "Rating updated successfully", + "MessageCommentDeleted": "Rating deleted successfully", + "ErrorLoadingComments": "Error loading ratings", + "ErrorAddingComment": "Error adding ratings", + "ErrorUpdatingComment": "Error updating ratings", + "ErrorDeletingComment": "Error deleting ratings", + "ConfirmDeleteComment": "Are you sure you want to delete this rating?", + "LabelRating": "Rating", + "LabelStarRating": "{0} stars", + "LabelNoRating": "No rating", + "LabelAverageRating": "Average rating: {0}", + "HeaderStyling": "Styling", + "HeaderStylingColors": "Colors", + "HeaderStylingPreview": "Preview", + "LabelBackgroundColor": "Background Color", + "LabelErrorColor": "Error Color", + "LabelInfoColor": "Info Color", + "LabelPrimaryColor": "Primary Color", + "LabelPrimaryDarkColor": "Primary Dark Color", + "LabelSuccessColor": "Success Color", + "LabelWarningColor": "Warning Color" } diff --git a/client/strings/en.json b/client/strings/en.json new file mode 100644 index 000000000..c8e51a5bb --- /dev/null +++ b/client/strings/en.json @@ -0,0 +1,40 @@ +{ + "HeaderServerStyling": "Server Styling", + "DescriptionServerStyling": "Customize server appearance", + "HeaderSettings": "Settings", + "HeaderLibraries": "Libraries", + "HeaderUsers": "Users", + "HeaderListeningSessions": "Listening Sessions", + "HeaderBackups": "Backups", + "HeaderLogs": "Logs", + "HeaderNotifications": "Notifications", + "HeaderEmail": "Email", + "HeaderItemMetadataUtils": "Item Metadata Utils", + "HeaderRSSFeeds": "RSS Feeds", + "HeaderAuthentication": "Authentication", + "HeaderLibraryStats": "Library Stats", + "HeaderYourStats": "Your Stats", + "DescriptionAuthentication": "Configure authentication methods and settings", + "DescriptionLibraries": "Manage your libraries", + "DescriptionBackups": "Configure server backups", + "DescriptionEmail": "Configure email settings", + "DescriptionNotifications": "Configure notification settings", + "DescriptionServerLogs": "View server logs", + "LabelSelectAll": "Select All", + "LabelComments": "Comments", + "PlaceholderAddComment": "Add a comment... (Ctrl+Enter to post)", + "ButtonPost": "Post", + "ButtonEdit": "Edit", + "ButtonDelete": "Delete", + "ButtonCancel": "Cancel", + "ButtonSave": "Save", + "MessageNoComments": "No comments yet. Be the first to comment!", + "MessageCommentAdded": "Comment added successfully", + "MessageCommentUpdated": "Comment updated successfully", + "MessageCommentDeleted": "Comment deleted successfully", + "ErrorLoadingComments": "Error loading comments", + "ErrorAddingComment": "Error adding comment", + "ErrorUpdatingComment": "Error updating comment", + "ErrorDeletingComment": "Error deleting comment", + "ConfirmDeleteComment": "Are you sure you want to delete this comment?" +} \ No newline at end of file diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 000000000..56fe58f77 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,51 @@ +version: '3.8' + +services: + audiobookshelf: + build: + context: https://github.com/zipben/audiobookshelf.git#workingitout + dockerfile: Dockerfile + container_name: audiobookshelf + ports: + - "7696:80" # The app will be available on port 7696 + volumes: + # Named volumes for persistent data + - audiobooks:/audiobooks + - podcasts:/podcasts + - metadata:/metadata + - config:/config + # Mount point for external libraries - customize this path in Portainer + - type: bind + source: /path/to/your/libraries + target: /libraries + environment: + - TZ=America/New_York # Set your timezone + - PUID=1000 # User ID for permissions + - PGID=1000 # Group ID for permissions + # Optional environment variables + - PORT=80 # Internal port (don't change unless necessary) + - HOST=0.0.0.0 # Listen on all interfaces + restart: unless-stopped + networks: + - abs_network + healthcheck: + test: ["CMD", "wget", "--spider", "http://localhost:80/ping"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + +networks: + abs_network: + driver: bridge + +volumes: + # Define named volumes - these will be created automatically + audiobooks: + name: audiobookshelf_audiobooks + podcasts: + name: audiobookshelf_podcasts + metadata: + name: audiobookshelf_metadata + config: + name: audiobookshelf_config diff --git a/package-lock.json b/package-lock.json index a80747945..e5989e771 100644 --- a/package-lock.json +++ b/package-lock.json @@ -185,15 +185,16 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz", - "integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==", + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.5.tgz", + "integrity": "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==", "dev": true, "dependencies": { - "@babel/types": "^7.23.3", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" + "@babel/parser": "^7.27.5", + "@babel/types": "^7.27.3", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" @@ -329,18 +330,18 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, "engines": { "node": ">=6.9.0" @@ -425,10 +426,13 @@ "dev": true }, "node_modules/@babel/parser": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz", - "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==", + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz", + "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==", "dev": true, + "dependencies": { + "@babel/types": "^7.27.3" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -495,14 +499,13 @@ "dev": true }, "node_modules/@babel/types": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz", - "integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.3.tgz", + "integrity": "sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -540,14 +543,14 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -563,9 +566,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "engines": { "node": ">=6.0.0" @@ -578,9 +581,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1012,12 +1015,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1926,9 +1929,9 @@ "license": "MIT" }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -2818,15 +2821,15 @@ } }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json5": { @@ -5135,15 +5138,6 @@ "node": ">=8" } }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", diff --git a/package.json b/package.json index d4831736d..ad202a939 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "audiobookshelf", - "version": "2.24.0", + "version": "2.24.1", "buildNumber": 1, "description": "Self-hosted audiobook and podcast server", "main": "index.js", diff --git a/readme.md b/readme.md index 3eb4cef7a..d2fc6b0c5 100644 --- a/readme.md +++ b/readme.md @@ -450,3 +450,28 @@ If you are using VSCode, this project includes a couple of pre-defined targets t # How to Support [See the incomplete "How to Support" page](https://www.audiobookshelf.org/support) + +# Development + +### Killing Running Processes +When developing locally, you might need to kill running instances of the client or server. Here are some helpful commands: + +```bash +# Kill process on port 3000 (client) +sudo kill $(lsof -t -i:3000) + +# Kill process on port 3333 (server) +sudo kill $(lsof -t -i:3333) +``` + +You can also find and kill processes manually: +```bash +# List all Node.js processes +ps aux | grep node + +# Kill processes by PID +kill |
|---|
{{ $strings.LabelRatings }}
+ + ++ {{ $strings.LabelAverageRating.replace('{0}', averageRating.toFixed(1)) }} + + + +
+