Project

General

Profile

m3u.cc.diff

git diff - Jim Turner, July 12, 2022 21:34

View differences:

src/m3u/m3u.cc
18 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 19
 */
20 20

  
21
#include <stdlib.h>
21 22
#include <string.h>
22 23

  
24
#include <libaudcore/preferences.h>
23 25
#include <libaudcore/audstrings.h>
24 26
#include <libaudcore/i18n.h>
25 27
#include <libaudcore/plugin.h>
28
#include <libaudcore/runtime.h>
26 29

  
27 30
static const char * const m3u_exts[] = {"m3u", "m3u8"};
28 31

  
29 32
class M3ULoader : public PlaylistPlugin
30 33
{
31 34
public:
32
    static constexpr PluginInfo info = {N_("M3U Playlists"), PACKAGE};
35
    static const PreferencesWidget widgets[];
36
    static const PluginPreferences prefs;
37
    static constexpr PluginInfo info = {
38
        N_("M3U Playlists"),
39
        PACKAGE,
40
        nullptr,
41
        & prefs
42
    };
33 43

  
34 44
    constexpr M3ULoader () : PlaylistPlugin (info, m3u_exts, true) {}
35 45

  
......
58 68
bool M3ULoader::load (const char * filename, VFSFile & file, String & title,
59 69
 Index<PlaylistAddItem> & items)
60 70
{
71
    enum extDataType {NA, ALB, ART, GENRE, INF};
72
    bool Extended_m3u = false;
73
    bool firstline = true;
74
    bool refreshTuple = true;
75
    Tuple tuple = Tuple ();
76

  
61 77
    Index<char> text = file.read_all ();
62 78
    if (! text.len ())
63 79
        return false;
......
75 91
        while (* parse == ' ' || * parse == '\t')
76 92
            parse ++;
77 93

  
78
        if (* parse && * parse != '#')
94
        if (* parse)
79 95
        {
80
            StringBuf s = uri_construct (parse, filename);
81
            if (s)
82
                items.append (String (s));
96
            if (* parse != '#')
97
            {
98
                String s = String (uri_construct (parse, filename));
99

  
100
                if (s && s[0])
101
                {
102
                    if (Extended_m3u)
103
                    {
104
                        tuple.set_filename (s);
105
                        tuple.set_state (Tuple::Valid);
106
                        items.append (s, std::move (tuple));
107
                        refreshTuple = true;
108
                    }
109
                    else
110
                        items.append (s);
111
                }
112
            }
113
            else if (Extended_m3u)
114
            {
115
                if (! strncmp (parse, "#EXT-X-", 7))  // WE'RE AN "HLS" STREAM, STAND DOWN & LET ffaudio PLUGIN HANDLE!:
116
                {
117
                    AUDINFO ("i:HLS STREAM(%s) - STOP PARSING & JUST ADD PLAYLIST AS SINGLE ENTRY!\n", filename);
118
                    items.append (String (filename));
119
                    break;
120
                }
121
                else if (! strncmp (parse, "#EXT", 4))  // WE'RE A DATA LINE (EXTENDED M3U):
122
                {
123
                    extDataType extData = NA;
124
                    if (refreshTuple)
125
                    {
126
                        tuple = Tuple ();
127
                        refreshTuple = false;
128
                    }
129

  
130
                    if (! strncmp (parse, "#EXTINF", 7))        // SET [LENGTH,] TITLE
131
                        extData = INF;
132
                    else if (! strncmp (parse, "#EXTGENRE", 9)) // SET GENRE
133
                    {
134
                        parse += 2;
135
                        extData = GENRE;
136
                    }
137
                    else if (! strncmp (parse, "#EXTALB", 7))   // SET ALBUM
138
                        extData = ALB;
139
                    else if (! strncmp (parse, "#EXTART", 7))   // SET ARTIST
140
                        extData = ART;
141

  
142
                    parse += 7;
143
                    if (parse < next && * parse == ':')
144
                    {
145
                        ++parse;
146
                        while (parse < next && * parse == ' ')
147
                            ++parse;
148

  
149
                        if (* parse && parse < next)
150
                        {
151
                            Index<String> headerparts = str_list_to_index (parse, ",");
152
                            if (extData == INF && headerparts.len () > 1)
153
                            {
154
                                int tlen = atoi (headerparts[0]) * 1000;
155
                                if (tlen <= 0)
156
                                    tuple.unset (Tuple::Length);
157
                                else
158
                                    tuple.set_int (Tuple::Length, tlen);
159

  
160
                                // FIND THE TITLE AND MOVE PAST ANY LEADING SPACES IN IT:
161
                                char * c = parse;
162
                                while (c < next && * c != ',')
163
                                    ++c;
164
                                if (c < next && * c)
165
                                    ++c;
166
                                while (c < next && * c == ' ')
167
                                    ++c;
168
                                if (*c && c < next)
169
                                    tuple.set_str (Tuple::Title, c);
170
                            }
171
                            else if (headerparts.len () > 0)
172
                            {
173
                                if (extData == INF)
174
                                {
175
                                    tuple.unset (Tuple::Length);
176
                                    tuple.set_str (Tuple::Title, headerparts[0]);
177
                                }
178
                                else if (extData == ART)
179
                                    tuple.set_str (Tuple::Artist, headerparts[0]);
180
                                else if (extData == ALB)
181
                                    tuple.set_str (Tuple::Album, headerparts[0]);
182
                                else if (extData == GENRE)
183
                                    tuple.set_str (Tuple::Genre, headerparts[0]);
184
                            }
185
                        }
186
                    }
187
                }
188
            }
189
            else if (firstline && ! strncmp (parse, "#EXTM3U", 7))  // WE'RE AN EXTENDED M3U:
190
                Extended_m3u = true;
83 191
        }
84 192

  
193
        firstline = false;
85 194
        parse = next;
86 195
    }
87 196

  
......
91 200
bool M3ULoader::save (const char * filename, VFSFile & file, const char * title,
92 201
 const Index<PlaylistAddItem> & items)
93 202
{
203
    bool Extended_m3u = aud_get_bool ("m3u", "saveas_extended_m3u");
204

  
205
    if (Extended_m3u && file.fwrite (str_copy("#EXTM3U\n"), 1, 8) != 8)
206
        return false;
207

  
94 208
    for (auto & item : items)
95 209
    {
96 210
        StringBuf path = uri_deconstruct (item.filename, filename);
211
        if (Extended_m3u && item.tuple.state () == Tuple::Valid)
212
        {
213
            int tuplen = item.tuple.get_int (Tuple::Length);
214
            if (tuplen >= 0)
215
                tuplen /= 1000;
216

  
217
            {
218
                String tupstr = item.tuple.get_str (Tuple::Title);
219
                if (! tupstr)
220
                    tupstr = String (filename_get_base (item.filename));
221
                StringBuf line = str_printf ("#EXTINF:%d, %s\n", tuplen, (const char *) tupstr);
222
                if (file.fwrite (line, 1, line.len ()) != line.len ())
223
                    return false;
224
            }
225
            {
226
                String tupstr = item.tuple.get_str (Tuple::Artist);
227
                if (tupstr && tupstr[0])
228
                {
229
                    StringBuf line = str_printf ("#EXTART:%s\n", (const char *) tupstr);
230
                    if (file.fwrite (line, 1, line.len ()) != line.len ())
231
                        AUDERR ("m3u: could not write artist to extended m3u file?!\n");
232
                }
233
            }
234
            {
235
                String tupstr = item.tuple.get_str (Tuple::Album);
236
                if (tupstr && tupstr[0])
237
                {
238
                    StringBuf line = str_printf ("#EXTALB:%s\n", (const char *) tupstr);
239
                    if (file.fwrite (line, 1, line.len ()) != line.len ())
240
                        AUDERR ("m3u: could not write album to extended m3u file?!\n");
241
                }
242
            }
243
            {
244
                String tupstr = item.tuple.get_str (Tuple::Genre);
245
                if (tupstr && tupstr[0])
246
                {
247
                    StringBuf line = str_printf ("#EXTGENRE:%s\n", (const char *) tupstr);
248
                    if (file.fwrite (line, 1, line.len ()) != line.len ())
249
                        AUDERR ("m3u: could not write genre to extended m3u file?!\n");
250
                }
251
            }
252
        }
97 253
        StringBuf line = str_concat ({path, "\n"});
98 254
        if (file.fwrite (line, 1, line.len ()) != line.len ())
99 255
            return false;
......
101 257

  
102 258
    return true;
103 259
}
260

  
261
const PreferencesWidget M3ULoader::widgets[] = {
262
    WidgetLabel(N_("<b>M3U Configuration</b>")),
263
    WidgetCheck(N_("Save in Extended M3U format?"), WidgetBool("m3u", "saveas_extended_m3u")),
264
};
265

  
266
const PluginPreferences M3ULoader::prefs = {{widgets}};