diff --git a/src/app/SidebarNav.vue b/src/app/SidebarNav.vue
index 8fdb47d..3e10fc8 100644
--- a/src/app/SidebarNav.vue
+++ b/src/app/SidebarNav.vue
@@ -47,6 +47,10 @@
Radio
+
+ Files
+
+
diff --git a/src/library/file/Files.vue b/src/library/file/Files.vue
new file mode 100644
index 0000000..837e548
--- /dev/null
+++ b/src/library/file/Files.vue
@@ -0,0 +1,118 @@
+
+
+
+
+ Files
+
+
+
+
+
+
+
+
+
+ |
+
+ ..
+ |
+
+
+
+
+ |
+
+ {{ dir.name }}
+ |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/shared/api.ts b/src/shared/api.ts
index 65fb020..b494fdf 100644
--- a/src/shared/api.ts
+++ b/src/shared/api.ts
@@ -73,6 +73,16 @@ export interface PodcastEpisode {
description: string
}
+export interface Directory {
+ id: string
+ name: string
+ tracks: Track[]
+ directories: {
+ id: string
+ name: string
+ }[]
+}
+
export interface Playlist {
id: string
name: string
@@ -366,6 +376,55 @@ export class API {
return this.fetch('rest/deletePodcastChannel', { id })
}
+ async getDirectory(path: string): Promise {
+ const parts = path.split('/')
+ const musicFolderId = parts[0]
+ const id = parts.length > 1 ? parts[parts.length - 1] : ''
+
+ if (musicFolderId === '') {
+ const response = await this.fetch('rest/getMusicFolders')
+ const items = response?.musicFolders?.musicFolder ?? []
+ return {
+ id: '',
+ name: '',
+ tracks: [],
+ directories: items.map((item: any) => ({ id: `${item?.id}`, name: item?.name, })),
+ }
+ }
+
+ if (id === '') {
+ const response = await this.fetch('rest/getIndexes', { musicFolderId })
+ const directories = (response?.indexes?.index ?? []).flatMap((item: any) => [
+ ...(item?.artist || []).map((i: any) => ({ id: i.id, name: i.name }))
+ ])
+ const tracks = (response?.indexes?.child ?? []).map(this.normalizeTrack, this)
+ return {
+ id: musicFolderId,
+ name: musicFolderId,
+ tracks,
+ directories
+ }
+ }
+
+ const response = await this.fetch('rest/getMusicDirectory', { id })
+ const items = response?.directory?.child ?? []
+
+ const directories = items
+ .filter((item: any) => item.isDir)
+ .map((item: any) => ({ id: item.id, name: item.title }))
+
+ const tracks = items
+ .filter((item: any) => !item.isDir && item.type === 'music' && item?.duration > 0)
+ .map(this.normalizeTrack, this)
+
+ return {
+ id: response.directory.id,
+ name: response.directory.name,
+ tracks,
+ directories,
+ }
+ }
+
async scan(): Promise {
return this.fetch('rest/startScan')
}
diff --git a/src/shared/components/Icon.vue b/src/shared/components/Icon.vue
index e2a1296..d8a4bc2 100644
--- a/src/shared/components/Icon.vue
+++ b/src/shared/components/Icon.vue
@@ -23,6 +23,8 @@
import iconDiscover from '@iconify-icons/bi/card-text'
import iconDownload from '@iconify-icons/bi/download'
import iconEdit from '@iconify-icons/bi/pencil-square'
+ import iconFiles from '@iconify-icons/bi/files'
+ import iconFolder from '@iconify-icons/bi/folder'
import iconHeart from '@iconify-icons/bi/heart'
import iconHeartFill from '@iconify-icons/bi/heart-fill'
import iconLibrary from '@iconify-icons/bi/collection'
@@ -54,6 +56,8 @@
discover: iconDiscover.body,
download: iconDownload.body,
edit: iconEdit.body,
+ files: iconFiles.body,
+ folder: iconFolder.body,
heart: iconHeart.body,
'heart-fill': iconHeartFill.body,
library: iconLibrary.body,
diff --git a/src/shared/router.ts b/src/shared/router.ts
index 1c26f09..b444f76 100644
--- a/src/shared/router.ts
+++ b/src/shared/router.ts
@@ -17,6 +17,7 @@ import PlaylistLibrary from '@/library/playlist/PlaylistLibrary.vue'
import SearchResult from '@/library/search/SearchResult.vue'
import { AuthService } from '@/auth/service'
import ArtistTracks from '@/library/artist/ArtistTracks.vue'
+import Files from '@/library/file/Files.vue'
export function setupRouter(auth: AuthService) {
const router = new Router({
@@ -118,6 +119,12 @@ export function setupRouter(auth: AuthService) {
component: PodcastDetails,
props: true,
},
+ {
+ name: 'files',
+ path: '/files/:path*',
+ component: Files,
+ props: true,
+ },
{
name: 'playlists',
path: '/playlists/:sort?',