Skip to content

Commit 5f78dad

Browse files
medialib: fsmonitor wip
1 parent 676b879 commit 5f78dad

6 files changed

Lines changed: 338 additions & 15 deletions

File tree

osx/deadbeef.xcodeproj/project.pbxproj

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6290,7 +6290,6 @@
62906290
2D78C55827568B4A00F96F9D /* medialibscanner.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = medialibscanner.c; sourceTree = "<group>"; };
62916291
2D78C55B27568D9600F96F9D /* medialibtree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = medialibtree.h; sourceTree = "<group>"; };
62926292
2D78C55C27568D9600F96F9D /* medialibtree.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = medialibtree.c; sourceTree = "<group>"; };
6293-
2D78C565275698D400F96F9D /* medialibfilesystem_inotify.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = medialibfilesystem_inotify.c; sourceTree = "<group>"; };
62946293
2D78C5672756990B00F96F9D /* medialibfilesystem_stub.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = medialibfilesystem_stub.c; sourceTree = "<group>"; };
62956294
2D7C1FAB2946001B00163538 /* ShaderRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShaderRenderer.h; sourceTree = "<group>"; };
62966295
2D7C1FAC2946001B00163538 /* ShaderRenderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ShaderRenderer.m; sourceTree = "<group>"; };
@@ -6995,6 +6994,9 @@
69956994
2DBCA69827944B2200D7432F /* COPYING.GPLv2 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = COPYING.GPLv2; path = ../../COPYING.GPLv2; sourceTree = "<group>"; };
69966995
2DBCA69927944B2200D7432F /* COPYING.LGPLv2.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = COPYING.LGPLv2.1; path = ../../COPYING.LGPLv2.1; sourceTree = "<group>"; };
69976996
2DBCA69C27944BB600D7432F /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ChangeLog; path = ../../ChangeLog; sourceTree = "<group>"; };
6997+
2DBD235A2F3FB3B1004F9EFF /* fsmonitor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fsmonitor.h; sourceTree = "<group>"; };
6998+
2DBD235C2F3FB408004F9EFF /* fsmonitor.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = fsmonitor.c; sourceTree = "<group>"; };
6999+
2DBD235E2F3FB460004F9EFF /* medialibfilesystem_inotify.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = medialibfilesystem_inotify.c; sourceTree = "<group>"; };
69987000
2DBF3D3F270868D400023138 /* MainContentViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainContentViewController.xib; sourceTree = "<group>"; };
69997001
2DBF3D4127086AA900023138 /* MainContentViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MainContentViewController.h; sourceTree = "<group>"; };
70007002
2DBF3D4227086AA900023138 /* MainContentViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MainContentViewController.m; sourceTree = "<group>"; };
@@ -10961,6 +10963,8 @@
1096110963
2D887BC524B1C82A0078392F /* medialib */ = {
1096210964
isa = PBXGroup;
1096310965
children = (
10966+
2DBD23592F3FB395004F9EFF /* apple */,
10967+
2DBD23582F3FB38A004F9EFF /* linux */,
1096410968
2D20924D2A9A077800CDBB2B /* scriptable_tfquery.c */,
1096510969
2D20924C2A9A077800CDBB2B /* scriptable_tfquery.h */,
1096610970
2D887BC724B1C82A0078392F /* medialib.c */,
@@ -10969,8 +10973,6 @@
1096910973
2D78C54227568A4D00F96F9D /* medialibcommon.h */,
1097010974
2D78C53B2756892300F96F9D /* medialibdb.c */,
1097110975
2D78C53A2756892300F96F9D /* medialibdb.h */,
10972-
2D78C565275698D400F96F9D /* medialibfilesystem_inotify.c */,
10973-
2DB4E0682AE18ECA00028624 /* medialibfilesystem_mac.m */,
1097410976
2D78C5672756990B00F96F9D /* medialibfilesystem_stub.c */,
1097510977
2D78C53E27568A1300F96F9D /* medialibfilesystem.h */,
1097610978
2D78C55827568B4A00F96F9D /* medialibscanner.c */,
@@ -12273,6 +12275,24 @@
1227312275
name = Assets;
1227412276
sourceTree = "<group>";
1227512277
};
12278+
2DBD23582F3FB38A004F9EFF /* linux */ = {
12279+
isa = PBXGroup;
12280+
children = (
12281+
2DBD235E2F3FB460004F9EFF /* medialibfilesystem_inotify.c */,
12282+
2DBD235C2F3FB408004F9EFF /* fsmonitor.c */,
12283+
2DBD235A2F3FB3B1004F9EFF /* fsmonitor.h */,
12284+
);
12285+
path = linux;
12286+
sourceTree = "<group>";
12287+
};
12288+
2DBD23592F3FB395004F9EFF /* apple */ = {
12289+
isa = PBXGroup;
12290+
children = (
12291+
2DB4E0682AE18ECA00028624 /* medialibfilesystem_mac.m */,
12292+
);
12293+
path = apple;
12294+
sourceTree = "<group>";
12295+
};
1227612296
2DC657D0274957FE00583E14 /* Tabs */ = {
1227712297
isa = PBXGroup;
1227812298
children = (

plugins/medialib/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ medialib_la_SOURCES =\
99
medialibdb.c\
1010
medialibdb.h\
1111
medialibfilesystem.h\
12-
medialibfilesystem_inotify.c\
12+
linux/medialibfilesystem_inotify.c\
1313
medialibscanner.c\
1414
medialibscanner.h\
1515
medialibsource.c\
File renamed without changes.

plugins/medialib/linux/fsmonitor.c

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/*
2+
DeaDBeeF -- the music player
3+
Copyright (C) 2009-2025 Oleksiy Yakovenko and other contributors
4+
5+
This software is provided 'as-is', without any express or implied
6+
warranty. In no event will the authors be held liable for any damages
7+
arising from the use of this software.
8+
9+
Permission is granted to anyone to use this software for any purpose,
10+
including commercial applications, and to alter it and redistribute it
11+
freely, subject to the following restrictions:
12+
13+
1. The origin of this software must not be misrepresented; you must not
14+
claim that you wrote the original software. If you use this software
15+
in a product, an acknowledgment in the product documentation would be
16+
appreciated but is not required.
17+
18+
2. Altered source versions must be plainly marked as such, and must not be
19+
misrepresented as being the original software.
20+
21+
3. This notice may not be removed or altered from any source distribution.
22+
*/
23+
24+
#include "fsmonitor.h"
25+
26+
#include <sys/inotify.h>
27+
#include <dirent.h>
28+
#include <unistd.h>
29+
#include <limits.h>
30+
#include <stdlib.h>
31+
#include <string.h>
32+
#include <dispatch/dispatch.h>
33+
34+
typedef struct node {
35+
int wd;
36+
char *path;
37+
struct node *next;
38+
} node_t;
39+
40+
struct ddb_fsmonitor_s {
41+
int fd;
42+
dispatch_queue_t queue;
43+
dispatch_source_t readSource;
44+
45+
node_t *nodes;
46+
47+
ddb_fsmonitor_callback_t cb;
48+
void *userdata;
49+
};
50+
51+
#define DDB_FSMON_MASK \
52+
(IN_CREATE | IN_DELETE | IN_MODIFY | \
53+
IN_MOVED_FROM | IN_MOVED_TO | \
54+
IN_ATTRIB | IN_DELETE_SELF | IN_MOVE_SELF)
55+
56+
static node_t *
57+
node_find(ddb_fsmonitor_t *m, int wd) {
58+
for (node_t *n = m->nodes; n; n = n->next)
59+
if (n->wd == wd) return n;
60+
return NULL;
61+
}
62+
63+
static void
64+
node_add(ddb_fsmonitor_t *m, int wd, const char *path) {
65+
node_t *n = malloc(sizeof(*n));
66+
n->wd = wd;
67+
n->path = strdup(path);
68+
n->next = m->nodes;
69+
m->nodes = n;
70+
}
71+
72+
static void
73+
node_remove(ddb_fsmonitor_t *m, int wd) {
74+
node_t **pp = &m->nodes;
75+
while (*pp) {
76+
if ((*pp)->wd == wd) {
77+
node_t *dead = *pp;
78+
*pp = dead->next;
79+
free(dead->path);
80+
free(dead);
81+
return;
82+
}
83+
pp = &(*pp)->next;
84+
}
85+
}
86+
87+
static void
88+
add_recursive(ddb_fsmonitor_t *m, const char *path) {
89+
int wd = inotify_add_watch(m->fd, path, DDB_FSMON_MASK);
90+
if (wd < 0) return;
91+
92+
node_add(m, wd, path);
93+
94+
DIR *d = opendir(path);
95+
if (!d) return;
96+
97+
struct dirent *e;
98+
while ((e = readdir(d))) {
99+
if (e->d_type == DT_DIR &&
100+
strcmp(e->d_name, ".") &&
101+
strcmp(e->d_name, "..")) {
102+
103+
char buf[PATH_MAX];
104+
snprintf(buf, sizeof(buf), "%s/%s", path, e->d_name);
105+
add_recursive(m, buf);
106+
}
107+
}
108+
109+
closedir(d);
110+
}
111+
112+
static void
113+
handle_events(ddb_fsmonitor_t *m) {
114+
char buf[8192];
115+
116+
ssize_t len;
117+
while ((len = read(m->fd, buf, sizeof(buf))) > 0) {
118+
119+
size_t i = 0;
120+
while (i < len) {
121+
struct inotify_event *ev =
122+
(struct inotify_event *)&buf[i];
123+
124+
node_t *node = node_find(m, ev->wd);
125+
126+
// New directory → add watch
127+
if (node &&
128+
(ev->mask & IN_CREATE) &&
129+
(ev->mask & IN_ISDIR)) {
130+
131+
char p[PATH_MAX];
132+
snprintf(p, sizeof(p), "%s/%s",
133+
node->path, ev->name);
134+
add_recursive(m, p);
135+
}
136+
137+
// Watch removed / directory gone
138+
if (ev->mask & IN_IGNORED ||
139+
ev->mask & IN_DELETE_SELF ||
140+
ev->mask & IN_MOVE_SELF) {
141+
142+
node_remove(m, ev->wd);
143+
}
144+
145+
// Notify user
146+
if (m->cb)
147+
m->cb(m->userdata);
148+
149+
i += sizeof(struct inotify_event) + ev->len;
150+
}
151+
}
152+
}
153+
154+
ddb_fsmonitor_t *
155+
ddb_fsmonitor_create(const char **paths,
156+
size_t count,
157+
ddb_fsmonitor_callback_t cb,
158+
void *userdata)
159+
{
160+
ddb_fsmonitor_t *m = calloc(1, sizeof(*m));
161+
162+
m->fd = inotify_init1(IN_NONBLOCK);
163+
m->queue = dispatch_queue_create("ddb.fsmonitor", 0);
164+
m->cb = cb;
165+
m->userdata = userdata;
166+
167+
for (size_t i = 0; i < count; i++)
168+
add_recursive(m, paths[i]);
169+
170+
m->readSource =
171+
dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
172+
m->fd, 0, m->queue);
173+
174+
dispatch_source_set_event_handler(m->readSource, ^{
175+
handle_events(m);
176+
});
177+
178+
dispatch_resume(m->readSource);
179+
180+
return m;
181+
}
182+
183+
void
184+
ddb_fsmonitor_free(ddb_fsmonitor_t *m) {
185+
if (!m) return;
186+
187+
dispatch_source_cancel(m->readSource);
188+
close(m->fd);
189+
190+
node_t *n = m->nodes;
191+
while (n) {
192+
node_t *next = n->next;
193+
free(n->path);
194+
free(n);
195+
n = next;
196+
}
197+
198+
free(m);
199+
}

plugins/medialib/medialibfilesystem_inotify.c renamed to plugins/medialib/linux/fsmonitor.h

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
DeaDBeeF -- the music player
3-
Copyright (C) 2009-2021 Oleksiy Yakovenko and other contributors
3+
Copyright (C) 2009-2025 Oleksiy Yakovenko and other contributors
44
55
This software is provided 'as-is', without any express or implied
66
warranty. In no event will the authors be held liable for any damages
@@ -21,18 +21,22 @@
2121
3. This notice may not be removed or altered from any source distribution.
2222
*/
2323

24-
#include <stdio.h>
25-
#include "medialibsource.h"
24+
#ifndef __DDB_FSMONITOR
25+
#define __DDB_FSMONITOR
2626

27-
struct ml_watch_s {
28-
};
27+
#include <stddef.h>
2928

30-
ml_watch_t *
31-
ml_watch_fs_start (struct json_t *musicpathsJson, void (*eventCallback)(void *), void *userdata) {
32-
return NULL;
33-
}
29+
typedef struct ddb_fsmonitor_s ddb_fsmonitor_t;
30+
31+
typedef void (*ddb_fsmonitor_callback_t)(void *userdata);
32+
33+
ddb_fsmonitor_t *
34+
ddb_fsmonitor_create(const char **paths,
35+
size_t count,
36+
ddb_fsmonitor_callback_t cb,
37+
void *userdata);
3438

3539
void
36-
ml_watch_fs_stop (ml_watch_t *wrapper) {
37-
}
40+
ddb_fsmonitor_free(ddb_fsmonitor_t *m);
3841

42+
#endif

0 commit comments

Comments
 (0)