mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-07 23:35:03 +01:00
Merge branch 'export-dialog' into cairocanvas
Fix merge conflicts in: gtk2_ardour/export_range_markers_dialog.cc gtk2_ardour/wscript libs/ardour/ardour/export_handler.h libs/ardour/system_exec.cc libs/pbd/pbd/system_exec.h libs/pbd/system_exec.cc
This commit is contained in:
commit
5399425f53
29 changed files with 992 additions and 367 deletions
30
export/Soundcloud upload (lossless).format
Normal file
30
export/Soundcloud upload (lossless).format
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ExportFormatSpecification name="Soundcloud upload (lossless)" id="14f5b271-86b3-48c6-9ee2-133f46fe06c1" with-cue="false" with-toc="false" upload="true" command="">
|
||||||
|
<Encoding id="F_FLAC" type="T_Sndfile" extension="flac" name="FLAC" has-sample-format="true" channel-limit="8"/>
|
||||||
|
<SampleRate rate="1"/>
|
||||||
|
<SRCQuality quality="SRC_SincBest"/>
|
||||||
|
<EncodingOptions>
|
||||||
|
<Option name="sample-format" value="SF_16"/>
|
||||||
|
<Option name="dithering" value="D_Shaped"/>
|
||||||
|
<Option name="tag-metadata" value="true"/>
|
||||||
|
<Option name="tag-support" value="true"/>
|
||||||
|
<Option name="broadcast-info" value="false"/>
|
||||||
|
</EncodingOptions>
|
||||||
|
<Processing>
|
||||||
|
<Normalize enabled="false" target="1"/>
|
||||||
|
<Silence>
|
||||||
|
<Start>
|
||||||
|
<Trim enabled="false"/>
|
||||||
|
<Add enabled="false">
|
||||||
|
<Duration format="Timecode" hours="0" minutes="0" seconds="0" frames="0"/>
|
||||||
|
</Add>
|
||||||
|
</Start>
|
||||||
|
<End>
|
||||||
|
<Trim enabled="false"/>
|
||||||
|
<Add enabled="false">
|
||||||
|
<Duration format="Timecode" hours="0" minutes="0" seconds="0" frames="0"/>
|
||||||
|
</Add>
|
||||||
|
</End>
|
||||||
|
</Silence>
|
||||||
|
</Processing>
|
||||||
|
</ExportFormatSpecification>
|
||||||
30
export/Soundcloud upload (lossy).format
Normal file
30
export/Soundcloud upload (lossy).format
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ExportFormatSpecification name="Soundcloud upload (lossy)" id="a42eb2fe-2470-4aa9-8027-798ba625592a" with-cue="false" with-toc="false" upload="true" command="">
|
||||||
|
<Encoding id="F_Ogg" type="T_Sndfile" extension="ogg" name="Ogg Vorbis" has-sample-format="false" channel-limit="256"/>
|
||||||
|
<SampleRate rate="44100"/>
|
||||||
|
<SRCQuality quality="SRC_SincBest"/>
|
||||||
|
<EncodingOptions>
|
||||||
|
<Option name="sample-format" value="SF_Vorbis"/>
|
||||||
|
<Option name="dithering" value="D_Shaped"/>
|
||||||
|
<Option name="tag-metadata" value="true"/>
|
||||||
|
<Option name="tag-support" value="true"/>
|
||||||
|
<Option name="broadcast-info" value="false"/>
|
||||||
|
</EncodingOptions>
|
||||||
|
<Processing>
|
||||||
|
<Normalize enabled="false" target="1"/>
|
||||||
|
<Silence>
|
||||||
|
<Start>
|
||||||
|
<Trim enabled="false"/>
|
||||||
|
<Add enabled="false">
|
||||||
|
<Duration format="Timecode" hours="0" minutes="0" seconds="0" frames="0"/>
|
||||||
|
</Add>
|
||||||
|
</Start>
|
||||||
|
<End>
|
||||||
|
<Trim enabled="false"/>
|
||||||
|
<Add enabled="false">
|
||||||
|
<Duration format="Timecode" hours="0" minutes="0" seconds="0" frames="0"/>
|
||||||
|
</Add>
|
||||||
|
</End>
|
||||||
|
</Silence>
|
||||||
|
</Processing>
|
||||||
|
</ExportFormatSpecification>
|
||||||
|
|
@ -458,15 +458,15 @@ RegionExportChannelSelector::RegionExportChannelSelector (ARDOUR::Session * _ses
|
||||||
|
|
||||||
raw_button.set_label (string_compose (_("Region contents without fades nor region gain (channels: %1)"), region_chans));
|
raw_button.set_label (string_compose (_("Region contents without fades nor region gain (channels: %1)"), region_chans));
|
||||||
raw_button.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection));
|
raw_button.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection));
|
||||||
vbox.pack_start (raw_button);
|
vbox.pack_start (raw_button, false, false);
|
||||||
|
|
||||||
fades_button.set_label (string_compose (_("Region contents with fades and region gain (channels: %1)"), region_chans));
|
fades_button.set_label (string_compose (_("Region contents with fades and region gain (channels: %1)"), region_chans));
|
||||||
fades_button.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection));
|
fades_button.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection));
|
||||||
vbox.pack_start (fades_button);
|
vbox.pack_start (fades_button, false, false);
|
||||||
|
|
||||||
processed_button.set_label (string_compose (_("Track output (channels: %1)"), track_chans));
|
processed_button.set_label (string_compose (_("Track output (channels: %1)"), track_chans));
|
||||||
processed_button.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection));
|
processed_button.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection));
|
||||||
vbox.pack_start (processed_button);
|
vbox.pack_start (processed_button, false, false);
|
||||||
|
|
||||||
sync_with_manager();
|
sync_with_manager();
|
||||||
vbox.show_all_children ();
|
vbox.show_all_children ();
|
||||||
|
|
@ -541,7 +541,7 @@ TrackExportChannelSelector::TrackExportChannelSelector (ARDOUR::Session * sessio
|
||||||
// Options
|
// Options
|
||||||
options_box.pack_start(region_contents_button);
|
options_box.pack_start(region_contents_button);
|
||||||
options_box.pack_start(track_output_button);
|
options_box.pack_start(track_output_button);
|
||||||
main_layout.pack_start(options_box);
|
main_layout.pack_start(options_box, false, false);
|
||||||
|
|
||||||
// Track scroller
|
// Track scroller
|
||||||
track_scroller.add (track_view);
|
track_scroller.add (track_view);
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ class PortExportChannelSelector : public ExportChannelSelector
|
||||||
typedef Gtk::TreeModelColumn<Glib::RefPtr<Gtk::ListStore> > ComboCol;
|
typedef Gtk::TreeModelColumn<Glib::RefPtr<Gtk::ListStore> > ComboCol;
|
||||||
ComboCol port_list_col;
|
ComboCol port_list_col;
|
||||||
|
|
||||||
/* Channel struct, that represents the selected port and it's name */
|
/* Channel struct, that represents the selected port and its name */
|
||||||
|
|
||||||
struct Channel {
|
struct Channel {
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -140,69 +140,27 @@ ExportDialog::init ()
|
||||||
progress_widget.hide_all();
|
progress_widget.hide_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ExportDialog::expanded_changed ()
|
|
||||||
{
|
|
||||||
set_resizable(advanced->get_expanded());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ExportDialog::init_gui ()
|
ExportDialog::init_gui ()
|
||||||
{
|
{
|
||||||
Gtk::Alignment * preset_align = Gtk::manage (new Gtk::Alignment());
|
Gtk::Alignment * preset_align = Gtk::manage (new Gtk::Alignment());
|
||||||
preset_align->add (*preset_selector);
|
preset_align->add (*preset_selector);
|
||||||
preset_align->set_padding (0, 12, 0, 0);
|
preset_align->set_padding (0, 12, 0, 0);
|
||||||
get_vbox()->pack_start (*preset_align, false, false, 0);
|
|
||||||
|
|
||||||
Gtk::VPaned * advanced_paned = Gtk::manage (new Gtk::VPaned());
|
Gtk::VBox * file_format_selector = Gtk::manage (new Gtk::VBox());
|
||||||
|
file_format_selector->set_homogeneous (false);
|
||||||
|
file_format_selector->pack_start (*preset_align, false, false, 0);
|
||||||
|
file_format_selector->pack_start (*file_notebook, false, false, 0);
|
||||||
|
file_format_selector->pack_start (*soundcloud_selector, false, false, 0);
|
||||||
|
|
||||||
Gtk::VBox* timespan_vbox = Gtk::manage (new Gtk::VBox());
|
export_notebook.append_page (*file_format_selector, _("File format"));
|
||||||
timespan_vbox->set_spacing (12);
|
export_notebook.append_page (*timespan_selector, _("Time Span"));
|
||||||
timespan_vbox->set_border_width (12);
|
export_notebook.append_page (*channel_selector, _("Channels"));
|
||||||
|
|
||||||
|
get_vbox()->pack_start (export_notebook, true, true, 0);
|
||||||
|
get_vbox()->pack_end (warning_widget, false, false, 0);
|
||||||
|
get_vbox()->pack_end (progress_widget, false, false, 0);
|
||||||
|
|
||||||
Gtk::Alignment * timespan_align = Gtk::manage (new Gtk::Alignment());
|
|
||||||
timespan_label = Gtk::manage (new Gtk::Label (_("Time Span"), Gtk::ALIGN_LEFT));
|
|
||||||
timespan_align->add (*timespan_selector);
|
|
||||||
timespan_align->set_padding (0, 0, 18, 0);
|
|
||||||
timespan_vbox->pack_start (*timespan_label, false, false, 0);
|
|
||||||
timespan_vbox->pack_start (*timespan_align, true, true, 0);
|
|
||||||
advanced_paned->pack1(*timespan_vbox, true, false);
|
|
||||||
|
|
||||||
Gtk::VBox* channels_vbox = Gtk::manage (new Gtk::VBox());
|
|
||||||
channels_vbox->set_spacing (12);
|
|
||||||
channels_vbox->set_border_width (12);
|
|
||||||
|
|
||||||
Gtk::Alignment * channels_align = Gtk::manage (new Gtk::Alignment());
|
|
||||||
channels_label = Gtk::manage (new Gtk::Label (_("Channels"), Gtk::ALIGN_LEFT));
|
|
||||||
channels_align->add (*channel_selector);
|
|
||||||
channels_align->set_padding (0, 12, 18, 0);
|
|
||||||
channels_vbox->pack_start (*channels_label, false, false, 0);
|
|
||||||
channels_vbox->pack_start (*channels_align, true, true, 0);
|
|
||||||
advanced_paned->pack2(*channels_vbox, channel_selector_is_expandable(), false);
|
|
||||||
|
|
||||||
get_vbox()->pack_start (*file_notebook, false, false, 0);
|
|
||||||
get_vbox()->pack_start (warning_widget, false, false, 0);
|
|
||||||
get_vbox()->pack_start (progress_widget, false, false, 0);
|
|
||||||
|
|
||||||
advanced = Gtk::manage (new Gtk::Expander (_("Time span and channel options")));
|
|
||||||
advanced->property_expanded().signal_changed().connect(
|
|
||||||
sigc::mem_fun(*this, &ExportDialog::expanded_changed));
|
|
||||||
advanced->add (*advanced_paned);
|
|
||||||
|
|
||||||
if (channel_selector_is_expandable()) {
|
|
||||||
advanced_sizegroup = Gtk::SizeGroup::create(Gtk::SIZE_GROUP_VERTICAL);
|
|
||||||
advanced_sizegroup->add_widget(*timespan_selector);
|
|
||||||
advanced_sizegroup->add_widget(*channel_selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
get_vbox()->pack_start (*advanced, true, true);
|
|
||||||
|
|
||||||
Pango::AttrList bold;
|
|
||||||
Pango::Attribute b = Pango::Attribute::create_attr_weight (Pango::WEIGHT_BOLD);
|
|
||||||
bold.insert (b);
|
|
||||||
|
|
||||||
timespan_label->set_attributes (bold);
|
|
||||||
channels_label->set_attributes (bold);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -211,6 +169,7 @@ ExportDialog::init_components ()
|
||||||
preset_selector.reset (new ExportPresetSelector ());
|
preset_selector.reset (new ExportPresetSelector ());
|
||||||
timespan_selector.reset (new ExportTimespanSelectorMultiple (_session, profile_manager));
|
timespan_selector.reset (new ExportTimespanSelectorMultiple (_session, profile_manager));
|
||||||
channel_selector.reset (new PortExportChannelSelector (_session, profile_manager));
|
channel_selector.reset (new PortExportChannelSelector (_session, profile_manager));
|
||||||
|
soundcloud_selector.reset (new SoundcloudExportSelector ());
|
||||||
file_notebook.reset (new ExportFileNotebook ());
|
file_notebook.reset (new ExportFileNotebook ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -300,11 +259,34 @@ ExportDialog::show_conflicting_files ()
|
||||||
dialog.run();
|
dialog.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExportDialog::soundcloud_upload_progress(double total, double now, std::string title)
|
||||||
|
{
|
||||||
|
soundcloud_selector->do_progress_callback(total, now, title);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ExportDialog::do_export ()
|
ExportDialog::do_export ()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
profile_manager->prepare_for_export ();
|
profile_manager->prepare_for_export ();
|
||||||
|
handler->upload_username = soundcloud_selector->username();
|
||||||
|
handler->upload_password = soundcloud_selector->password();
|
||||||
|
handler->upload_public = soundcloud_selector->upload_public();
|
||||||
|
handler->upload_open = soundcloud_selector->upload_open();
|
||||||
|
|
||||||
|
handler->SoundcloudProgress.connect_same_thread(
|
||||||
|
*this,
|
||||||
|
boost::bind(&ExportDialog::soundcloud_upload_progress, this, _1, _2, _3)
|
||||||
|
);
|
||||||
|
#if 0
|
||||||
|
handler->SoundcloudProgress.connect(
|
||||||
|
*this, invalidator (*this),
|
||||||
|
boost::bind(&ExportDialog::soundcloud_upload_progress, this, _1, _2, _3),
|
||||||
|
gui_context()
|
||||||
|
);
|
||||||
|
#endif
|
||||||
handler->do_export ();
|
handler->do_export ();
|
||||||
show_progress ();
|
show_progress ();
|
||||||
} catch(std::exception & e) {
|
} catch(std::exception & e) {
|
||||||
|
|
@ -418,6 +400,7 @@ ExportRangeDialog::init_components ()
|
||||||
preset_selector.reset (new ExportPresetSelector ());
|
preset_selector.reset (new ExportPresetSelector ());
|
||||||
timespan_selector.reset (new ExportTimespanSelectorSingle (_session, profile_manager, range_id));
|
timespan_selector.reset (new ExportTimespanSelectorSingle (_session, profile_manager, range_id));
|
||||||
channel_selector.reset (new PortExportChannelSelector (_session, profile_manager));
|
channel_selector.reset (new PortExportChannelSelector (_session, profile_manager));
|
||||||
|
soundcloud_selector.reset (new SoundcloudExportSelector ());
|
||||||
file_notebook.reset (new ExportFileNotebook ());
|
file_notebook.reset (new ExportFileNotebook ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -431,6 +414,7 @@ ExportSelectionDialog::init_components ()
|
||||||
preset_selector.reset (new ExportPresetSelector ());
|
preset_selector.reset (new ExportPresetSelector ());
|
||||||
timespan_selector.reset (new ExportTimespanSelectorSingle (_session, profile_manager, X_("selection")));
|
timespan_selector.reset (new ExportTimespanSelectorSingle (_session, profile_manager, X_("selection")));
|
||||||
channel_selector.reset (new PortExportChannelSelector (_session, profile_manager));
|
channel_selector.reset (new PortExportChannelSelector (_session, profile_manager));
|
||||||
|
soundcloud_selector.reset (new SoundcloudExportSelector ());
|
||||||
file_notebook.reset (new ExportFileNotebook ());
|
file_notebook.reset (new ExportFileNotebook ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -444,8 +428,7 @@ void
|
||||||
ExportRegionDialog::init_gui ()
|
ExportRegionDialog::init_gui ()
|
||||||
{
|
{
|
||||||
ExportDialog::init_gui ();
|
ExportDialog::init_gui ();
|
||||||
|
export_notebook.set_tab_label_text(*export_notebook.get_nth_page(2), _("Source"));
|
||||||
channels_label->set_text (_("Source"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -456,6 +439,7 @@ ExportRegionDialog::init_components ()
|
||||||
preset_selector.reset (new ExportPresetSelector ());
|
preset_selector.reset (new ExportPresetSelector ());
|
||||||
timespan_selector.reset (new ExportTimespanSelectorSingle (_session, profile_manager, loc_id));
|
timespan_selector.reset (new ExportTimespanSelectorSingle (_session, profile_manager, loc_id));
|
||||||
channel_selector.reset (new RegionExportChannelSelector (_session, profile_manager, region, track));
|
channel_selector.reset (new RegionExportChannelSelector (_session, profile_manager, region, track));
|
||||||
|
soundcloud_selector.reset (new SoundcloudExportSelector ());
|
||||||
file_notebook.reset (new ExportFileNotebook ());
|
file_notebook.reset (new ExportFileNotebook ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -471,5 +455,6 @@ StemExportDialog::init_components ()
|
||||||
preset_selector.reset (new ExportPresetSelector ());
|
preset_selector.reset (new ExportPresetSelector ());
|
||||||
timespan_selector.reset (new ExportTimespanSelectorMultiple (_session, profile_manager));
|
timespan_selector.reset (new ExportTimespanSelectorMultiple (_session, profile_manager));
|
||||||
channel_selector.reset (new TrackExportChannelSelector (_session, profile_manager));
|
channel_selector.reset (new TrackExportChannelSelector (_session, profile_manager));
|
||||||
|
soundcloud_selector.reset (new SoundcloudExportSelector ());
|
||||||
file_notebook.reset (new ExportFileNotebook ());
|
file_notebook.reset (new ExportFileNotebook ());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
#include "export_file_notebook.h"
|
#include "export_file_notebook.h"
|
||||||
#include "export_preset_selector.h"
|
#include "export_preset_selector.h"
|
||||||
#include "ardour_dialog.h"
|
#include "ardour_dialog.h"
|
||||||
|
#include "soundcloud_export_selector.h"
|
||||||
|
|
||||||
#include <gtkmm.h>
|
#include <gtkmm.h>
|
||||||
|
|
||||||
|
|
@ -43,7 +44,8 @@ namespace ARDOUR {
|
||||||
class ExportTimespanSelector;
|
class ExportTimespanSelector;
|
||||||
class ExportChannelSelector;
|
class ExportChannelSelector;
|
||||||
|
|
||||||
class ExportDialog : public ArdourDialog {
|
class ExportDialog : public ArdourDialog, public PBD::ScopedConnectionList
|
||||||
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
@ -75,26 +77,22 @@ class ExportDialog : public ArdourDialog {
|
||||||
// Must initialize all the shared_ptrs below
|
// Must initialize all the shared_ptrs below
|
||||||
virtual void init_components ();
|
virtual void init_components ();
|
||||||
|
|
||||||
// Override if the channel selector should not be grown
|
|
||||||
virtual bool channel_selector_is_expandable() { return true; }
|
|
||||||
|
|
||||||
boost::scoped_ptr<ExportPresetSelector> preset_selector;
|
boost::scoped_ptr<ExportPresetSelector> preset_selector;
|
||||||
boost::scoped_ptr<ExportTimespanSelector> timespan_selector;
|
boost::scoped_ptr<ExportTimespanSelector> timespan_selector;
|
||||||
boost::scoped_ptr<ExportChannelSelector> channel_selector;
|
boost::scoped_ptr<ExportChannelSelector> channel_selector;
|
||||||
boost::scoped_ptr<ExportFileNotebook> file_notebook;
|
boost::scoped_ptr<ExportFileNotebook> file_notebook;
|
||||||
|
boost::scoped_ptr<SoundcloudExportSelector> soundcloud_selector;
|
||||||
|
|
||||||
Gtk::VBox warning_widget;
|
Gtk::VBox warning_widget;
|
||||||
Gtk::VBox progress_widget;
|
Gtk::VBox progress_widget;
|
||||||
|
|
||||||
Gtk::Label * timespan_label;
|
/*** GUI components ***/
|
||||||
Gtk::Label * channels_label;
|
Gtk::Notebook export_notebook;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void init ();
|
void init ();
|
||||||
|
|
||||||
void expanded_changed();
|
|
||||||
|
|
||||||
void notify_errors (bool force = false);
|
void notify_errors (bool force = false);
|
||||||
void close_dialog ();
|
void close_dialog ();
|
||||||
|
|
||||||
|
|
@ -112,10 +110,7 @@ class ExportDialog : public ArdourDialog {
|
||||||
PublicEditor & editor;
|
PublicEditor & editor;
|
||||||
StatusPtr status;
|
StatusPtr status;
|
||||||
|
|
||||||
/*** GUI components ***/
|
|
||||||
|
|
||||||
Glib::RefPtr<Gtk::SizeGroup> advanced_sizegroup;
|
|
||||||
Gtk::Expander * advanced;
|
|
||||||
|
|
||||||
/* Warning area */
|
/* Warning area */
|
||||||
|
|
||||||
|
|
@ -138,6 +133,8 @@ class ExportDialog : public ArdourDialog {
|
||||||
|
|
||||||
float previous_progress; // Needed for gtk bug workaround
|
float previous_progress; // Needed for gtk bug workaround
|
||||||
|
|
||||||
|
void soundcloud_upload_progress(double total, double now, std::string title);
|
||||||
|
|
||||||
/* Buttons */
|
/* Buttons */
|
||||||
|
|
||||||
Gtk::Button * cancel_button;
|
Gtk::Button * cancel_button;
|
||||||
|
|
@ -170,9 +167,6 @@ class ExportRegionDialog : public ExportDialog
|
||||||
public:
|
public:
|
||||||
ExportRegionDialog (PublicEditor & editor, ARDOUR::AudioRegion const & region, ARDOUR::AudioTrack & track);
|
ExportRegionDialog (PublicEditor & editor, ARDOUR::AudioRegion const & region, ARDOUR::AudioTrack & track);
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual bool channel_selector_is_expandable() { return false; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init_gui ();
|
void init_gui ();
|
||||||
void init_components ();
|
void init_components ();
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,9 @@ ExportFormatDialog::ExportFormatDialog (FormatPtr format, bool new_dialog) :
|
||||||
silence_end_checkbox (_("Add silence at end:")),
|
silence_end_checkbox (_("Add silence at end:")),
|
||||||
silence_end_clock ("silence_end", true, "", true, false, true),
|
silence_end_clock ("silence_end", true, "", true, false, true),
|
||||||
|
|
||||||
|
upload_checkbox(_("Upload to Soundcloud")),
|
||||||
|
command_label(_("Command to run post-export\n(%f=full path & filename, %d=directory, %b=basename, %u=username, %p=password):")),
|
||||||
|
|
||||||
format_table (3, 4),
|
format_table (3, 4),
|
||||||
compatibility_label (_("Compatibility"), Gtk::ALIGN_LEFT),
|
compatibility_label (_("Compatibility"), Gtk::ALIGN_LEFT),
|
||||||
quality_label (_("Quality"), Gtk::ALIGN_LEFT),
|
quality_label (_("Quality"), Gtk::ALIGN_LEFT),
|
||||||
|
|
@ -113,6 +116,10 @@ ExportFormatDialog::ExportFormatDialog (FormatPtr format, bool new_dialog) :
|
||||||
silence_table.attach (silence_end_checkbox, 1, 2, 2, 3);
|
silence_table.attach (silence_end_checkbox, 1, 2, 2, 3);
|
||||||
silence_table.attach (silence_end_clock, 2, 3, 2, 3);
|
silence_table.attach (silence_end_clock, 2, 3, 2, 3);
|
||||||
|
|
||||||
|
get_vbox()->pack_start (upload_checkbox, false, false);
|
||||||
|
get_vbox()->pack_start (command_label, false, false);
|
||||||
|
get_vbox()->pack_start (command_entry, false, false);
|
||||||
|
|
||||||
/* Format table */
|
/* Format table */
|
||||||
|
|
||||||
init_format_table();
|
init_format_table();
|
||||||
|
|
@ -142,6 +149,8 @@ ExportFormatDialog::ExportFormatDialog (FormatPtr format, bool new_dialog) :
|
||||||
|
|
||||||
with_cue.signal_toggled().connect (sigc::mem_fun (*this, &ExportFormatDialog::update_with_cue));
|
with_cue.signal_toggled().connect (sigc::mem_fun (*this, &ExportFormatDialog::update_with_cue));
|
||||||
with_toc.signal_toggled().connect (sigc::mem_fun (*this, &ExportFormatDialog::update_with_toc));
|
with_toc.signal_toggled().connect (sigc::mem_fun (*this, &ExportFormatDialog::update_with_toc));
|
||||||
|
upload_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &ExportFormatDialog::update_upload));
|
||||||
|
command_entry.signal_changed().connect (sigc::mem_fun (*this, &ExportFormatDialog::update_command));
|
||||||
|
|
||||||
cue_toc_vbox.pack_start (with_cue, false, false);
|
cue_toc_vbox.pack_start (with_cue, false, false);
|
||||||
cue_toc_vbox.pack_start (with_toc, false, false);
|
cue_toc_vbox.pack_start (with_toc, false, false);
|
||||||
|
|
@ -296,6 +305,8 @@ ExportFormatDialog::load_state (FormatPtr spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
tag_checkbox.set_active (spec->tag());
|
tag_checkbox.set_active (spec->tag());
|
||||||
|
upload_checkbox.set_active (spec->upload());
|
||||||
|
command_entry.set_text (spec->command());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -717,6 +728,18 @@ ExportFormatDialog::update_with_toc ()
|
||||||
manager.select_with_toc (with_toc.get_active());
|
manager.select_with_toc (with_toc.get_active());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExportFormatDialog::update_upload ()
|
||||||
|
{
|
||||||
|
manager.select_upload (upload_checkbox.get_active());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExportFormatDialog::update_command ()
|
||||||
|
{
|
||||||
|
manager.set_command (command_entry.get_text());
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ExportFormatDialog::update_description()
|
ExportFormatDialog::update_description()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -179,6 +179,12 @@ class ExportFormatDialog : public ArdourDialog, public PBD::ScopedConnectionList
|
||||||
Gtk::CheckButton silence_end_checkbox;
|
Gtk::CheckButton silence_end_checkbox;
|
||||||
AudioClock silence_end_clock;
|
AudioClock silence_end_clock;
|
||||||
|
|
||||||
|
/* Upload */
|
||||||
|
|
||||||
|
Gtk::CheckButton upload_checkbox;
|
||||||
|
Gtk::Label command_label;
|
||||||
|
Gtk::Entry command_entry;
|
||||||
|
|
||||||
/* Format table */
|
/* Format table */
|
||||||
|
|
||||||
struct CompatibilityCols : public Gtk::TreeModelColumnRecord
|
struct CompatibilityCols : public Gtk::TreeModelColumnRecord
|
||||||
|
|
@ -311,6 +317,8 @@ class ExportFormatDialog : public ArdourDialog, public PBD::ScopedConnectionList
|
||||||
|
|
||||||
void update_with_toc ();
|
void update_with_toc ();
|
||||||
void update_with_cue ();
|
void update_with_cue ();
|
||||||
|
void update_upload ();
|
||||||
|
void update_command ();
|
||||||
|
|
||||||
Gtk::TreeView sample_format_view;
|
Gtk::TreeView sample_format_view;
|
||||||
Gtk::TreeView dither_type_view;
|
Gtk::TreeView dither_type_view;
|
||||||
|
|
|
||||||
|
|
@ -1,209 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright (C) 2006 Paul Davis
|
|
||||||
Author: Andre Raue
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include "ardour/audioengine.h"
|
|
||||||
#include "ardour/sndfile_helpers.h"
|
|
||||||
|
|
||||||
#include "ardour_ui.h"
|
|
||||||
#include "export_range_markers_dialog.h"
|
|
||||||
|
|
||||||
#include "i18n.h"
|
|
||||||
|
|
||||||
using namespace Gtk;
|
|
||||||
using namespace ARDOUR;
|
|
||||||
using namespace PBD;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
ExportRangeMarkersDialog::ExportRangeMarkersDialog (PublicEditor& editor)
|
|
||||||
: ExportDialog(editor)
|
|
||||||
{
|
|
||||||
set_title (_("Export Ranges"));
|
|
||||||
file_frame.set_label (_("Export to Directory"));
|
|
||||||
|
|
||||||
do_not_allow_export_cd_markers();
|
|
||||||
|
|
||||||
total_duration = 0;
|
|
||||||
current_range_marker_index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Gtk::FileChooserAction
|
|
||||||
ExportRangeMarkersDialog::browse_action () const
|
|
||||||
{
|
|
||||||
return Gtk::FILE_CHOOSER_ACTION_CREATE_FOLDER;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ExportRangeMarkersDialog::export_data ()
|
|
||||||
{
|
|
||||||
getSession().locations()->apply(*this, &ExportRangeMarkersDialog::process_range_markers_export);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ExportRangeMarkersDialog::process_range_markers_export(Locations::LocationList& locations)
|
|
||||||
{
|
|
||||||
Locations::LocationList::iterator locationIter;
|
|
||||||
current_range_marker_index = 0;
|
|
||||||
init_progress_computing(locations);
|
|
||||||
|
|
||||||
for (locationIter = locations.begin(); locationIter != locations.end(); ++locationIter) {
|
|
||||||
Location *currentLocation = (*locationIter);
|
|
||||||
|
|
||||||
if(currentLocation->is_range_marker()){
|
|
||||||
// init filename
|
|
||||||
string filepath = get_target_filepath(
|
|
||||||
get_selected_file_name(),
|
|
||||||
currentLocation->name(),
|
|
||||||
get_selected_header_format());
|
|
||||||
|
|
||||||
initSpec(filepath);
|
|
||||||
|
|
||||||
spec.start_frame = currentLocation->start();
|
|
||||||
spec.end_frame = currentLocation->end();
|
|
||||||
|
|
||||||
if (getSession().start_export(spec)){
|
|
||||||
// if export fails
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait until export of this range finished
|
|
||||||
gtk_main_iteration();
|
|
||||||
|
|
||||||
while (spec.running){
|
|
||||||
if(gtk_events_pending()){
|
|
||||||
gtk_main_iteration();
|
|
||||||
}else {
|
|
||||||
Glib::usleep(10000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current_range_marker_index++;
|
|
||||||
|
|
||||||
getSession().stop_export (spec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spec.running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
string
|
|
||||||
ExportRangeMarkersDialog::get_target_filepath(string path, string filename, string postfix)
|
|
||||||
{
|
|
||||||
string target_path = path;
|
|
||||||
if ((target_path.find_last_of ('/')) != string::npos) {
|
|
||||||
target_path += '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
string target_filepath = target_path + filename + postfix;
|
|
||||||
struct stat statbuf;
|
|
||||||
|
|
||||||
for(int counter=1; (stat (target_filepath.c_str(), &statbuf) == 0); counter++){
|
|
||||||
// while file exists
|
|
||||||
ostringstream scounter;
|
|
||||||
scounter.flush();
|
|
||||||
scounter << counter;
|
|
||||||
|
|
||||||
target_filepath =
|
|
||||||
target_path + filename + "_" + scounter.str() + postfix;
|
|
||||||
}
|
|
||||||
|
|
||||||
return target_filepath;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ExportRangeMarkersDialog::is_filepath_valid(string &filepath)
|
|
||||||
{
|
|
||||||
// sanity check file name first
|
|
||||||
struct stat statbuf;
|
|
||||||
|
|
||||||
if (filepath.empty()) {
|
|
||||||
// warning dialog
|
|
||||||
string txt = _("Please enter a valid target directory.");
|
|
||||||
MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true);
|
|
||||||
msg.run();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( (stat (filepath.c_str(), &statbuf) != 0) ||
|
|
||||||
(!S_ISDIR (statbuf.st_mode)) ) {
|
|
||||||
string txt = _("Please select an existing target directory. Files are not allowed!");
|
|
||||||
MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true);
|
|
||||||
msg.run();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// directory needs to exist and be writable
|
|
||||||
string dirpath = Glib::path_get_dirname (filepath);
|
|
||||||
if (!exists_and_writable (dirpath)) {
|
|
||||||
string txt = _("Cannot write file in: ") + dirpath;
|
|
||||||
MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true);
|
|
||||||
msg.run();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ExportRangeMarkersDialog::init_progress_computing(Locations::LocationList& locations)
|
|
||||||
{
|
|
||||||
// flush vector
|
|
||||||
range_markers_durations_aggregated.resize(0);
|
|
||||||
|
|
||||||
framecnt_t duration_before_current_location = 0;
|
|
||||||
Locations::LocationList::iterator locationIter;
|
|
||||||
|
|
||||||
for (locationIter = locations.begin(); locationIter != locations.end(); ++locationIter) {
|
|
||||||
Location *currentLocation = (*locationIter);
|
|
||||||
|
|
||||||
if(currentLocation->is_range_marker()){
|
|
||||||
range_markers_durations_aggregated.push_back (duration_before_current_location);
|
|
||||||
|
|
||||||
framecnt_t duration = currentLocation->end() - currentLocation->start();
|
|
||||||
|
|
||||||
range_markers_durations.push_back (duration);
|
|
||||||
duration_before_current_location += duration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
total_duration = duration_before_current_location;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
gint
|
|
||||||
ExportRangeMarkersDialog::progress_timeout ()
|
|
||||||
{
|
|
||||||
double progress = 0.0;
|
|
||||||
|
|
||||||
if (current_range_marker_index >= range_markers_durations.size()){
|
|
||||||
progress = 1.0;
|
|
||||||
} else{
|
|
||||||
progress = ((double) range_markers_durations_aggregated[current_range_marker_index] +
|
|
||||||
(spec.progress * (double) range_markers_durations[current_range_marker_index])) /
|
|
||||||
(double) total_duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_progress_fraction( progress );
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright (C) 2006 Andre Raue
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __export_range_markers_dialog_h__
|
|
||||||
#define __export_range_markers_dialog_h__
|
|
||||||
|
|
||||||
#include "ardour/location.h"
|
|
||||||
|
|
||||||
#include "export_dialog.h"
|
|
||||||
|
|
||||||
|
|
||||||
class ExportRangeMarkersDialog : public ExportDialog
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ExportRangeMarkersDialog (PublicEditor&);
|
|
||||||
|
|
||||||
Gtk::FileChooserAction browse_action() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual bool is_filepath_valid(string &filepath);
|
|
||||||
|
|
||||||
void export_data();
|
|
||||||
|
|
||||||
bool wants_dir() { return true; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
// keeps the duration of all range_markers before the current
|
|
||||||
vector<nframes_t> range_markers_durations_aggregated;
|
|
||||||
vector<nframes_t> range_markers_durations;
|
|
||||||
// duration of all range markers
|
|
||||||
nframes_t total_duration;
|
|
||||||
// index of range marker, that get's exported right now
|
|
||||||
unsigned int current_range_marker_index;
|
|
||||||
|
|
||||||
// sets value of progress bar
|
|
||||||
virtual gint progress_timeout ();
|
|
||||||
|
|
||||||
// initializes range_markers_durations_aggregated, range_markers_durations
|
|
||||||
// and total_duration
|
|
||||||
void init_progress_computing(ARDOUR::Locations::LocationList& locations);
|
|
||||||
|
|
||||||
// searches for a filename like "<filename><nr>.<postfix>" in path, that
|
|
||||||
// does not exist
|
|
||||||
string get_target_filepath(string path, string filename, string postfix);
|
|
||||||
|
|
||||||
void process_range_markers_export(ARDOUR::Locations::LocationList&);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif // __export_range_markers_dialog_h__
|
|
||||||
|
|
@ -105,6 +105,9 @@ ExportTimespanSelector::ExportTimespanSelector (ARDOUR::Session * session, Profi
|
||||||
/* Range view */
|
/* Range view */
|
||||||
|
|
||||||
range_list = Gtk::ListStore::create (range_cols);
|
range_list = Gtk::ListStore::create (range_cols);
|
||||||
|
// order by location start times
|
||||||
|
range_list->set_sort_column(range_cols.location, Gtk::SORT_ASCENDING);
|
||||||
|
range_list->set_sort_func(range_cols.location, sigc::mem_fun(*this, &ExportTimespanSelector::location_sorter));
|
||||||
range_view.set_model (range_list);
|
range_view.set_model (range_list);
|
||||||
range_view.set_headers_visible (true);
|
range_view.set_headers_visible (true);
|
||||||
}
|
}
|
||||||
|
|
@ -114,6 +117,22 @@ ExportTimespanSelector::~ExportTimespanSelector ()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ExportTimespanSelector::location_sorter(Gtk::TreeModel::iterator a, Gtk::TreeModel::iterator b)
|
||||||
|
{
|
||||||
|
Location *l1 = (*a)[range_cols.location];
|
||||||
|
Location *l2 = (*b)[range_cols.location];
|
||||||
|
const Location *ls = _session->locations()->session_range_location();
|
||||||
|
|
||||||
|
// always sort session range first
|
||||||
|
if (l1 == ls)
|
||||||
|
return -1;
|
||||||
|
if (l2 == ls)
|
||||||
|
return +1;
|
||||||
|
|
||||||
|
return l1->start() - l2->start();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ExportTimespanSelector::add_range_to_selection (ARDOUR::Location const * loc)
|
ExportTimespanSelector::add_range_to_selection (ARDOUR::Location const * loc)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ class ExportTimespanSelector : public Gtk::VBox, public ARDOUR::SessionHandlePtr
|
||||||
void update_range_name (std::string const & path, std::string const & new_text);
|
void update_range_name (std::string const & path, std::string const & new_text);
|
||||||
|
|
||||||
void set_selection_state_of_all_timespans (bool);
|
void set_selection_state_of_all_timespans (bool);
|
||||||
|
int location_sorter(Gtk::TreeModel::iterator a, Gtk::TreeModel::iterator b);
|
||||||
|
|
||||||
/*** GUI components ***/
|
/*** GUI components ***/
|
||||||
|
|
||||||
|
|
@ -132,7 +133,7 @@ class ExportTimespanSelector : public Gtk::VBox, public ARDOUR::SessionHandlePtr
|
||||||
Gtk::ScrolledWindow range_scroller;
|
Gtk::ScrolledWindow range_scroller;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Allows seleting multiple timespans
|
/// Allows selecting multiple timespans
|
||||||
class ExportTimespanSelectorMultiple : public ExportTimespanSelector
|
class ExportTimespanSelectorMultiple : public ExportTimespanSelector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
BIN
gtk2_ardour/icons/soundcloud.png
Normal file
BIN
gtk2_ardour/icons/soundcloud.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
110
gtk2_ardour/soundcloud_export_selector.cc
Normal file
110
gtk2_ardour/soundcloud_export_selector.cc
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
/* soundcloud_export_selector.cpp ***************************************************
|
||||||
|
|
||||||
|
Adapted for Ardour by Ben Loftis, March 2012
|
||||||
|
|
||||||
|
Licence GPL:
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
|
||||||
|
*************************************************************************************/
|
||||||
|
#include "ardour/soundcloud_upload.h"
|
||||||
|
#include "soundcloud_export_selector.h"
|
||||||
|
|
||||||
|
#include <pbd/error.h>
|
||||||
|
#include "pbd/openuri.h"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
|
||||||
|
#include "i18n.h"
|
||||||
|
|
||||||
|
using namespace PBD;
|
||||||
|
|
||||||
|
#include "ardour/session_metadata.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
SoundcloudExportSelector::SoundcloudExportSelector() :
|
||||||
|
sc_table (4, 3),
|
||||||
|
soundcloud_public_checkbox (_("Make file(s) public")),
|
||||||
|
soundcloud_username_label (_("User Email"), 1.0, 0.5),
|
||||||
|
soundcloud_password_label (_("Password"), 1.0, 0.5),
|
||||||
|
soundcloud_open_checkbox (_("Open uploaded files in browser")),
|
||||||
|
progress_bar()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
soundcloud_public_checkbox.set_name ("ExportCheckbox");
|
||||||
|
soundcloud_username_label.set_name ("ExportFormatLabel");
|
||||||
|
soundcloud_username_entry.set_name ("ExportFormatDisplay");
|
||||||
|
soundcloud_password_label.set_name ("ExportFormatLabel");
|
||||||
|
soundcloud_password_entry.set_name ("ExportFormatDisplay");
|
||||||
|
|
||||||
|
soundcloud_username_entry.set_text (ARDOUR::SessionMetadata::Metadata()->user_email());
|
||||||
|
soundcloud_password_entry.set_visibility(false);
|
||||||
|
|
||||||
|
Gtk::Frame *sc_frame = manage(new Gtk::Frame);
|
||||||
|
sc_frame->set_border_width(4);
|
||||||
|
sc_frame->set_shadow_type(Gtk::SHADOW_ETCHED_OUT);
|
||||||
|
sc_frame->set_name("soundcloud_export_box");
|
||||||
|
pack_start(*sc_frame, false, false);
|
||||||
|
|
||||||
|
sc_table.set_border_width(4);
|
||||||
|
sc_table.set_col_spacings (5);
|
||||||
|
sc_table.set_row_spacings (5);
|
||||||
|
sc_frame->add (sc_table);
|
||||||
|
|
||||||
|
// sc_table.attach ( *( manage (new EventBox (::get_icon (X_("soundcloud"))))) , 0, 1, 0, 1);
|
||||||
|
sc_table.attach ( *(Gtk::manage (new Gtk::Image (get_icon (X_("soundcloud"))))) , 0, 1, 0, 2);
|
||||||
|
|
||||||
|
sc_table.attach (soundcloud_public_checkbox, 2, 3, 1, 2);
|
||||||
|
sc_table.attach (soundcloud_username_label, 0, 1, 3, 4);
|
||||||
|
sc_table.attach (soundcloud_username_entry, 1, 3, 3, 4);
|
||||||
|
sc_table.attach (soundcloud_password_label, 0, 1, 5, 6);
|
||||||
|
sc_table.attach (soundcloud_password_entry, 1, 3, 5, 6);
|
||||||
|
sc_table.attach (soundcloud_open_checkbox, 2, 3, 7, 8);
|
||||||
|
|
||||||
|
pack_end(progress_bar, false, false);
|
||||||
|
sc_frame->show_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
SoundcloudExportSelector::do_progress_callback(double ultotal, double ulnow, const std::string &filename)
|
||||||
|
{
|
||||||
|
std::cerr << "SoundcloudExportSelector::do_progress_callback(" << ultotal << ", " << ulnow << ", " << filename << ")..." << std::endl;
|
||||||
|
if (soundcloud_cancel) {
|
||||||
|
progress_bar.set_fraction (0);
|
||||||
|
// cancel_button.set_label ("");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
double fraction = 0.0;
|
||||||
|
if (ultotal != 0) {
|
||||||
|
fraction = ulnow / ultotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress_bar.set_fraction ( fraction );
|
||||||
|
|
||||||
|
std::string prog;
|
||||||
|
prog = string_compose (_("%1: %2 of %3 bytes uploaded"), filename, ulnow, ultotal);
|
||||||
|
progress_bar.set_text( prog );
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
41
gtk2_ardour/soundcloud_export_selector.h
Normal file
41
gtk2_ardour/soundcloud_export_selector.h
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*soundcloud_export_selector.h***********************************************
|
||||||
|
|
||||||
|
Adapted for Ardour by Ben Loftis, March 2012
|
||||||
|
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <gtkmm.h>
|
||||||
|
#include <gtkmm/progressbar.h>
|
||||||
|
|
||||||
|
class SoundcloudExportSelector : public Gtk::VBox, public ARDOUR::SessionHandlePtr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SoundcloudExportSelector ();
|
||||||
|
int do_progress_callback (double ultotal, double ulnow, const std::string &filename);
|
||||||
|
std::string username () { return soundcloud_username_entry.get_text (); }
|
||||||
|
std::string password () { return soundcloud_password_entry.get_text (); }
|
||||||
|
bool upload_public () { return soundcloud_public_checkbox.get_active (); }
|
||||||
|
bool upload_open () { return soundcloud_open_checkbox.get_active (); }
|
||||||
|
void cancel () { soundcloud_cancel = true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Gtk::Table sc_table;
|
||||||
|
Gtk::CheckButton soundcloud_public_checkbox;
|
||||||
|
Gtk::Label soundcloud_username_label;
|
||||||
|
Gtk::Entry soundcloud_username_entry;
|
||||||
|
Gtk::Label soundcloud_password_label;
|
||||||
|
Gtk::Entry soundcloud_password_entry;
|
||||||
|
Gtk::CheckButton soundcloud_open_checkbox;
|
||||||
|
bool soundcloud_cancel;
|
||||||
|
Gtk::ProgressBar progress_bar;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -204,6 +204,7 @@ gtk2_ardour_sources = [
|
||||||
'session_option_editor.cc',
|
'session_option_editor.cc',
|
||||||
'sfdb_ui.cc',
|
'sfdb_ui.cc',
|
||||||
'shuttle_control.cc',
|
'shuttle_control.cc',
|
||||||
|
'soundcloud_export_selector.cc',
|
||||||
'splash.cc',
|
'splash.cc',
|
||||||
'speaker_dialog.cc',
|
'speaker_dialog.cc',
|
||||||
'startup.cc',
|
'startup.cc',
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,8 @@ class LIBARDOUR_API ExportFormatManager : public PBD::ScopedConnectionList
|
||||||
|
|
||||||
void select_with_cue (bool);
|
void select_with_cue (bool);
|
||||||
void select_with_toc (bool);
|
void select_with_toc (bool);
|
||||||
|
void select_upload (bool);
|
||||||
|
void set_command (std::string);
|
||||||
void select_src_quality (ExportFormatBase::SRCQuality value);
|
void select_src_quality (ExportFormatBase::SRCQuality value);
|
||||||
void select_trim_beginning (bool value);
|
void select_trim_beginning (bool value);
|
||||||
void select_silence_beginning (AnyTime const & time);
|
void select_silence_beginning (AnyTime const & time);
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,8 @@ class LIBARDOUR_API ExportFormatSpecification : public ExportFormatBase {
|
||||||
void set_tag (bool tag_it) { _tag = tag_it; }
|
void set_tag (bool tag_it) { _tag = tag_it; }
|
||||||
void set_with_cue (bool yn) { _with_cue = yn; }
|
void set_with_cue (bool yn) { _with_cue = yn; }
|
||||||
void set_with_toc (bool yn) { _with_toc = yn; }
|
void set_with_toc (bool yn) { _with_toc = yn; }
|
||||||
|
void set_upload (bool yn) { _upload = yn; }
|
||||||
|
void set_command (std::string command) { _command = command; }
|
||||||
|
|
||||||
void set_silence_beginning (AnyTime const & value) { _silence_beginning = value; }
|
void set_silence_beginning (AnyTime const & value) { _silence_beginning = value; }
|
||||||
void set_silence_end (AnyTime const & value) { _silence_end = value; }
|
void set_silence_end (AnyTime const & value) { _silence_end = value; }
|
||||||
|
|
@ -125,6 +127,8 @@ class LIBARDOUR_API ExportFormatSpecification : public ExportFormatBase {
|
||||||
float normalize_target () const { return _normalize_target; }
|
float normalize_target () const { return _normalize_target; }
|
||||||
bool with_toc() const { return _with_toc; }
|
bool with_toc() const { return _with_toc; }
|
||||||
bool with_cue() const { return _with_cue; }
|
bool with_cue() const { return _with_cue; }
|
||||||
|
bool upload() const { return _upload; }
|
||||||
|
std::string command() const { return _command; }
|
||||||
|
|
||||||
bool tag () const { return _tag && supports_tagging; }
|
bool tag () const { return _tag && supports_tagging; }
|
||||||
|
|
||||||
|
|
@ -174,6 +178,8 @@ class LIBARDOUR_API ExportFormatSpecification : public ExportFormatBase {
|
||||||
float _normalize_target;
|
float _normalize_target;
|
||||||
bool _with_toc;
|
bool _with_toc;
|
||||||
bool _with_cue;
|
bool _with_cue;
|
||||||
|
bool _upload;
|
||||||
|
std::string _command;
|
||||||
|
|
||||||
/* serialization helpers */
|
/* serialization helpers */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include "ardour/session.h"
|
#include "ardour/session.h"
|
||||||
#include "ardour/libardour_visibility.h"
|
#include "ardour/libardour_visibility.h"
|
||||||
#include "ardour/types.h"
|
#include "ardour/types.h"
|
||||||
|
#include "pbd/signals.h"
|
||||||
|
|
||||||
namespace AudioGrapher {
|
namespace AudioGrapher {
|
||||||
class BroadcastInfo;
|
class BroadcastInfo;
|
||||||
|
|
@ -68,7 +69,7 @@ class LIBARDOUR_API ExportElementFactory
|
||||||
Session & session;
|
Session & session;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LIBARDOUR_API ExportHandler : public ExportElementFactory
|
class LIBARDOUR_API ExportHandler : public ExportElementFactory, public sigc::trackable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct FileSpec {
|
struct FileSpec {
|
||||||
|
|
@ -95,6 +96,8 @@ class LIBARDOUR_API ExportHandler : public ExportElementFactory
|
||||||
friend boost::shared_ptr<ExportHandler> Session::get_export_handler();
|
friend boost::shared_ptr<ExportHandler> Session::get_export_handler();
|
||||||
ExportHandler (Session & session);
|
ExportHandler (Session & session);
|
||||||
|
|
||||||
|
void command_output(std::string output, size_t size);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~ExportHandler ();
|
~ExportHandler ();
|
||||||
|
|
||||||
|
|
@ -105,6 +108,17 @@ class LIBARDOUR_API ExportHandler : public ExportElementFactory
|
||||||
|
|
||||||
std::string get_cd_marker_filename(std::string filename, CDMarkerFormat format);
|
std::string get_cd_marker_filename(std::string filename, CDMarkerFormat format);
|
||||||
|
|
||||||
|
/** signal emitted when soundcloud export reports progress updates during upload.
|
||||||
|
* The parameters are total and current bytes downloaded, and the current filename
|
||||||
|
*/
|
||||||
|
PBD::Signal3<void, double, double, std::string> SoundcloudProgress;
|
||||||
|
|
||||||
|
/* upload credentials & preferences */
|
||||||
|
std::string upload_username;
|
||||||
|
std::string upload_password;
|
||||||
|
bool upload_public;
|
||||||
|
bool upload_open;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void handle_duplicate_format_extensions();
|
void handle_duplicate_format_extensions();
|
||||||
|
|
|
||||||
55
libs/ardour/ardour/soundcloud_upload.h
Normal file
55
libs/ardour/ardour/soundcloud_upload.h
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
/* soundcloud_upload.h ******************************************************
|
||||||
|
|
||||||
|
Adapted for Ardour by Ben Loftis, March 2012
|
||||||
|
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __ardour_soundcloud_upload_h__
|
||||||
|
#define __ardour_soundcloud_upload_h__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "curl/curl.h"
|
||||||
|
#include "ardour/session_handle.h"
|
||||||
|
#include "ardour/export_handler.h"
|
||||||
|
#include "pbd/signals.h"
|
||||||
|
|
||||||
|
//--- struct to store XML file
|
||||||
|
struct MemoryStruct {
|
||||||
|
char *memory;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SoundcloudUploader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SoundcloudUploader();
|
||||||
|
~SoundcloudUploader();
|
||||||
|
|
||||||
|
std::string Get_Auth_Token(std::string username, std::string password);
|
||||||
|
std::string Upload (std::string file_path, std::string title, std::string token, bool ispublic, ARDOUR::ExportHandler *caller);
|
||||||
|
static int progress_callback(void *caller, double dltotal, double dlnow, double ultotal, double ulnow);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void setcUrlOptions();
|
||||||
|
|
||||||
|
CURL *curl_handle;
|
||||||
|
CURLM *multi_handle;
|
||||||
|
char errorBuffer[CURL_ERROR_SIZE]; // storage for cUrl error message
|
||||||
|
|
||||||
|
std::string title;
|
||||||
|
ARDOUR::ExportHandler *caller;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __ardour_soundcloud_upload_h__ */
|
||||||
|
|
@ -32,6 +32,7 @@ class LIBARDOUR_API SystemExec
|
||||||
public:
|
public:
|
||||||
SystemExec (std::string c, std::string a = "");
|
SystemExec (std::string c, std::string a = "");
|
||||||
SystemExec (std::string c, char ** a);
|
SystemExec (std::string c, char ** a);
|
||||||
|
SystemExec (std::string c, const std::map<char, std::string> subs);
|
||||||
~SystemExec ();
|
~SystemExec ();
|
||||||
|
|
||||||
int start (int stderr_mode = 1) {
|
int start (int stderr_mode = 1) {
|
||||||
|
|
|
||||||
|
|
@ -293,6 +293,20 @@ ExportFormatManager::select_with_toc (bool value)
|
||||||
check_for_description_change ();
|
check_for_description_change ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExportFormatManager::select_upload (bool value)
|
||||||
|
{
|
||||||
|
current_selection->set_upload (value);
|
||||||
|
check_for_description_change ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExportFormatManager::set_command (std::string command)
|
||||||
|
{
|
||||||
|
current_selection->set_command (command);
|
||||||
|
check_for_description_change ();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ExportFormatManager::select_trim_beginning (bool value)
|
ExportFormatManager::select_trim_beginning (bool value)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,8 @@ ExportFormatSpecification::ExportFormatSpecification (Session & s)
|
||||||
, _normalize_target (1.0)
|
, _normalize_target (1.0)
|
||||||
, _with_toc (false)
|
, _with_toc (false)
|
||||||
, _with_cue (false)
|
, _with_cue (false)
|
||||||
|
, _upload (false)
|
||||||
|
, _command ("")
|
||||||
{
|
{
|
||||||
format_ids.insert (F_None);
|
format_ids.insert (F_None);
|
||||||
endiannesses.insert (E_FileDefault);
|
endiannesses.insert (E_FileDefault);
|
||||||
|
|
@ -244,6 +246,8 @@ ExportFormatSpecification::get_state ()
|
||||||
root->add_property ("id", _id.to_s());
|
root->add_property ("id", _id.to_s());
|
||||||
root->add_property ("with-cue", _with_cue ? "true" : "false");
|
root->add_property ("with-cue", _with_cue ? "true" : "false");
|
||||||
root->add_property ("with-toc", _with_toc ? "true" : "false");
|
root->add_property ("with-toc", _with_toc ? "true" : "false");
|
||||||
|
root->add_property ("upload", _upload ? "true" : "false");
|
||||||
|
root->add_property ("command", _command);
|
||||||
|
|
||||||
node = root->add_child ("Encoding");
|
node = root->add_child ("Encoding");
|
||||||
node->add_property ("id", enum_2_string (format_id()));
|
node->add_property ("id", enum_2_string (format_id()));
|
||||||
|
|
@ -321,6 +325,18 @@ ExportFormatSpecification::set_state (const XMLNode & root)
|
||||||
_with_toc = false;
|
_with_toc = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((prop = root.property ("upload"))) {
|
||||||
|
_upload = string_is_affirmative (prop->value());
|
||||||
|
} else {
|
||||||
|
_upload = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((prop = root.property ("command"))) {
|
||||||
|
_command = prop->value();
|
||||||
|
} else {
|
||||||
|
_command = "";
|
||||||
|
}
|
||||||
|
|
||||||
/* Encoding and SRC */
|
/* Encoding and SRC */
|
||||||
|
|
||||||
if ((child = root.child ("Encoding"))) {
|
if ((child = root.child ("Encoding"))) {
|
||||||
|
|
@ -590,6 +606,14 @@ ExportFormatSpecification::description (bool include_name)
|
||||||
components.push_back ("CUE");
|
components.push_back ("CUE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_upload) {
|
||||||
|
components.push_back ("Upload");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_command.empty()) {
|
||||||
|
components.push_back ("+");
|
||||||
|
}
|
||||||
|
|
||||||
string desc;
|
string desc;
|
||||||
if (include_name) {
|
if (include_name) {
|
||||||
desc = _name + ": ";
|
desc = _name + ": ";
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,10 @@
|
||||||
#include "ardour/export_status.h"
|
#include "ardour/export_status.h"
|
||||||
#include "ardour/export_format_specification.h"
|
#include "ardour/export_format_specification.h"
|
||||||
#include "ardour/export_filename.h"
|
#include "ardour/export_filename.h"
|
||||||
|
#include "ardour/soundcloud_upload.h"
|
||||||
|
#include "ardour/system_exec.h"
|
||||||
|
#include "pbd/openuri.h"
|
||||||
|
#include "pbd/basename.h"
|
||||||
#include "ardour/session_metadata.h"
|
#include "ardour/session_metadata.h"
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
@ -277,6 +281,13 @@ ExportHandler::process_normalize ()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExportHandler::command_output(std::string output, size_t size)
|
||||||
|
{
|
||||||
|
std::cerr << "command: " << size << ", " << output << std::endl;
|
||||||
|
info << output << endmsg;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ExportHandler::finish_timespan ()
|
ExportHandler::finish_timespan ()
|
||||||
{
|
{
|
||||||
|
|
@ -297,13 +308,77 @@ ExportHandler::finish_timespan ()
|
||||||
AudiofileTagger::tag_file(filename, *SessionMetadata::Metadata());
|
AudiofileTagger::tag_file(filename, *SessionMetadata::Metadata());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!fmt->command().empty()) {
|
||||||
|
|
||||||
|
#if 0 // would be nicer with C++11 initialiser...
|
||||||
|
std::map<char, std::string> subs {
|
||||||
|
{ 'f', filename },
|
||||||
|
{ 'd', Glib::path_get_dirname(filename) },
|
||||||
|
{ 'b', PBD::basename_nosuffix(filename) },
|
||||||
|
{ 'u', upload_username },
|
||||||
|
{ 'p', upload_password}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PBD::ScopedConnection command_connection;
|
||||||
|
std::map<char, std::string> subs;
|
||||||
|
subs.insert (std::pair<char, std::string> ('f', filename));
|
||||||
|
subs.insert (std::pair<char, std::string> ('d', Glib::path_get_dirname(filename)));
|
||||||
|
subs.insert (std::pair<char, std::string> ('b', PBD::basename_nosuffix(filename)));
|
||||||
|
subs.insert (std::pair<char, std::string> ('u', upload_username));
|
||||||
|
subs.insert (std::pair<char, std::string> ('p', upload_password));
|
||||||
|
|
||||||
|
|
||||||
|
std::cerr << "running command: " << fmt->command() << "..." << std::endl;
|
||||||
|
ARDOUR::SystemExec *se = new ARDOUR::SystemExec(fmt->command(), subs);
|
||||||
|
se->ReadStdout.connect_same_thread(command_connection, boost::bind(&ExportHandler::command_output, this, _1, _2));
|
||||||
|
if (se->start (2) == 0) {
|
||||||
|
// successfully started
|
||||||
|
std::cerr << "started!" << std::endl;
|
||||||
|
while (se->is_running ()) {
|
||||||
|
// wait for system exec to terminate
|
||||||
|
// std::cerr << "waiting..." << std::endl;
|
||||||
|
usleep (1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cerr << "done! deleting..." << std::endl;
|
||||||
|
delete (se);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fmt->upload()) {
|
||||||
|
SoundcloudUploader *soundcloud_uploader = new SoundcloudUploader;
|
||||||
|
std::string token = soundcloud_uploader->Get_Auth_Token(upload_username, upload_password);
|
||||||
|
std::cerr
|
||||||
|
<< "uploading "
|
||||||
|
<< filename << std::endl
|
||||||
|
<< "username = " << upload_username
|
||||||
|
<< ", password = " << upload_password
|
||||||
|
<< " - token = " << token << " ..."
|
||||||
|
<< std::endl;
|
||||||
|
std::string path = soundcloud_uploader->Upload (
|
||||||
|
filename,
|
||||||
|
PBD::basename_nosuffix(filename), // title
|
||||||
|
token,
|
||||||
|
upload_public,
|
||||||
|
this);
|
||||||
|
|
||||||
|
if (path.length() != 0) {
|
||||||
|
if (upload_open) {
|
||||||
|
std::cerr << "opening " << path << " ..." << std::endl;
|
||||||
|
open_uri(path.c_str()); // open the soundcloud website to the new file
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error << _("upload to Soundcloud failed. Perhaps your email or password are incorrect?\n") << endmsg;
|
||||||
|
}
|
||||||
|
delete soundcloud_uploader;
|
||||||
|
}
|
||||||
config_map.erase (config_map.begin());
|
config_map.erase (config_map.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
start_timespan ();
|
start_timespan ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** CD Marker sutff ***/
|
/*** CD Marker stuff ***/
|
||||||
|
|
||||||
struct LocationSortByStart {
|
struct LocationSortByStart {
|
||||||
bool operator() (Location *a, Location *b) {
|
bool operator() (Location *a, Location *b) {
|
||||||
|
|
|
||||||
349
libs/ardour/soundcloud_upload.cc
Normal file
349
libs/ardour/soundcloud_upload.cc
Normal file
|
|
@ -0,0 +1,349 @@
|
||||||
|
/* soundcloud_export.cpp **********************************************************************
|
||||||
|
|
||||||
|
Adapted for Ardour by Ben Loftis, March 2012
|
||||||
|
|
||||||
|
Licence GPL:
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
|
||||||
|
*************************************************************************************/
|
||||||
|
#include "ardour/soundcloud_upload.h"
|
||||||
|
|
||||||
|
#include "pbd/xml++.h"
|
||||||
|
#include <pbd/error.h>
|
||||||
|
//#include "pbd/filesystem.h"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
|
||||||
|
#include "i18n.h"
|
||||||
|
|
||||||
|
using namespace PBD;
|
||||||
|
|
||||||
|
// static const std::string base_url = "http://api.soundcloud.com/tracks/13158665?client_id=";
|
||||||
|
|
||||||
|
size_t
|
||||||
|
WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
|
||||||
|
{
|
||||||
|
register int realsize = (int)(size * nmemb);
|
||||||
|
struct MemoryStruct *mem = (struct MemoryStruct *)data;
|
||||||
|
|
||||||
|
mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
|
||||||
|
|
||||||
|
if (mem->memory) {
|
||||||
|
memcpy(&(mem->memory[mem->size]), ptr, realsize);
|
||||||
|
mem->size += realsize;
|
||||||
|
mem->memory[mem->size] = 0;
|
||||||
|
}
|
||||||
|
return realsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundcloudUploader::SoundcloudUploader()
|
||||||
|
{
|
||||||
|
curl_handle = curl_easy_init();
|
||||||
|
multi_handle = curl_multi_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
SoundcloudUploader::Get_Auth_Token( std::string username, std::string password )
|
||||||
|
{
|
||||||
|
struct MemoryStruct xml_page;
|
||||||
|
xml_page.memory = NULL;
|
||||||
|
xml_page.size = 0;
|
||||||
|
|
||||||
|
setcUrlOptions();
|
||||||
|
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &xml_page);
|
||||||
|
|
||||||
|
struct curl_httppost *formpost=NULL;
|
||||||
|
struct curl_httppost *lastptr=NULL;
|
||||||
|
|
||||||
|
/* Fill in the filename field */
|
||||||
|
curl_formadd(&formpost,
|
||||||
|
&lastptr,
|
||||||
|
CURLFORM_COPYNAME, "client_id",
|
||||||
|
CURLFORM_COPYCONTENTS, "e7ac891eef866f139773cf8102b7a719",
|
||||||
|
CURLFORM_END);
|
||||||
|
|
||||||
|
curl_formadd(&formpost,
|
||||||
|
&lastptr,
|
||||||
|
CURLFORM_COPYNAME, "client_secret",
|
||||||
|
CURLFORM_COPYCONTENTS, "d78f34d19f09d26731801a0cb0f382c4",
|
||||||
|
CURLFORM_END);
|
||||||
|
|
||||||
|
curl_formadd(&formpost,
|
||||||
|
&lastptr,
|
||||||
|
CURLFORM_COPYNAME, "grant_type",
|
||||||
|
CURLFORM_COPYCONTENTS, "password",
|
||||||
|
CURLFORM_END);
|
||||||
|
|
||||||
|
curl_formadd(&formpost,
|
||||||
|
&lastptr,
|
||||||
|
CURLFORM_COPYNAME, "username",
|
||||||
|
CURLFORM_COPYCONTENTS, username.c_str(),
|
||||||
|
CURLFORM_END);
|
||||||
|
|
||||||
|
curl_formadd(&formpost,
|
||||||
|
&lastptr,
|
||||||
|
CURLFORM_COPYNAME, "password",
|
||||||
|
CURLFORM_COPYCONTENTS, password.c_str(),
|
||||||
|
CURLFORM_END);
|
||||||
|
|
||||||
|
struct curl_slist *headerlist=NULL;
|
||||||
|
headerlist = curl_slist_append(headerlist, "Expect:");
|
||||||
|
headerlist = curl_slist_append(headerlist, "Accept: application/xml");
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headerlist);
|
||||||
|
|
||||||
|
/* what URL that receives this POST */
|
||||||
|
std::string url = "https://api.soundcloud.com/oauth2/token";
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_HTTPPOST, formpost);
|
||||||
|
|
||||||
|
// curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
|
||||||
|
|
||||||
|
// perform online request
|
||||||
|
CURLcode res = curl_easy_perform(curl_handle);
|
||||||
|
if( res != 0 ) {
|
||||||
|
std::cerr << "curl error " << res << " (" << curl_easy_strerror(res) << ")" << std::endl;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(xml_page.memory){
|
||||||
|
//cheesy way to parse the json return value. find access_token, then advance 3 quotes
|
||||||
|
|
||||||
|
if ( strstr ( xml_page.memory , "access_token" ) == NULL) {
|
||||||
|
error << _("Upload to Soundcloud failed. Perhaps your email or password are incorrect?\n") << endmsg;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string token = strtok( xml_page.memory, "access_token" );
|
||||||
|
token = strtok( NULL, "\"" );
|
||||||
|
token = strtok( NULL, "\"" );
|
||||||
|
token = strtok( NULL, "\"" );
|
||||||
|
|
||||||
|
free( xml_page.memory );
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
SoundcloudUploader::progress_callback(void *caller, double dltotal, double dlnow, double ultotal, double ulnow)
|
||||||
|
{
|
||||||
|
SoundcloudUploader *scu = (SoundcloudUploader *) caller;
|
||||||
|
std::cerr << scu->title << ": uploaded " << ulnow << " of " << ultotal << std::endl;
|
||||||
|
scu->caller->SoundcloudProgress(ultotal, ulnow, scu->title); /* EMIT SIGNAL */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string
|
||||||
|
SoundcloudUploader::Upload(std::string file_path, std::string title, std::string token, bool ispublic, ARDOUR::ExportHandler *caller)
|
||||||
|
{
|
||||||
|
int still_running;
|
||||||
|
|
||||||
|
struct MemoryStruct xml_page;
|
||||||
|
xml_page.memory = NULL;
|
||||||
|
xml_page.size = 0;
|
||||||
|
|
||||||
|
setcUrlOptions();
|
||||||
|
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &xml_page);
|
||||||
|
|
||||||
|
struct curl_httppost *formpost=NULL;
|
||||||
|
struct curl_httppost *lastptr=NULL;
|
||||||
|
|
||||||
|
/* Fill in the file upload field. This makes libcurl load data from
|
||||||
|
the given file name when curl_easy_perform() is called. */
|
||||||
|
curl_formadd(&formpost,
|
||||||
|
&lastptr,
|
||||||
|
CURLFORM_COPYNAME, "track[asset_data]",
|
||||||
|
CURLFORM_FILE, file_path.c_str(),
|
||||||
|
CURLFORM_END);
|
||||||
|
|
||||||
|
/* Fill in the filename field */
|
||||||
|
curl_formadd(&formpost,
|
||||||
|
&lastptr,
|
||||||
|
CURLFORM_COPYNAME, "oauth_token",
|
||||||
|
CURLFORM_COPYCONTENTS, token.c_str(),
|
||||||
|
CURLFORM_END);
|
||||||
|
|
||||||
|
curl_formadd(&formpost,
|
||||||
|
&lastptr,
|
||||||
|
CURLFORM_COPYNAME, "track[title]",
|
||||||
|
CURLFORM_COPYCONTENTS, title.c_str(),
|
||||||
|
CURLFORM_END);
|
||||||
|
|
||||||
|
curl_formadd(&formpost,
|
||||||
|
&lastptr,
|
||||||
|
CURLFORM_COPYNAME, "track[sharing]",
|
||||||
|
CURLFORM_COPYCONTENTS, ispublic ? "public" : "private",
|
||||||
|
CURLFORM_END);
|
||||||
|
|
||||||
|
/* initalize custom header list (stating that Expect: 100-continue is not
|
||||||
|
wanted */
|
||||||
|
struct curl_slist *headerlist=NULL;
|
||||||
|
static const char buf[] = "Expect:";
|
||||||
|
headerlist = curl_slist_append(headerlist, buf);
|
||||||
|
|
||||||
|
|
||||||
|
if (curl_handle && multi_handle) {
|
||||||
|
|
||||||
|
/* what URL that receives this POST */
|
||||||
|
std::string url = "https://api.soundcloud.com/tracks";
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());
|
||||||
|
// curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
|
||||||
|
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headerlist);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_HTTPPOST, formpost);
|
||||||
|
|
||||||
|
this->title = title; // save title to show in progress bar
|
||||||
|
this->caller = caller;
|
||||||
|
|
||||||
|
curl_easy_setopt (curl_handle, CURLOPT_NOPROGRESS, 0); // turn on the progress bar
|
||||||
|
curl_easy_setopt (curl_handle, CURLOPT_PROGRESSFUNCTION, &SoundcloudUploader::progress_callback);
|
||||||
|
curl_easy_setopt (curl_handle, CURLOPT_PROGRESSDATA, this);
|
||||||
|
|
||||||
|
curl_multi_add_handle(multi_handle, curl_handle);
|
||||||
|
|
||||||
|
curl_multi_perform(multi_handle, &still_running);
|
||||||
|
|
||||||
|
|
||||||
|
while(still_running) {
|
||||||
|
struct timeval timeout;
|
||||||
|
int rc; /* select() return code */
|
||||||
|
|
||||||
|
fd_set fdread;
|
||||||
|
fd_set fdwrite;
|
||||||
|
fd_set fdexcep;
|
||||||
|
int maxfd = -1;
|
||||||
|
|
||||||
|
long curl_timeo = -1;
|
||||||
|
|
||||||
|
FD_ZERO(&fdread);
|
||||||
|
FD_ZERO(&fdwrite);
|
||||||
|
FD_ZERO(&fdexcep);
|
||||||
|
|
||||||
|
/* set a suitable timeout to play around with */
|
||||||
|
timeout.tv_sec = 1;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
|
curl_multi_timeout(multi_handle, &curl_timeo);
|
||||||
|
if(curl_timeo >= 0) {
|
||||||
|
timeout.tv_sec = curl_timeo / 1000;
|
||||||
|
if(timeout.tv_sec > 1)
|
||||||
|
timeout.tv_sec = 1;
|
||||||
|
else
|
||||||
|
timeout.tv_usec = (curl_timeo % 1000) * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get file descriptors from the transfers */
|
||||||
|
curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
|
||||||
|
|
||||||
|
/* In a real-world program you OF COURSE check the return code of the
|
||||||
|
function calls. On success, the value of maxfd is guaranteed to be
|
||||||
|
greater or equal than -1. We call select(maxfd + 1, ...), specially in
|
||||||
|
case of (maxfd == -1), we call select(0, ...), which is basically equal
|
||||||
|
to sleep. */
|
||||||
|
|
||||||
|
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
|
||||||
|
|
||||||
|
switch(rc) {
|
||||||
|
case -1:
|
||||||
|
/* select error */
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
/* timeout or readable/writable sockets */
|
||||||
|
curl_multi_perform(multi_handle, &still_running);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* then cleanup the formpost chain */
|
||||||
|
curl_formfree(formpost);
|
||||||
|
|
||||||
|
/* free slist */
|
||||||
|
curl_slist_free_all (headerlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_easy_setopt (curl_handle, CURLOPT_NOPROGRESS, 1); // turn off the progress bar
|
||||||
|
|
||||||
|
if(xml_page.memory){
|
||||||
|
|
||||||
|
std::cout << xml_page.memory << std::endl;
|
||||||
|
|
||||||
|
XMLTree doc;
|
||||||
|
doc.read_buffer( xml_page.memory );
|
||||||
|
XMLNode *root = doc.root();
|
||||||
|
|
||||||
|
if (!root) {
|
||||||
|
std::cout << "no root XML node!" << std::endl;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLNode *url_node = root->child("permalink-url");
|
||||||
|
if (!url_node) {
|
||||||
|
std::cout << "no child node \"permalink-url\" found!" << std::endl;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLNode *text_node = url_node->child("text");
|
||||||
|
if (!text_node) {
|
||||||
|
std::cout << "no text node found!" << std::endl;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
free( xml_page.memory );
|
||||||
|
return text_node->content();
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
SoundcloudUploader:: ~SoundcloudUploader()
|
||||||
|
{
|
||||||
|
curl_easy_cleanup(curl_handle);
|
||||||
|
curl_multi_cleanup(multi_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SoundcloudUploader::setcUrlOptions()
|
||||||
|
{
|
||||||
|
// basic init for curl
|
||||||
|
curl_global_init(CURL_GLOBAL_ALL);
|
||||||
|
// some servers don't like requests that are made without a user-agent field, so we provide one
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
|
||||||
|
// setup curl error buffer
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, errorBuffer);
|
||||||
|
// Allow redirection
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
|
||||||
|
|
||||||
|
// Allow connections to time out (without using signals)
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 30);
|
||||||
|
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -65,4 +65,14 @@ SystemExec::SystemExec (std::string c, std::string a)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SystemExec::SystemExec (std::string c, const std::map<char, std::string> subs)
|
||||||
|
: PBD::SystemExec(c, subs)
|
||||||
|
{
|
||||||
|
#ifndef PLATFORM_WINDOWS
|
||||||
|
if (!_vfork_exec_wrapper) {
|
||||||
|
_vfork_exec_wrapper = vfork_exec_wrapper_path();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
SystemExec::~SystemExec() { }
|
SystemExec::~SystemExec() { }
|
||||||
|
|
|
||||||
|
|
@ -194,6 +194,7 @@ libardour_sources = [
|
||||||
'sndfile_helpers.cc',
|
'sndfile_helpers.cc',
|
||||||
'sndfileimportable.cc',
|
'sndfileimportable.cc',
|
||||||
'sndfilesource.cc',
|
'sndfilesource.cc',
|
||||||
|
'soundcloud_upload.cc',
|
||||||
'source.cc',
|
'source.cc',
|
||||||
'source_factory.cc',
|
'source_factory.cc',
|
||||||
'speakers.cc',
|
'speakers.cc',
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#ifdef NOPBD /* unit-test outside ardour */
|
#ifdef NOPBD /* unit-test outside ardour */
|
||||||
#include <sigc++/bind.h>
|
#include <sigc++/bind.h>
|
||||||
#include <sigc++/signal.h>
|
#include <sigc++/signal.h>
|
||||||
|
|
@ -94,6 +96,23 @@ class LIBPBD_API SystemExec
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
SystemExec (std::string c, char ** a);
|
SystemExec (std::string c, char ** a);
|
||||||
|
|
||||||
|
/** similar to \ref SystemExec but expects a whole command line, and
|
||||||
|
* handles some simple escape sequences.
|
||||||
|
*
|
||||||
|
* @param command complete command-line to be executed
|
||||||
|
* @param subs a map of <char, std::string> listing the % substitutions to
|
||||||
|
* be made.
|
||||||
|
*
|
||||||
|
* creates an argv array from the given command string, splitting into
|
||||||
|
* parameters at spaces.
|
||||||
|
* "\ " is non-splitting space, "\\" (and "\" at end of command) as "\",
|
||||||
|
* for "%<char>", <char> is looked up in subs and the corresponding string
|
||||||
|
* substituted. "%%" (and "%" at end of command)
|
||||||
|
* returns an argv array suitable for creating a new SystemExec with
|
||||||
|
*/
|
||||||
|
SystemExec (std::string command, const std::map<char, std::string> subs);
|
||||||
|
|
||||||
virtual ~SystemExec ();
|
virtual ~SystemExec ();
|
||||||
|
|
||||||
/** fork and execute the given program
|
/** fork and execute the given program
|
||||||
|
|
@ -182,6 +201,7 @@ class LIBPBD_API SystemExec
|
||||||
int nicelevel; ///< process nice level - defaults to 0
|
int nicelevel; ///< process nice level - defaults to 0
|
||||||
|
|
||||||
void make_argp(std::string);
|
void make_argp(std::string);
|
||||||
|
void make_argp_escaped(std::string command, const std::map<char, std::string> subs);
|
||||||
void make_envp();
|
void make_envp();
|
||||||
|
|
||||||
char **argp;
|
char **argp;
|
||||||
|
|
@ -198,6 +218,7 @@ class LIBPBD_API SystemExec
|
||||||
#else
|
#else
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
#endif
|
#endif
|
||||||
|
void init ();
|
||||||
pthread_mutex_t write_lock;
|
pthread_mutex_t write_lock;
|
||||||
|
|
||||||
int fdin; ///< file-descriptor for writing to child's STDIN. This variable is identical to pin[1] but also used as status check if the stdin pipe is open: <0 means closed.
|
int fdin; ///< file-descriptor for writing to child's STDIN. This variable is identical to pin[1] but also used as status check if the stdin pipe is open: <0 means closed.
|
||||||
|
|
|
||||||
|
|
@ -151,9 +151,8 @@ static int close_allv(const int except_fds[]) {
|
||||||
}
|
}
|
||||||
#endif /* not on windows, nor vfork */
|
#endif /* not on windows, nor vfork */
|
||||||
|
|
||||||
|
void
|
||||||
SystemExec::SystemExec (std::string c, std::string a)
|
SystemExec::init ()
|
||||||
: cmd(c)
|
|
||||||
{
|
{
|
||||||
pthread_mutex_init(&write_lock, NULL);
|
pthread_mutex_init(&write_lock, NULL);
|
||||||
thread_active=false;
|
thread_active=false;
|
||||||
|
|
@ -161,12 +160,19 @@ SystemExec::SystemExec (std::string c, std::string a)
|
||||||
pin[1] = -1;
|
pin[1] = -1;
|
||||||
nicelevel = 0;
|
nicelevel = 0;
|
||||||
envp = NULL;
|
envp = NULL;
|
||||||
argp = NULL;
|
|
||||||
#ifdef PLATFORM_WINDOWS
|
#ifdef PLATFORM_WINDOWS
|
||||||
stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE;
|
stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE;
|
||||||
stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE;
|
stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE;
|
||||||
stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE;
|
stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemExec::SystemExec (std::string c, std::string a)
|
||||||
|
: cmd(c)
|
||||||
|
{
|
||||||
|
init ();
|
||||||
|
|
||||||
|
argp = NULL;
|
||||||
make_envp();
|
make_envp();
|
||||||
make_argp(a);
|
make_argp(a);
|
||||||
}
|
}
|
||||||
|
|
@ -174,21 +180,101 @@ SystemExec::SystemExec (std::string c, std::string a)
|
||||||
SystemExec::SystemExec (std::string c, char **a)
|
SystemExec::SystemExec (std::string c, char **a)
|
||||||
: cmd(c) , argp(a)
|
: cmd(c) , argp(a)
|
||||||
{
|
{
|
||||||
pthread_mutex_init(&write_lock, NULL);
|
init ();
|
||||||
thread_active=false;
|
|
||||||
pid = 0;
|
|
||||||
pin[1] = -1;
|
|
||||||
nicelevel = 0;
|
|
||||||
envp = NULL;
|
|
||||||
#ifdef PLATFORM_WINDOWS
|
#ifdef PLATFORM_WINDOWS
|
||||||
stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE;
|
|
||||||
stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE;
|
|
||||||
stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE;
|
|
||||||
make_wargs(a);
|
make_wargs(a);
|
||||||
#endif
|
#endif
|
||||||
make_envp();
|
make_envp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SystemExec::SystemExec (std::string command, const std::map<char, std::string> subs)
|
||||||
|
{
|
||||||
|
init ();
|
||||||
|
make_argp_escaped(command, subs);
|
||||||
|
cmd = argp[0];
|
||||||
|
// cmd = strdup(argp[0]);
|
||||||
|
make_envp();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SystemExec::make_argp_escaped(std::string command, const std::map<char, std::string> subs)
|
||||||
|
{
|
||||||
|
|
||||||
|
int inquotes = 0;
|
||||||
|
int n = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
std::string arg = "";
|
||||||
|
|
||||||
|
argp = (char **) malloc(sizeof(char *));
|
||||||
|
|
||||||
|
for (i = 0; i <= command.length(); i++) { // include terminating '\0'
|
||||||
|
char c = command.c_str()[i];
|
||||||
|
if (inquotes) {
|
||||||
|
if (c == '"') {
|
||||||
|
inquotes = 0;
|
||||||
|
} else {
|
||||||
|
// still in quotes - just copy
|
||||||
|
arg += c;
|
||||||
|
}
|
||||||
|
} else switch (c) {
|
||||||
|
case '%' :
|
||||||
|
c = command.c_str()[++i];
|
||||||
|
if (c == '%' || c == '\0') {
|
||||||
|
// "%%", "%" at end-of-string => "%"
|
||||||
|
arg += '%';
|
||||||
|
} else {
|
||||||
|
// search subs for string to substitute for char
|
||||||
|
std::map<char, std::string>::const_iterator s = subs.find(c);
|
||||||
|
if (s != subs.end()) {
|
||||||
|
// found substitution
|
||||||
|
arg += s->second;
|
||||||
|
} else {
|
||||||
|
// not a valid substitution, just copy
|
||||||
|
arg += '%';
|
||||||
|
arg += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
c = command.c_str()[++i];
|
||||||
|
switch (c) {
|
||||||
|
case ' ' :
|
||||||
|
case '"' : arg += c; break; // "\\", "\" at end-of-string => "\"
|
||||||
|
case '\0':
|
||||||
|
case '\\': arg += '\\'; break;
|
||||||
|
default : arg += '\\'; arg += c; break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '"' :
|
||||||
|
inquotes = 1;
|
||||||
|
break;
|
||||||
|
case ' ' :
|
||||||
|
case '\t':
|
||||||
|
case '\0':
|
||||||
|
if (arg.length() > 0) {
|
||||||
|
// if there wasn't already a space or tab, start a new parameter
|
||||||
|
argp = (char **) realloc(argp, (n + 2) * sizeof(char *));
|
||||||
|
argp[n++] = strdup (arg.c_str());
|
||||||
|
arg = "";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
arg += c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argp[n] = NULL;
|
||||||
|
|
||||||
|
char *p = argp[0];
|
||||||
|
n = 0;
|
||||||
|
do {
|
||||||
|
std::cerr << "argv[" << n << "] == \"" << p << "\"" << std::endl;
|
||||||
|
p = argp[n++];
|
||||||
|
} while (p);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
SystemExec::~SystemExec ()
|
SystemExec::~SystemExec ()
|
||||||
{
|
{
|
||||||
terminate ();
|
terminate ();
|
||||||
|
|
@ -522,7 +608,7 @@ SystemExec::make_argp(std::string args) {
|
||||||
*cp2 = '\0';
|
*cp2 = '\0';
|
||||||
argp[argn++] = strdup(cp1);
|
argp[argn++] = strdup(cp1);
|
||||||
cp1 = cp2 + 1;
|
cp1 = cp2 + 1;
|
||||||
argp = (char **) realloc(argp, (argn + 1) * sizeof(char *));
|
argp = (char **) realloc(argp, (argn + 1) * sizeof(char *));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cp2 != cp1) {
|
if (cp2 != cp1) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue