1
+ #include " ArduinoFTPClient.h"
2
+ #include " AudioSource.h"
3
+ #include " vector"
4
+
5
+ namespace audio_tools {
6
+
7
+ /* *
8
+ * @brief An AudioSource that uses the
9
+ * https://github.com/pschatzmann/TinyFTPClient library to retrieve files from a
10
+ * FTP Server. You need to provide an FTPClient object to the constructor and
11
+ * make sure that you open it before you access the files. The storage of the
12
+ * expanded file names is done on the heap, so in order to limit the requested
13
+ * memory we can limit the number of files.
14
+ *
15
+ * @ingroup player
16
+ * @author Phil Schatzmann
17
+ * @copyright GPLv3
18
+ */
19
+
20
+
21
+ class AudioSourceFTP : public AudioSource {
22
+ public:
23
+ AudioSourceFTP (FTPClient& client, const char * path, const char * ext,
24
+ int files = 0 ) {
25
+ p_client = &client;
26
+ timeout_auto_next_value = 5000 ;
27
+ if (path) p_path = path;
28
+ setMaxFiles (files);
29
+ }
30
+
31
+ // / Resets the actual data
32
+ void begin ()override {
33
+ TRACED ();
34
+ idx = 0 ;
35
+ files.clear ();
36
+ addDirectory (p_path);
37
+ }
38
+
39
+ // / Resets the actual data
40
+ void end () {
41
+ idx = 0 ;
42
+ files.clear ();
43
+ }
44
+
45
+ // / Returns next audio stream
46
+ Stream* nextStream (int offset) override {
47
+ int tmp_idx = idx + offset;
48
+ if (!isValidIdx (tmp_idx)) return nullptr ;
49
+ return selectStream (tmp_idx);
50
+ };
51
+
52
+ // / Returns previous audio stream
53
+ Stream* previousStream (int offset) override { return nextStream (-offset); };
54
+
55
+ // / Returns audio stream at the indicated index (the index is zero based, so
56
+ // / the first value is 0!)
57
+ Stream* selectStream (int index) override {
58
+ if (!isValidIdx (index )) return nullptr ;
59
+ idx = index ;
60
+ if (file) {
61
+ file.close (); // close the previous file
62
+ }
63
+ file = p_client->open (files[idx].name ());
64
+ return &file;
65
+ }
66
+
67
+ // / Retrieves all files and returns the actual index of the stream
68
+ int index () override { return idx; }
69
+
70
+ // / Returns the FTPFile for the indicated path
71
+ Stream* selectStream (const char * path) override {
72
+ TRACED ();
73
+ files.clear ();
74
+ idx = 0 ;
75
+ addDirectory (path);
76
+ return selectStream (0 );
77
+ }
78
+
79
+ // / provides the actual stream (e.g. file) name or url
80
+ const char * toStr () override {
81
+ return file.name ();
82
+ }
83
+
84
+ // / Defines the max number of files (if value is >0)
85
+ void setMaxFiles (int maxCount) { max_files = maxCount; }
86
+
87
+ // / Adds all the files of a directory
88
+ bool addDirectory (const char * path) {
89
+ TRACED ();
90
+ if (p_client == nullptr ) return false ;
91
+ FTPFile dir = p_client->open (path);
92
+ addFiles (dir, 1 );
93
+ return true ;
94
+ }
95
+
96
+ // / Returns the number of available files
97
+ size_t size () { return files.size (); }
98
+
99
+ protected:
100
+ std::vector<FTPFile> files;
101
+ FTPClient* p_client = nullptr ;
102
+ FTPFile file;
103
+ int idx = 0 ;
104
+ size_t max_files = 0 ;
105
+ const char * p_ext = nullptr ;
106
+ const char * p_path = " /" ;
107
+ bool is_first = true ;
108
+
109
+ // / Adds all files recursively
110
+ void addFiles (FTPFile& dir, int level) {
111
+ if (!endsWith (dir.name (), p_ext)) {
112
+ LOGI (" adding file %s" , dir.name ());
113
+ files.push_back (std::move (dir));
114
+ } else {
115
+ for (const auto & file : p_client->ls (dir.name ())) {
116
+ if (endsWith (file.name (), p_ext)) {
117
+ LOGI (" adding file %s" , file.name ());
118
+ files.push_back (std::move (file));
119
+ }
120
+ if (max_files > 0 && files.size () >= max_files) {
121
+ LOGI (" max files reached: %d" , max_files);
122
+ return ; // stop if we reached the max number of files
123
+ }
124
+ }
125
+ }
126
+ }
127
+
128
+ bool isValidIdx (int index) {
129
+ if (index < 0 ) return false ;
130
+ if (index >= files.size ()) {
131
+ LOGE (" index %d is out of range (size: %d)" , index , files.size ());
132
+ return false ;
133
+ }
134
+ return true ;
135
+ }
136
+
137
+ bool endsWith (const char * file, const char * ext) {
138
+ if (file == nullptr ) return false ;
139
+ if (p_ext == nullptr ) return true ;
140
+ return (StrView (file).endsWith (ext));
141
+ }
142
+ };
143
+
144
+ } // namespace audio_tools
0 commit comments