Example #1
0
void
playqueue_remove (playItem_t *it) {
    pl_lock ();
    for (;;) {
        int i;
        for (i = 0; i < playqueue_count; i++) {
            if (playqueue[i] == it) {
                if (i < playqueue_count-1) {
                    memmove (&playqueue[i], &playqueue[i+1], (playqueue_count-i) * sizeof (playItem_t*));
                    messagepump_push (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_PLAYQUEUE, 0);
                }
                else {
                    playqueue_send_trackinfochanged (it);
                }
                pl_item_unref (it);
                playqueue_count--;
                break;
            }
        }
        if (i == playqueue_count) {
            break;
        }
    }
    pl_unlock ();
}
Example #2
0
void
playqueue_clear (void) {
    pl_lock ();
    for (int i = 0; i < playqueue_count; i++) {
        pl_item_unref (playqueue[i]);
        playqueue[i] = NULL;
    }
    playqueue_count = 0;
    pl_unlock ();
    messagepump_push (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_PLAYQUEUE, 0);
}
Example #3
0
void
streamer_set_dsp_chain_real (ddb_dsp_context_t *chain) {
    dsp_chain_free (dsp_chain);
    dsp_chain = chain;
    eq = NULL;
    streamer_dsp_postinit ();

    streamer_dsp_chain_save();
    streamer_reset (1);

    messagepump_push (DB_EV_DSPCHAINCHANGED, 0, 0, 0);
}
Example #4
0
void
playqueue_remove_nth (int n) {
    pl_lock ();
    playItem_t *it = playqueue[n];
    if (n < playqueue_count-1) {
        memmove (playqueue + n, playqueue + n + 1, (playqueue_count-n) * sizeof (playItem_t*));
    }
    playqueue_count--;

    pl_item_unref (it);
    pl_unlock ();
    messagepump_push (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_PLAYQUEUE, 0);
}
Example #5
0
void
playqueue_insert_at (int n, playItem_t *it) {
    if (playqueue_count == PLAYQUEUE_SIZE) {
        trace ("playqueue is full\n");
        return;
    }
    pl_lock ();
    if (n == playqueue_count) {
        playqueue_push(it);
        pl_unlock ();
        return;
    }
    memmove (playqueue+n+1, playqueue+n, (playqueue_count - n) * sizeof (playItem_t *));
    playqueue[n] = it;
    pl_item_ref (it);
    playqueue_count++;
    pl_unlock ();
    messagepump_push (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_PLAYQUEUE, 0);
}
Example #6
0
void
playqueue_pop (void) {
    if (!playqueue_count) {
        return;
    }
    pl_lock ();
    if (playqueue_count == 1) {
        playqueue_count = 0;
        playqueue_send_trackinfochanged (playqueue[0]);
        pl_item_unref (playqueue[0]);
        pl_unlock ();
        return;
    }
    playItem_t *it = playqueue[0];
    memmove (&playqueue[0], &playqueue[1], (playqueue_count-1) * sizeof (playItem_t*));
    playqueue_count--;
    pl_item_unref (it);
    pl_unlock ();
    messagepump_push (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_PLAYQUEUE, 0);
}
Example #7
0
void
server_loop (void *ctx) {
    fd_set rds;
    int ret;
    struct timeval timeout = {0, 0};

    FD_ZERO(&rds);
    while (!server_terminate) {
        FD_SET(srv_socket, &rds);
        timeout.tv_usec = 500000;
        if ((ret = select(srv_socket + 1, &rds, NULL, NULL, &timeout)) < 0 && errno != EINTR) {
            perror("select");
            exit (-1);
        }
        if (ret > 0) {
            if (server_update () < 0) {
                messagepump_push (DB_EV_TERMINATE, 0, 0, 0);
            }
        }
    }
}
Example #8
0
int
server_update (void) {
    // handle remote stuff
    int t = sizeof (srv_remote);
    unsigned s2;
    s2 = accept(srv_socket, (struct sockaddr *)&srv_remote, &t);
    if (s2 == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
        perror("accept");
        return -1;
    }
    else if (s2 != -1) {
        int size = -1;
        char *buf = read_entire_message(s2, &size);
        char sendback[1024] = "";
        if (size > 0) {
            if (size == 1 && buf[0] == 0) {
                // FIXME: that should be called right after activation of gui plugin
                messagepump_push (DB_EV_ACTIVATED, 0, 0, 0);
            }
            else {
                server_exec_command_line (buf, size, sendback, sizeof (sendback));
            }
        }
        if (sendback[0]) {
            // send nowplaying back to client
            send (s2, sendback, strlen (sendback)+1, 0);
        }
        else {
            send (s2, "", 1, 0);
        }
        close(s2);

        if (buf) {
            free(buf);
        }
    }
    return 0;
}
Example #9
0
int
main (int argc, char *argv[]) {
    int portable = 0;
#if STATICLINK
    int staticlink = 1;
#else
    int staticlink = 0;
#endif
#if PORTABLE
    portable = 1;
    if (!realpath (argv[0], dbinstalldir)) {
        strcpy (dbinstalldir, argv[0]);
    }
    char *e = strrchr (dbinstalldir, '/');
    if (e) {
        *e = 0;
    }
    else {
        fprintf (stderr, "couldn't determine install folder from path %s\n", argv[0]);
        exit (-1);
    }
#else
    if (!realpath (argv[0], dbinstalldir)) {
        strcpy (dbinstalldir, argv[0]);
    }
    char *e = strrchr (dbinstalldir, '/');
    if (e) {
        *e = 0;
        struct stat st;
        char checkpath[PATH_MAX];
        snprintf (checkpath, sizeof (checkpath), "%s/.ddb_portable", dbinstalldir);
        if (!stat (checkpath, &st)) {
            if (S_ISREG (st.st_mode)) {
                portable = 1;
            }
        }
    }
    if (!portable) {
        strcpy (dbinstalldir, PREFIX);
    }
#endif

#ifdef __GLIBC__
    signal (SIGSEGV, sigsegv_handler);
#endif
    setlocale (LC_ALL, "");
    setlocale (LC_NUMERIC, "C");
#ifdef ENABLE_NLS
//    fprintf (stderr, "enabling gettext support: package=" PACKAGE ", dir=" LOCALEDIR "...\n");
    if (portable) {
        char localedir[PATH_MAX];
        snprintf (localedir, sizeof (localedir), "%s/locale", dbinstalldir);
        bindtextdomain (PACKAGE, localedir);
    }
    else {
        bindtextdomain (PACKAGE, LOCALEDIR);
    }
	bind_textdomain_codeset (PACKAGE, "UTF-8");
	textdomain (PACKAGE);
#endif

    fprintf (stderr, "starting deadbeef " VERSION "%s%s\n", staticlink ? " [static]" : "", portable ? " [portable]" : "");
    srand (time (NULL));
#ifdef __linux__
    prctl (PR_SET_NAME, "deadbeef-main", 0, 0, 0, 0);
#endif

#if PORTABLE_FULL
    if (snprintf (confdir, sizeof (confdir), "%s/config", dbinstalldir) > sizeof (confdir)) {
        fprintf (stderr, "fatal: too long install path %s\n", dbinstalldir);
        return -1;
    }

    strcpy (dbconfdir, confdir);
#else
    char *homedir = getenv ("HOME");
    if (!homedir) {
        fprintf (stderr, "unable to find home directory. stopping.\n");
        return -1;
    }

    char *xdg_conf_dir = getenv ("XDG_CONFIG_HOME");
    if (xdg_conf_dir) {
        if (snprintf (confdir, sizeof (confdir), "%s", xdg_conf_dir) > sizeof (confdir)) {
            fprintf (stderr, "fatal: XDG_CONFIG_HOME value is too long: %s\n", xdg_conf_dir);
            return -1;
        }
    }
    else {
        if (snprintf (confdir, sizeof (confdir), "%s/.config", homedir) > sizeof (confdir)) {
            fprintf (stderr, "fatal: HOME value is too long: %s\n", homedir);
            return -1;
        }
    }
    if (snprintf (dbconfdir, sizeof (dbconfdir), "%s/deadbeef", confdir) > sizeof (dbconfdir)) {
        fprintf (stderr, "fatal: out of memory while configuring\n");
        return -1;
    }
    mkdir (confdir, 0755);
#endif


    if (portable) {
        if (snprintf (dbdocdir, sizeof (dbdocdir), "%s/doc", dbinstalldir) > sizeof (dbdocdir)) {
            fprintf (stderr, "fatal: too long install path %s\n", dbinstalldir);
            return -1;
        }
#ifdef HAVE_COCOAUI
        char respath[PATH_MAX];
        cocoautil_get_resources_path (respath, sizeof (respath));
        if (snprintf (dbplugindir, sizeof (dbplugindir), "%s", respath) > sizeof (dbplugindir)) {
            fprintf (stderr, "fatal: too long install path %s\n", dbinstalldir);
            return -1;
        }
#else
        if (snprintf (dbplugindir, sizeof (dbplugindir), "%s/plugins", dbinstalldir) > sizeof (dbplugindir)) {
            fprintf (stderr, "fatal: too long install path %s\n", dbinstalldir);
            return -1;
        }
#endif
        if (snprintf (dbpixmapdir, sizeof (dbpixmapdir), "%s/pixmaps", dbinstalldir) > sizeof (dbpixmapdir)) {
            fprintf (stderr, "fatal: too long install path %s\n", dbinstalldir);
            return -1;
        }
        mkdir (dbplugindir, 0755);
    }
    else {
        if (snprintf (dbdocdir, sizeof (dbdocdir), "%s", DOCDIR) > sizeof (dbdocdir)) {
            fprintf (stderr, "fatal: too long install path %s\n", dbinstalldir);
            return -1;
        }
        if (snprintf (dbplugindir, sizeof (dbplugindir), "%s/deadbeef", LIBDIR) > sizeof (dbplugindir)) {
            fprintf (stderr, "fatal: too long install path %s\n", dbinstalldir);
            return -1;
        }
        if (snprintf (dbpixmapdir, sizeof (dbpixmapdir), "%s/share/deadbeef/pixmaps", PREFIX) > sizeof (dbpixmapdir)) {
            fprintf (stderr, "fatal: too long install path %s\n", dbinstalldir);
            return -1;
        }
    }

    for (int i = 1; i < argc; i++) {
        // help, version and nowplaying are executed with any filter
        if (!strcmp (argv[i], "--help") || !strcmp (argv[i], "-h")) {
            print_help ();
            return 0;
        }
        else if (!strcmp (argv[i], "--version")) {
            fprintf (stderr, "DeaDBeeF " VERSION " Copyright © 2009-2013 Alexey Yakovenko\n");
            return 0;
        }
        else if (!strcmp (argv[i], "--gui")) {
            if (i == argc-1) {
                break;
            }
            i++;
            strncpy (use_gui_plugin, argv[i], sizeof(use_gui_plugin) - 1);
            use_gui_plugin[sizeof(use_gui_plugin) - 1] = 0;
        }
    }

    trace ("installdir: %s\n", dbinstalldir);
    trace ("confdir: %s\n", confdir);
    trace ("docdir: %s\n", dbdocdir);
    trace ("plugindir: %s\n", dbplugindir);
    trace ("pixmapdir: %s\n", dbpixmapdir);

    mkdir (dbconfdir, 0755);

    int size = 0;
    char *cmdline = prepare_command_line (argc, argv, &size);

    // try to connect to remote player
    int s, len;
    struct sockaddr_un remote;

    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    memset (&remote, 0, sizeof (remote));
    remote.sun_family = AF_UNIX;
#if USE_ABSTRACT_SOCKET_NAME
    memcpy (remote.sun_path, server_id, sizeof (server_id));
    len = offsetof(struct sockaddr_un, sun_path) + sizeof (server_id)-1;
#else
    char *socketdirenv = getenv ("DDB_SOCKET_DIR");
    snprintf (remote.sun_path, sizeof (remote.sun_path), "%s/socket", socketdirenv ? socketdirenv : dbconfdir);
    len = offsetof(struct sockaddr_un, sun_path) + strlen (remote.sun_path);
#endif
    if (connect(s, (struct sockaddr *)&remote, len) == 0) {
        // pass args to remote and exit
        if (send(s, cmdline, size, 0) == -1) {
            perror ("send");
            exit (-1);
        }
        // end of message
        shutdown(s, SHUT_WR);

        int sz = -1;
        char *out = read_entire_message(s, &sz);
        if (sz == -1) {
            fprintf (stderr, "failed to pass args to remote!\n");
            exit (-1);
        }
        else {
            // check if that's nowplaying response
            const char np[] = "nowplaying ";
            const char err[] = "error ";
            if (!strncmp (out, np, sizeof (np)-1)) {
                const char *prn = &out[sizeof (np)-1];
                fwrite (prn, 1, strlen (prn), stdout);
            }
            else if (!strncmp (out, err, sizeof (err)-1)) {
                const char *prn = &out[sizeof (err)-1];
                fwrite (prn, 1, strlen (prn), stderr);
            }
            else if (sz > 0 && out[0]) {
                fprintf (stderr, "%s\n", out);
            }
        }
        if (out) {
            free (out);
        }
        close (s);
        exit (0);
    }
//    else {
//        perror ("INFO: failed to connect to existing session:");
//    }
    close(s);

    // become a server
    if (server_start () < 0) {
        exit (-1);
    }

    // hack: report nowplaying
    if (!strcmp (cmdline, "--nowplaying")) {
        char nothing[] = "nothing";
        fwrite (nothing, 1, sizeof (nothing)-1, stdout);
        return 0;
    }

    pl_init ();
    conf_init ();
    conf_load (); // required by some plugins at startup

    if (use_gui_plugin[0]) {
        conf_set_str ("gui_plugin", use_gui_plugin);
    }

    conf_set_str ("deadbeef_version", VERSION);

    volume_set_db (conf_get_float ("playback.volume", 0)); // volume need to be initialized before plugins start

    messagepump_init (); // required to push messages while handling commandline
    if (plug_load_all ()) { // required to add files to playlist from commandline
        exit (-1);
    }
    pl_load_all ();
    plt_set_curr_idx (conf_get_int ("playlist.current", 0));

    // execute server commands in local context
    int noloadpl = 0;
    if (argc > 1) {
        int res = server_exec_command_line (cmdline, size, NULL, 0);
        // some of the server commands ran on 1st instance should terminate it
        if (res == 2) {
            noloadpl = 1;
        }
        else if (res > 0) {
            exit (0);
        }
        else if (res < 0) {
            exit (-1);
        }
    }

    free (cmdline);

#if 0
    signal (SIGTERM, sigterm_handler);
    atexit (atexit_handler); // helps to save in simple cases
#endif

    streamer_init ();

    plug_connect_all ();
    messagepump_push (DB_EV_PLUGINSLOADED, 0, 0, 0);

    if (!noloadpl) {
        restore_resume_state ();
    }

    server_tid = thread_start (server_loop, NULL);

    mainloop_tid = thread_start (mainloop_thread, NULL);

    DB_plugin_t *gui = plug_get_gui ();
    if (gui) {
        gui->start ();
    }

    fprintf (stderr, "gui plugin has quit; waiting for mainloop thread to finish\n");
    thread_join (mainloop_tid);

    // terminate server and wait for completion
    if (server_tid) {
        server_terminate = 1;
        thread_join (server_tid);
        server_tid = 0;
    }

    // save config
    pl_save_all ();
    conf_save ();

    // delete legacy session file
    {
        char sessfile[1024]; // $HOME/.config/deadbeef/session
        if (snprintf (sessfile, sizeof (sessfile), "%s/deadbeef/session", confdir) < sizeof (sessfile)) {
            unlink (sessfile);
        }
    }

    // stop receiving messages from outside
    server_close ();

    // plugins might still hold references to playitems,
    // and query configuration in background
    // so unload everything 1st before final cleanup
    plug_disconnect_all ();
    plug_unload_all ();

    // at this point we can simply do exit(0), but let's clean up for debugging
    pl_free (); // may access conf_*
    conf_free ();

    fprintf (stderr, "messagepump_free\n");
    messagepump_free ();
    fprintf (stderr, "plug_cleanup\n");
    plug_cleanup ();

    fprintf (stderr, "hej-hej!\n");

    return 0;
}
Example #10
0
void
player_mainloop (void) {
    for (;;) {
        uint32_t msg;
        uintptr_t ctx;
        uint32_t p1;
        uint32_t p2;
        int term = 0;
        while (messagepump_pop(&msg, &ctx, &p1, &p2) != -1) {
            // broadcast to all plugins
            DB_plugin_t **plugs = plug_get_list ();
            for (int n = 0; plugs[n]; n++) {
                if (plugs[n]->message) {
                    plugs[n]->message (msg, ctx, p1, p2);
                }
            }
            if (!term) {
                DB_output_t *output = plug_get_output ();
                switch (msg) {
                case DB_EV_REINIT_SOUND:
                    plug_reinit_sound ();
                    streamer_reset (1);
                    conf_save ();
                    break;
                case DB_EV_TERMINATE:
                    {
                        save_resume_state ();

                        pl_playqueue_clear ();

                        // stop streaming and playback before unloading plugins
                        DB_output_t *output = plug_get_output ();
                        output->stop ();
                        streamer_free ();
                        output->free ();
                        term = 1;
                    }
                    break;
                case DB_EV_PLAY_CURRENT:
                    streamer_play_current_track ();
                    break;
                case DB_EV_PLAY_NUM:
                    pl_playqueue_clear ();
                    streamer_set_nextsong (p1, 4);
                    break;
                case DB_EV_STOP:
                    streamer_set_nextsong (-2, 0);
                    break;
                case DB_EV_NEXT:
                    streamer_move_to_nextsong (1);
                    break;
                case DB_EV_PREV:
                    streamer_move_to_prevsong (1);
                    break;
                case DB_EV_PAUSE:
                    if (output->state () != OUTPUT_STATE_PAUSED) {
                        output->pause ();
                        messagepump_push (DB_EV_PAUSED, 0, 1, 0);
                    }
                    break;
                case DB_EV_TOGGLE_PAUSE:
                    if (output->state () == OUTPUT_STATE_PAUSED) {
                        streamer_play_current_track ();
                    }
                    else {
                        output->pause ();
                        messagepump_push (DB_EV_PAUSED, 0, 1, 0);
                    }
                    break;
                case DB_EV_PLAY_RANDOM:
                    streamer_move_to_randomsong (1);
                    break;
                case DB_EV_PLAYLIST_REFRESH:
                    pl_save_current ();
                    messagepump_push (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
                    break;
                case DB_EV_CONFIGCHANGED:
                    conf_save ();
                    streamer_configchanged ();
                    junk_configchanged ();
                    break;
                case DB_EV_SEEK:
                    streamer_set_seek (p1 / 1000.f);
                    break;
                }
            }
            if (msg >= DB_EV_FIRST && ctx) {
                messagepump_event_free ((ddb_event_t *)ctx);
            }
        }
        if (term) {
            return;
        }
        messagepump_wait ();
    }
}
Example #11
0
// this function executes server-side commands only
// must be called only from within server
// -1 error, program must exit with error code -1
//  0 proceed normally as nothing happened
//  1 no error, but program must exit with error code 0
//  2 don't load playlist on startup
//  when executed in remote server -- error code will be ignored
int
server_exec_command_line (const char *cmdline, int len, char *sendback, int sbsize) {
    if (sendback) {
        sendback[0] = 0;
    }
    const uint8_t *parg = (const uint8_t *)cmdline;
    const uint8_t *pend = cmdline + len;
    int queue = 0;
    while (parg < pend) {
        const char *parg_c = parg;
        if (strlen (parg) >= 2 && parg[0] == '-' && parg[1] != '-') {
            parg += strlen (parg);
            parg++;
            return 0; // running under osx debugger?
        }
        else if (!strcmp (parg, "--nowplaying")) {
            parg += strlen (parg);
            parg++;
            if (parg >= pend) {
                if (sendback) {
                    snprintf (sendback, sbsize, "error --nowplaying expects format argument\n");
                    return 0;
                }
                else {
                    fprintf (stderr, "--nowplaying expects format argument\n");
                    return -1;
                }
            }
            if (sendback) {
                playItem_t *curr = streamer_get_playing_track ();
                DB_fileinfo_t *dec = streamer_get_current_fileinfo ();
                if (curr && dec) {
                    const char np[] = "nowplaying ";
                    memcpy (sendback, np, sizeof (np)-1);
                    pl_format_title (curr, -1, sendback+sizeof(np)-1, sbsize-sizeof(np)+1, -1, parg);
                }
                else {
                    strcpy (sendback, "nowplaying nothing");
                }
                if (curr) {
                    pl_item_unref (curr);
                }
            }
            else {
                char out[2048];
                playItem_t *curr = streamer_get_playing_track ();
                DB_fileinfo_t *dec = streamer_get_current_fileinfo();
                if (curr && dec) {
                    pl_format_title (curr, -1, out, sizeof (out), -1, parg);
                }
                else {
                    strcpy (out, "nothing");
                }
                if (curr) {
                    pl_item_unref (curr);
                }
                fwrite (out, 1, strlen (out), stdout);
                return 1; // exit
            }
        }
        else if (!strcmp (parg, "--next")) {
            messagepump_push (DB_EV_NEXT, 0, 0, 0);
            return 0;
        }
        else if (!strcmp (parg, "--prev")) {
            messagepump_push (DB_EV_PREV, 0, 0, 0);
            return 0;
        }
        else if (!strcmp (parg, "--play")) {
            messagepump_push (DB_EV_PLAY_CURRENT, 0, 0, 0);
            return 0;
        }
        else if (!strcmp (parg, "--stop")) {
            messagepump_push (DB_EV_STOP, 0, 0, 0);
            return 0;
        }
        else if (!strcmp (parg, "--pause")) {
            messagepump_push (DB_EV_PAUSE, 0, 0, 0);
            return 0;
        }
        else if (!strcmp (parg, "--toggle-pause")) {
            messagepump_push (DB_EV_TOGGLE_PAUSE, 0, 0, 0);
            return 0;
        }
        else if (!strcmp (parg, "--play-pause")) {
            int state = deadbeef->get_output ()->state ();
            if (state == OUTPUT_STATE_PLAYING) {
                deadbeef->sendmessage (DB_EV_PAUSE, 0, 0, 0);
            }
            else {
                deadbeef->sendmessage (DB_EV_PLAY_CURRENT, 0, 0, 0);
            }
            return 0;
        }
        else if (!strcmp (parg, "--random")) {
            messagepump_push (DB_EV_PLAY_RANDOM, 0, 0, 0);
            return 0;
        }
        else if (!strcmp (parg, "--queue")) {
            queue = 1;
        }
        else if (!strcmp (parg, "--quit")) {
            messagepump_push (DB_EV_TERMINATE, 0, 0, 0);
        }
        else if (!strcmp (parg, "--sm-client-id")) {
            parg += strlen (parg);
            parg++;
            if (parg < pend) {
                parg += strlen (parg);
                parg++;
            }
            continue;
        }
        else if (!strcmp (parg, "--gui")) {
            // need to skip --gui here, it is handled in the client cmdline
            parg += strlen (parg);
            parg++;
            if (parg >= pend) {
                break;
            }
            parg += strlen (parg);
            parg++;
            continue;
        }
        else if (parg[0] != '-') {
            break; // unknown option is filename
        }
        parg += strlen (parg);
        parg++;
    }
    if (parg < pend) {
        if (conf_get_int ("cli_add_to_specific_playlist", 1)) {
            char str[200];
            conf_get_str ("cli_add_playlist_name", "Default", str, sizeof (str));
            int idx = plt_find (str);
            if (idx < 0) {
                idx = plt_add (plt_get_count (), str);
            }
            if (idx >= 0) {
                plt_set_curr_idx (idx);
            }
        }
        playlist_t *curr_plt = plt_get_curr ();
        if (plt_add_files_begin (curr_plt, 0) != 0) {
            plt_unref (curr_plt);
            snprintf (sendback, sbsize, "it's not allowed to add files to playlist right now, because another file adding operation is in progress. please try again later.");
            return 0;
        }
        // add files
        if (!queue) {
            plt_clear (curr_plt);
            messagepump_push (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
            plt_reset_cursor (curr_plt);
        }
        while (parg < pend) {
            char resolved[PATH_MAX];
            const char *pname;
            if (realpath (parg, resolved)) {
                pname = resolved;
            }
            else {
                pname = parg;
            }
            if (deadbeef->plt_add_dir2 (0, (ddb_playlist_t*)curr_plt, pname, NULL, NULL) < 0) {
                if (deadbeef->plt_add_file2 (0, (ddb_playlist_t*)curr_plt, pname, NULL, NULL) < 0) {
                    int ab = 0;
                    playItem_t *it = plt_load2 (0, curr_plt, NULL, pname, &ab, NULL, NULL);
                    if (!it) {
                        fprintf (stderr, "failed to add file or folder %s\n", pname);
                    }
                }
            }
            parg += strlen (parg);
            parg++;
        }
        messagepump_push (DB_EV_PLAYLIST_REFRESH, 0, 0, 0);
        plt_add_files_end (curr_plt, 0);
        plt_unref (curr_plt);
        if (!queue) {
            messagepump_push (DB_EV_PLAY_NUM, 0, 0, 0);
            return 2; // don't reload playlist at startup
        }
    }
    return 0;
}