Maintenance update (#7)
- Use modern tooling uv and bun - Various changes to work with latest PyAV and PIL that have changed their API - Improved image, video and document previews (uses AVIF, renders AVIF/HEIC/videos in HDR, faster processing) - Fix a server hang in some cases where a folder was moved or renamed - Log exceptions instead of only returning 500 response to client - Log timing of preview generation functions - Default to quality 50 in previews (previously 40)
This commit was merged in pull request #7.
This commit is contained in:
+6
-6
@@ -22,25 +22,25 @@ If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has a
|
||||
### Run the backend
|
||||
|
||||
```fish
|
||||
hatch shell
|
||||
cista --dev -l :8000
|
||||
uv sync --dev
|
||||
uv run cista --dev -l :8000
|
||||
```
|
||||
|
||||
### And the Vite server (in another terminal)
|
||||
|
||||
```fish
|
||||
cd frontend
|
||||
npm install
|
||||
npm run dev
|
||||
bun install
|
||||
bun run dev
|
||||
```
|
||||
Browse to Vite, which will proxy API requests to port 8000. Both servers live reload changes.
|
||||
|
||||
|
||||
### Type-Check, Compile and Minify for Production
|
||||
|
||||
This is also called by `hatch build` during Python packaging:
|
||||
This is also called by `uv build` during Python packaging:
|
||||
|
||||
```fish
|
||||
npm run build
|
||||
bun run build
|
||||
```
|
||||
|
||||
|
||||
@@ -91,8 +91,7 @@
|
||||
}
|
||||
.headermain,
|
||||
.menu,
|
||||
.rename-button,
|
||||
.suggest-gallery {
|
||||
.rename-button {
|
||||
display: none !important;
|
||||
}
|
||||
.breadcrumb > a {
|
||||
|
||||
@@ -101,7 +101,7 @@ const video = () => ['mkv', 'mp4', 'webm', 'mov', 'avi'].includes(props.doc.ext)
|
||||
const audio = () => ['mp3', 'flac', 'ogg', 'aac'].includes(props.doc.ext)
|
||||
const archive = () => ['zip', 'tar', 'gz', 'bz2', 'xz', '7z', 'rar'].includes(props.doc.ext)
|
||||
const preview = () => (
|
||||
['bmp', 'ico', 'tif', 'tiff', 'pdf'].includes(props.doc.ext) ||
|
||||
['bmp', 'ico', 'tif', 'tiff', 'heic', 'heif', 'pdf', 'epub', 'mobi'].includes(props.doc.ext) ||
|
||||
props.doc.size > 500000 &&
|
||||
['avif', 'webp', 'png', 'jpg', 'jpeg'].includes(props.doc.ext)
|
||||
)
|
||||
|
||||
@@ -37,21 +37,24 @@ export class Doc {
|
||||
return this.url.replace(/^\/#/, '')
|
||||
}
|
||||
get img(): boolean {
|
||||
const ext = this.name.split('.').pop()?.toLowerCase()
|
||||
return ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif', 'svg'].includes(ext || '')
|
||||
// Folders cannot be images
|
||||
if (this.dir) return false
|
||||
return ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif', 'heic', 'heif', 'svg'].includes(this.ext)
|
||||
}
|
||||
get previewable(): boolean {
|
||||
// Folders cannot be previewable
|
||||
if (this.dir) return false
|
||||
if (this.img) return true
|
||||
const ext = this.name.split('.').pop()?.toLowerCase()
|
||||
// Not a comprehensive list, but good enough for now
|
||||
return ['mp4', 'mkv', 'webm', 'ogg', 'mp3', 'flac', 'aac', 'pdf'].includes(ext || '')
|
||||
return ['mp4', 'mkv', 'webm', 'ogg', 'mp3', 'flac', 'aac', 'pdf'].includes(this.ext)
|
||||
}
|
||||
get previewurl(): string {
|
||||
return this.url.replace(/^\/files/, '/preview')
|
||||
}
|
||||
get ext(): string {
|
||||
const ext = this.name.split('.').pop()
|
||||
return ext ? ext.toLowerCase() : ''
|
||||
const dotIndex = this.name.lastIndexOf('.')
|
||||
if (dotIndex === -1 || dotIndex === this.name.length - 1) return ''
|
||||
return this.name.slice(dotIndex + 1).toLowerCase()
|
||||
}
|
||||
}
|
||||
export type errorEvent = {
|
||||
|
||||
@@ -50,12 +50,11 @@ export function formatUnixDate(t: number) {
|
||||
}
|
||||
|
||||
export function getFileExtension(filename: string) {
|
||||
const parts = filename.split('.')
|
||||
if (parts.length > 1) {
|
||||
return parts[parts.length - 1]
|
||||
} else {
|
||||
return '' // No hay extensión
|
||||
const dotIndex = filename.lastIndexOf('.')
|
||||
if (dotIndex === -1 || dotIndex === filename.length - 1) {
|
||||
return '' // No extension
|
||||
}
|
||||
return filename.slice(dotIndex + 1)
|
||||
}
|
||||
interface FileTypes {
|
||||
[key: string]: string[]
|
||||
@@ -68,8 +67,9 @@ const filetypes: FileTypes = {
|
||||
}
|
||||
|
||||
export function getFileType(name: string): string {
|
||||
const ext = name.split('.').pop()?.toLowerCase()
|
||||
if (!ext || ext.length === name.length) return 'unknown'
|
||||
const dotIndex = name.lastIndexOf('.')
|
||||
if (dotIndex === -1 || dotIndex === name.length - 1) return 'unknown'
|
||||
const ext = name.slice(dotIndex + 1).toLowerCase()
|
||||
return Object.keys(filetypes).find(type => filetypes[type].includes(ext)) || 'unknown'
|
||||
}
|
||||
|
||||
|
||||
@@ -13,15 +13,11 @@
|
||||
:path="props.path"
|
||||
:documents="documents"
|
||||
/>
|
||||
<div v-if="!store.prefs.gallery && documents.some(doc => doc.previewable)" class="suggest-gallery">
|
||||
<SvgButton name="eye" taborder=0 @click="() => { store.prefs.gallery = true }"></SvgButton>
|
||||
Gallery View
|
||||
</div>
|
||||
<EmptyFolder :documents=documents :path=props.path />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { watchEffect, ref, computed } from 'vue'
|
||||
import { watchEffect, ref, computed, watch } from 'vue'
|
||||
import { useMainStore } from '@/stores/main'
|
||||
import Router from '@/router/index'
|
||||
import { needleFormat, localeIncludes, collator } from '@/utils'
|
||||
@@ -76,6 +72,10 @@ watchEffect(() => {
|
||||
store.fileExplorer = fileExplorer.value
|
||||
store.query = props.query
|
||||
})
|
||||
|
||||
watch(documents, (docs) => {
|
||||
store.prefs.gallery = docs.some(d => d.previewable)
|
||||
}, { immediate: true })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -89,15 +89,4 @@ watchEffect(() => {
|
||||
text-shadow: 0 0 .3rem #000, 0 0 2rem #0008;
|
||||
color: var(--accent-color);
|
||||
}
|
||||
.suggest-gallery p {
|
||||
font-size: 2rem;
|
||||
color: var(--accent-color);
|
||||
}
|
||||
.suggest-gallery {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -8,7 +8,7 @@ import svgLoader from 'vite-svg-loader'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
|
||||
// Development mode:
|
||||
// npm run dev # Run frontend that proxies to dev_backend
|
||||
// bun run dev # Run frontend that proxies to dev_backend
|
||||
// cista -l :8000 --dev # Run backend
|
||||
const dev_backend = {
|
||||
target: "http://localhost:8000",
|
||||
|
||||
Reference in New Issue
Block a user